MaskedArray
是基础numpy ndarray
的子类。它本身没有编译的代码。请查看numpy/ma/
目录或主文件以获取详细信息:
/usr/local/lib/python3.6/dist-packages/numpy/ma/core.py
一个掩码数组有两个关键属性,data 和 mask。其中一个是你用来创建它的数据数组,另一个是同样大小的布尔数组。
因此,所有操作都必须考虑这两个数组。它不仅要计算新的 data,还要计算新的 mask。
它可以采取多种方法(取决于操作):
- 直接使用 data。
- 使用压缩过的 data,即删除了掩盖值的新数组。
- 使用填充过的 data,其中掩盖值被替换为 fillvalue 或一些无害的值(例如,在加法时为 0,在乘法时为 1)。
掩码值的数量(0 或全部)在速度上没有或者很少有影响。
因此,你看到的速度差异并不奇怪。有很多额外的计算在进行。ma.core.py 文件中说,这个包最初是在 numpy 出现之前开发的,并在 2005 年左右纳入了 numpy。虽然一直有更新以保持更新,但我认为它没有得到重大改进。
以下是 np.ma.max 方法的代码:
def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
_mask = self._mask
newmask = _check_mask_axis(_mask, axis, **kwargs)
if fill_value is None:
fill_value = maximum_fill_value(self)
if out is None:
result = self.filled(fill_value).max(
axis=axis, out=out, **kwargs).view(type(self))
if result.ndim:
result.__setmask__(newmask)
if newmask.ndim:
np.copyto(result, result.fill_value, where=newmask)
elif newmask:
result = masked
return result
....
关键步骤如下:
fill_value = maximum_fill_value(self) # depends on dtype
self.filled(fill_value).max(
axis=axis, out=out, **kwargs).view(type(self))
您可以尝试使用“filled”来查看数组中发生了什么。
In [40]: arr = np.arange(10.)
In [41]: arr
Out[41]: array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
In [42]: Marr = np.ma.masked_array(arr, mask=[0]*9 + [1])
In [43]: Marr
Out[43]:
masked_array(data=[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, --],
mask=[False, False, False, False, False, False, False, False,
False, True],
fill_value=1e+20)
In [44]: np.ma.maximum_fill_value(Marr)
Out[44]: -inf
In [45]: Marr.filled()
Out[45]:
array([0.e+00, 1.e+00, 2.e+00, 3.e+00, 4.e+00, 5.e+00, 6.e+00, 7.e+00,
8.e+00, 1.e+20])
In [46]: Marr.filled(_44)
Out[46]: array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., -inf])
In [47]: arr.max()
Out[47]: 9.0
In [48]: Marr.max()
Out[48]: 8.0