6

在我的代码中,有时我尝试修改掩码数组的值,但 python 似乎忽略了这一点。我认为这与内存存储在数组中的方式有​​关,就好像我正在修改值的副本而不是值本身一样,但我对此不够精通,无法知道如何解决它。

这是我正在尝试做的简化版本:

    x = np.zeros((2,5)) # create 2D array of zeroes
    x[0][1:3] = 5       # replace some values along 1st dimension with 5

    mask = (x[0] > 0)   # create a mask to only deal with the non negative values

    x[0][mask][1] = 10  # change one of the values that is non negative 

    print x[0][mask][1] # value isn't changed in the original array

这个的输出是:

    5.0

什么时候应该是 10。

任何帮助将不胜感激,理想情况下,这需要是可扩展的(这意味着我不一定知道 x 的形状,或者值是非负的,或者我需要修改哪个)。

我在 Ubuntu 16.04.2 上的 python 2.7.12 上使用 numpy 1.11.0

谢谢 !

4

3 回答 3

4

让我们概括一下您的问题:

In [164]: x=np.zeros((2,5))
In [165]: x[0, [1, 3]] = 5      # index with a list, not a slice
In [166]: x
Out[166]: 
array([[ 0.,  5.,  0.,  5.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

当索引出现在 之前时=,它是 a 的一部分__setitem__并作用于原始数组。无论索引使用切片、列表还是布尔掩码,这都是正确的。

但是带有列表或掩码的选择会产生一个副本。进一步的索引分配仅影响该副本,而不影响原始文件。

In [167]: x[0, [1, 3]]
Out[167]: array([ 5.,  5.])
In [168]: x[0, [1, 3]][1] = 6
In [169]: x
Out[169]: 
array([[ 0.,  5.,  0.,  5.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

解决这个问题的最好方法是修改掩码本身:

In [170]: x[0, np.array([1,3])[1]] = 6
In [171]: x
Out[171]: 
array([[ 0.,  5.,  0.,  6.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

如果mask是布尔值,您可能需要将其转换为索引数组

In [174]: mask = x[0]>0
In [175]: mask
Out[175]: array([False,  True, False,  True, False], dtype=bool)
In [176]: idx = np.where(mask)[0]
In [177]: idx
Out[177]: array([1, 3], dtype=int32)
In [178]: x[0, idx[1]]
Out[178]: 6.0

或者您可以直接调整布尔值

In [179]: mask[1]=False
In [180]: x[0,mask]
Out[180]: array([ 6.])

因此,在您的大问题中,您需要注意索引何时生成视图并且它是副本。您需要熟悉使用列表、数组和布尔值进行索引,并了解如何在它们之间切换。

于 2017-05-11T18:59:31.823 回答
1

要了解发生了什么,我建议阅读此http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html

这归结为对花式索引的误导性使用。以下语句是相同的,您可以看到它使用掩码直接将 x 的元素设置为 10。

x[0][mask] = 10
x[0,mask] = 10
x.__setitem__((0, mask), 10)

另一方面,您正在做的是以下内容

x[0][mask][1] = 10
x[0,mask][1] = 10
x[0,mask].__setitem__(1, 10)
x.__getitem__((0, mask)).__setitem__(1, 10)

使用__getitem__()创建副本

总之,您需要重新考虑如何使用不同的掩码__setitem()__修改该单个数字

于 2017-05-11T18:09:15.620 回答
1

您创建的并不是真正的蒙面数组:

x = np.zeros((2,5))
x[0][1:3] = 5
mask = (x[0] > 0)
mask
Out[14]: array([False,  True,  True, False, False], dtype=bool)

所以,这只是一个布尔数组。要创建掩码数组,您应该使用numpy.ma模块:

masked_x = np.ma.array(x[0], mask=~(x[0] > 0)) # let's mask first row as you did
masked_x
Out[15]: 
masked_array(data = [-- 5.0 5.0 -- --],
             mask = [ True False False  True  True],
       fill_value = 1e+20)

现在您可以更改掩码数组,并相应地更改主数组:

masked_x[1] = 10.    
masked_x
Out[36]: 
masked_array(data = [-- 10.0 5.0 -- --],
             mask = [ True False False  True  True],
       fill_value = 1e+20)    
x
Out[37]: 
array([[  0.,  10.,   5.,   0.,   0.],
       [  0.,   0.,   0.,   0.,   0.]])

并注意在掩码数组中标记为的无效条目True

于 2017-05-11T18:06:41.360 回答