为什么我的数组在 Numpy 中进行多维索引后会丢失其掩码?

Why does my array lose its mask after doing multidimensional indexing in Numpy?

我希望使用多维 MaskedArray 作为索引数组:

数据:

In [149]: np.ma.arange(10, 60, 2)
Out[149]: 
masked_array(data = [10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58],
             mask = False,
       fill_value = 999999)

指数:

In [140]: np.ma.array(np.arange(20).reshape(4, 5), 
                      mask=np.arange(20).reshape(4, 5) % 3)
Out[140]: 
masked_array(data =
 [[0 -- -- 3 --]
 [-- 6 -- -- 9]
 [-- -- 12 -- --]
 [15 -- -- 18 --]],
             mask =
 [[False  True  True False  True]
 [ True False  True  True False]
 [ True  True False  True  True]
 [False  True  True False  True]],
       fill_value = 999999)

期望的输出:

In [151]: np.ma.arange(10, 60, 2)[np.ma.array(np.arange(20).reshape(4, 5), mask=np.arange(20).reshape(4, 5) % 3)]
Out[151]: 
masked_array(data =
 [[10 -- -- 16 --]
 [-- 22 -- -- 28]
 [-- -- 34 -- --]
 [40 -- -- 46 --]],
             mask =
 False,
       fill_value = 999999)

实际输出:

In [160]: np.ma.arange(10, 60, 2)[np.ma.array(np.arange(20).reshape(4, 5), mask=np.arange(20).reshape(4, 5) % 3)]
Out[160]: 
masked_array(data =
 [[10 12 14 16 18]
 [20 22 24 26 28]
 [30 32 34 36 38]
 [40 42 44 46 48]],
             mask =
 False,
       fill_value = 999999)

为什么生成的数组丢失了掩码?根据此处的回答:Indexing with Masked Arrays in numpy,这种索引方法非常糟糕。为什么?

尝试使用这样的 choose 方法:

np.ma.array(np.arange(20).reshape(4, 5), mask=np.arange(20).reshape(4, 5) % 3).
            choose(np.ma.arange(10, 60, 2))

给出:

masked_array(data =
 [[10 -- -- 16 --]
 [-- 22 -- -- 28]
 [-- -- 34 -- --]
 [40 -- -- 46 --]],
             mask =
 [[False  True  True False  True]
 [ True False  True  True False]
 [ True  True False  True  True]
 [False  True  True False  True]],
       fill_value = 999999)

看起来使用掩码数组进行索引只是忽略了掩码。在不深入研究文档或代码的情况下,我会说 numpy 数组索引没有掩码数组 subclass 的特殊知识。您得到的数组只是正常的 arange(20) 索引。

但是你可以执行正常的索引,'copy'掩码:

In [13]: data=np.arange(10,60,2)

In [14]: mI = np.ma.array(np.arange(20).reshape(4,5),mask=np.arange(20).reshape(4,5) % 3)

...

In [16]: np.ma.array(data[mI], mask=mI.mask)
Out[16]: 
masked_array(data =
 [[10 -- -- 16 --]
 [-- 22 -- -- 28]
 [-- -- 34 -- --]
 [40 -- -- 46 --]],
             mask =
 [[False  True  True False  True]
 [ True False  True  True False]
 [ True  True False  True  True]
 [False  True  True False  True]],
       fill_value = 999999)

你真的需要将索引和屏蔽合并到一个操作中吗(和屏蔽数组)。如果掩码是分开的,此操作同样有效。

 I = np.arange(20).reshape(4,5)
 m = (np.arange(20).reshape(4,5) % 3)>0
 np.ma.array(data[I], mask=m)

如果屏蔽的索引元素无效(例如超出范围),您可以用有效的内容填充它们(如果需要,随后进行屏蔽):

data[mI.filled(fill_value=0)]

您是否在 numpy 掩码数组文档中看到过使用掩码数组索引另一个数组的示例?或者所有的屏蔽数组都是'data'?设计者可能从未打算让您使用屏蔽索引。


掩码数组 .choose 之所以有效,是因为它使用了一种已针对掩码数组进行 subclass 处理的方法。常规索引可能会将索引转换为常规数组,例如:data[np.asarray(mI)].


MaskedArray class 的 __getitem__ 方法开始:

    def __getitem__(self, indx):

        Return the item described by i, as a masked array.

        """
        # This test is useful, but we should keep things light...
#        if getmask(indx) is not nomask:
#            msg = "Masked arrays must be filled before they can be used as indices!"
#            raise IndexError(msg)

这是在掩码数组上执行 [] 时调用的方法。显然,开发人员考虑正式阻止使用屏蔽索引,但认为这不是一个足够重要的问题。有关详细信息,请参阅 np.ma.core.py 文件。