什么时候结构化掩码数组上的高级索引*真的*返回一个副本?

时间:2016-06-15 17:36:00

标签: numpy indexing structured-array masked-array

当我有一个带有布尔索引的结构化蒙版数组时,在什么条件下我会得到一个视图,什么时候能得到一个副本? documentation表示高级索引始终返回副本,但事实并非如此,因为X[X>0]=42之类的东西在技术上是高级索引,但分配有效。我的情况比较复杂:

我想根据另一个字段的标准设置特定字段的掩码,所以我需要获取字段,应用布尔索引,并获取掩码。有3个! = 6个订单。

的制备:将

In [83]: M = ma.MaskedArray(random.random(400).view("f8,f8,f8,f8")).reshape(10, 10)

In [84]: crit = M[:, 4]["f2"] > 0.5
  1. 字段 - 索引 - 掩码(失败):

    In [85]: M["f3"][crit, 3].mask = True
    
    In [86]: print(M["f3"][crit, 3].mask)
    [False False False False False]
    
  2. 索引 - 字段 - 掩码(失败):

    In [87]: M[crit, 3]["f3"].mask = True
    
    In [88]: print(M[crit, 3]["f3"].mask)
    [False False False False False]
    
  3. 索引 - 掩码 - 字段(失败):

    In [94]: M[crit, 3].mask["f3"] = True
    
    In [95]: print(M[crit, 3].mask["f3"])
    [False False False False False]
    
  4. 掩码 - 索引 - 字段(失败):

    In [101]: M.mask[crit, 3]["f3"] = True
    
    In [102]: print(M.mask[crit, 3]["f3"])
    [False False False False False]
    
  5. 字段 - 掩码 - 索引(成功):

    In [103]: M["f3"].mask[crit, 3] = True
    
    In [104]: print(M["f3"].mask[crit, 3])
    [ True  True  True  True  True]
    
    # set back to False so I can try method #6
    
    In [105]: M["f3"].mask[crit, 3] = False
    
    In [106]: print(M["f3"].mask[crit, 3])
    [False False False False False]
    
  6. 掩码 - 字段 - 索引(成功):

    In [107]: M.mask["f3"][crit, 3] = True
    
    In [108]: print(M.mask["f3"][crit, 3])
    [ True  True  True  True  True]
    
  7. 因此,看起来索引必须 last

2 个答案:

答案 0 :(得分:1)

__setitem__ v。__getitem__的问题非常重要,但对于结构化数组和屏蔽,当__getitem__首次制作副本时,更难以理清。

关于结构化数组,字段索引首先出现还是元素都不重要。但是,某些版本似乎在这方面存在错误。我试着找一个最近的SO问题,这是一个问题。

使用蒙版数组,存在如何正确修改蒙版的问题。 .mask是访问基础._mask数组的属性。但这是用__getattr__获取的。因此,简单的setitem v getitem区别并不直接适用。

让我们先跳过结构化的比特

In [584]: M = np.ma.MaskedArray(np.arange(4))

In [585]: M
Out[585]: 
masked_array(data = [0 1 2 3],
             mask = False,
       fill_value = 999999)

In [586]: M.mask
Out[586]: False

In [587]: M.mask[[1,2]]=True
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-587-9010ee8f165e> in <module>()
----> 1 M.mask[[1,2]]=True

TypeError: 'numpy.bool_' object does not support item assignment

最初mask是标量布尔值,而不是数组。

这有效

In [588]: M.mask=np.zeros((4,),bool)  # change mask to array

In [589]: M
Out[589]: 
masked_array(data = [0 1 2 3],
             mask = [False False False False],
       fill_value = 999999)

In [590]: M.mask[[1,2]]=True

In [591]: M
Out[591]: 
masked_array(data = [0 -- -- 3],
             mask = [False  True  True False],
       fill_value = 999999)

这不是

In [592]: M[[1,2]].mask=True

In [593]: M
Out[593]: 
masked_array(data = [0 -- -- 3],
             mask = [False  True  True False],
       fill_value = 999999)

M[[1,2]]显然是副本,分配的是mask属性,而不是M.mask

...

屏蔽数组具有.__setmask__方法。你可以在np.ma.core.py中研究它。 mask属性用

定义
mask = property(fget=_get_mask, fset=__setmask__, doc="Mask")

所以M.mask=...确实使用了这个。

所以看起来问题就是这样做

M.__getitem__(index).__setmask__(values)
因此副本。 M.mask[]=...正在执行

M._mask.__setitem__(index, values)

因为_getmask只是return self._mask

M["f3"].mask[crit, 3] = True

有效,因为M['f3']是一个视图。 (M[['f1','f3']]可以获得,但不能设置)。

M.mask["f3"]也是一种观点。我不完全确定相关获取和设置的顺序。 __setmask__具有专门处理复合dtype(结构化)的代码。

=========================

查看结构化数组,没有屏蔽复杂性,索引顺序很重要

In [607]: M1 = np.arange(16).view("i,i")

In [609]: M1[[3,4]]['f1']=[3,4]          # no change   
In [610]: M1[[3,4]]['f1']
Out[610]: array([7, 9], dtype=int32)

In [611]: M1['f1'][[3,4]]=[1,2]    # change
In [612]: M1
Out[612]: 
array([(0, 1), (2, 3), (4, 5), (6, 1), (8, 2), (10, 11), (12, 13), (14, 15)], dtype=[('f0', '<i4'), ('f1', '<i4')])

因此,我们仍然有__getitem__后跟__setitem__,我们必须注意get是返回视图还是副本。

答案 1 :(得分:0)

这是因为虽然高级索引会返回副本,但分配给高级索引仍然有效。只有高级索引是 last 操作的方法才能分配高级索引(通过__setitem__)。