初始化带已有掩码的NumPy掩码数组的最优方法
numpy.ma 带掩码全零数组高效初始化方案
问题背景
原本期望通过如下语句直接初始化带硬掩码的全零掩码数组,传入的掩码形状与目标数组形状完全匹配:
ma.zeros(my_shape, mask=my_mask, hard_mask=True)
实际ma.zeros、ma.ones、ma.empty这几个构造接口都不支持传入mask参数。目前能跑通的最简写法是:
ma.array(np.zeros(my_shape), mask=my_mask, hard_mask=True)
但这个写法默认会拷贝一遍生成的全零数组,数组尺寸大的时候会平白多出来不必要的内存和时间开销。
无额外拷贝的实现方法
两种写法都可以完全避免数值数组的额外拷贝,性能和原生支持mask参数的理想接口几乎没有差距:
写法1:分步设置属性
直接用ma.zeros生成底层已经是全零值的MaskedArray实例,之后再给mask属性赋值、打开硬掩码开关就行:arr = ma.zeros(my_shape) arr.mask = my_mask arr.hardmask = True这个流程里只有掩码本身会占新的内存,底层存零值的那块内存从始至终只会分配一次,没有任何拷贝动作,逻辑最顺,也不会有内存共享的坑,优先用这个就行。
写法2:单语句实现,关闭拷贝开关
原来的单语句写法只要加个copy=False参数,就能让ma.array直接复用你传进去的全零ndarray当底层存储,不会再做拷贝:arr = ma.array(np.zeros(my_shape), mask=my_mask, hard_mask=True, copy=False)要注意这个写法里,你最先生成的
np.zeros(my_shape)和最后得到的掩码数组是共用同一块数值内存的,要是之后你在外面改了原始ndarray的值,掩码数组里的内容也会跟着变,要是需要内存隔离就老老实实选第一种写法。
避坑提示
别为了省性能用ma.empty替换ma.zeros:ma.empty分配的内存里是没初始化的随机脏数据,你要得到全零数组还是得手动填零,总开销和ma.zeros一模一样,搞不好还会把脏数据漏到计算逻辑里。
内容的提问来源于stack exchange,提问作者Matthew Collett
相关产品推荐
相关产品推荐

