我正在调查numpy issue 2972以及一些相关问题。事实证明,所有这些问题都与数组本身结构化的情况有关,但其掩码不是:
In [38]: R = numpy.zeros(10, dtype=[("A", "<f2"), ("B", "<f4")])
In [39]: Rm = numpy.ma.masked_where(R["A"]<5, R)
In [41]: Rm.dtype
Out[41]: dtype([('A', '<f2'), ('B', '<f4')])
In [42]: Rm.mask.dtype
Out[42]: dtype('bool')
# Now, both `__getitem__` and `__repr__` will result in errors — see issue #2972
如果我以不同方式创建蒙版数组,则掩码dtype的结构类似于数组本身的dtype:
In [44]: Q.dtype
Out[44]: dtype([('A', '<f4'), ('B', '<f4')])
In [45]: Q.mask.dtype
Out[45]: dtype([('A', '?'), ('B', '?')])
前一种情况暴露出几个问题。例如,Rm.__repr__()
和Rm["A"]
都会生成IndexError
,但过去只有ValueError
。
按照设计,模式应该是可能的,A.dtype
的结构是什么,但A.mask.dtype
不是结构化的?
换句话说:是__repr__
中的__getitem__
和numpy.ma.core.MaskedArray
方法中的错误,或者是之前发生的真正错误 - 通过允许这样的掩码结构化数组存在于第一名?
答案 0 :(得分:2)
第一种情况中的错误表明这些方法期望掩码具有与基本数组相同的字段数(和名称)
__getitem__: dout._mask = _mask[indx]
_recursive_printoption: (curdata, curmask) = (result[name], mask[name])
如果屏蔽数组是使用&#39; main&#39;构造函数,掩码具有相同的结构
Rn = np.ma.masked_array(R, mask=R['A']>5)
Rn.mask.dtype: dtype([('A', '?'), ('B', '?')])
换句话说,每个元素的每个字段都有一个掩码值。
masked_array
文档明显打算采用相同的形状&#39;包括dtype
结构。 Mask: Must be convertible to an array of booleans with the same shape as 'data'.
如果我尝试以与masked_where
相同的方式设置掩码
Rn._mask=R['A']>5
我得到了相同的打印错误。结构化掩码被新布尔值覆盖,改变其dtype。相反,如果我使用
Rn.mask=R['A']<5
Rn
打印得很好。 .mask
是一个属性,其set
方法显然正确处理结构化掩码。
没有深入研究代码历史(在github上),我的猜测是masked_where
是一个便利函数,当结构dtypes被添加到ma
代码的其他部分时,它没有被更新。与ma.masked_array
相比,它是一个根本不看dtype的简单函数。其他便利功能如ma.masked_greater
使用masked_where
。将result._mask = cond
更改为result.mask = cond
可能是解决此问题所需的全部内容。
您如何彻底测试非结构化面罩的后果?
Rm.flatten()
返回一个带有结构化掩码的数组,即使它是以非结构化掩码开始的。这是因为它使用了对字段敏感的Rm.__setmask__
。这就是set
属性的mask
函数。
Rm.tolist() # same error as str()
masked_where
以:
cond = make_mask(condition)
make_mask
返回简单的&#39; bool&#39; D型。也可以使用dtype调用它,生成结构化掩码:np.ma.make_mask(R['A']<5,dtype=R.dtype)
。但是在masked_where
中使用时,这样的结构化蒙版变得扁平化。 masked_where
不仅允许使用非结构化掩码,还会强制使用非结构化掩码。
您的非结构化蒙版已部分实现,recordmask
属性:
recordmask = property(fget=_get_recordmask)
我之所以这么说,是因为它有get
方法,但set
方法尚未实现。见def _set_recordmask(self):
我越是看到这一点,我就越相信masked_where
是错的。可以将其更改为设置结构化蒙版,但它与masked_array
没有太大区别。如果在构造数组时引发错误(具有dtype.names
)可能会更好。这样masked_where
对于非结构化数字数组仍然有用,同时防止对结构化数组的误用。
我还应该看一下测试代码。