结构化数组的掩码应该是自己构造的吗?

时间:2015-01-28 00:08:43

标签: python arrays numpy structured-array

我正在调查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方法中的错误,或者是之前发生的真正错误 - 通过允许这样的掩码结构化数组存在于第一名?

1 个答案:

答案 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对于非结构化数字数组仍然有用,同时防止对结构化数组的误用。

我还应该看一下测试代码。