In my code, at some point I try to modify a value of a masked array, yet python seems to ignore this. I'm thinking this has to do with the way memory is stored in arrays, as if I were modifying a copy of the value and not the value itself, but I'm not well versed enough in this to have any clue how to resolve it.
在我的代码中,在某些时候,我试图修改一个蒙面数组的值,但是python似乎忽略了这一点。我认为这与内存存储在数组中的方式有关,就好像我修改了一个值的副本,而不是值本身,但是我还没有足够的知识来理解它。
Here is a simplified version of what I'm trying to do :
下面是我想做的一个简化版本:
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
the output of this is :
它的输出是:
5.0
when it should be 10.
应该是10。
Any help would be greatly appreciated, ideally this need to be scalable (meaning I don't necessarily know the shape of x, or where the values are non-negative, or which one I will need to modify).
任何帮助都将得到极大的赞赏,理想情况下,这需要是可伸缩的(这意味着我不一定知道x的形状,或者值是非负的,或者我需要修改的值)。
I'm working with numpy 1.11.0, on python 2.7.12 on Ubuntu 16.04.2
我和numpy 1.11.0一起工作,在python 2.7.12和Ubuntu 16.04.2上
Thanks !
谢谢!
3 个解决方案
#1
2
Let's generalize your problem a bit:
让我们概括一下你的问题:
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.]])
When the indexing occurs right before the =
, it's part of a __setitem__
and acts on the original array. This is true whether the indexing uses slices, a list or a boolean mask.
当索引发生在=之前时,它是__setitem__的一部分,并对原始数组起作用。无论索引使用的是片、列表还是布尔蒙版,都是如此。
But a selection with the list or mask produces a copy. Further indexed assignment affects only that copy, not the original.
但是带有列表或遮罩的选项会产生一个副本。进一步的索引赋值只影响复制,而不是原始的。
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.]])
The best way around this is to modify the mask itself:
解决这个问题的最好办法是修改面具本身:
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.]])
If the mask
is boolean, you may need to convert it to indexing array
如果掩码是布尔值,您可能需要将其转换为索引数组。
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
Or you can tweak the boolean values directly
或者可以直接调整布尔值
In [179]: mask[1]=False
In [180]: x[0,mask]
Out[180]: array([ 6.])
So in your big problem you need to be aware of when indexing produces a view and it is a copy. And you need to be comfortable with index with lists, arrays and booleans, and understand how to switch between them.
所以在你的大问题中,你需要意识到什么时候索引产生了一个视图,它是一个副本。您需要熟悉使用列表、数组和布尔值的索引,并了解如何在它们之间进行切换。
#2
1
It's not really a masked array what you've created:
它并不是你所创建的蒙面数组
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)
So, this is just a boolean array. To create a masked array you should use numpy.ma module:
这只是一个布尔数组。要创建蒙面数组,应该使用numpy。马模块:
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)
Now you can change your masked array, and accordingly the main array:
现在您可以更改您的屏蔽数组,并相应地更改主数组:
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.]])
And notice that in masked arrays invalid entries marked as True
.
注意,在掩蔽数组中,被标记为True的无效条目。
#3
1
To understand what's going on I suggest reading this http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html
为了理解发生了什么,我建议阅读http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html
This boils down to the misleading use of fancy indexing. The following statements are the same and as you can see it's directly setting to 10 the elements of x using mask.
这可以归结为对花哨的索引的误导使用。下面的语句是一样的,您可以看到它直接使用蒙版将x的元素设置为10。
x[0][mask] = 10
x[0,mask] = 10
x.__setitem__((0, mask), 10)
What you're doing on the other hand is the following
另一方面,你正在做的是下面的事情
x[0][mask][1] = 10
x[0,mask][1] = 10
x[0,mask].__setitem__(1, 10)
x.__getitem__((0, mask)).__setitem__(1, 10)
Which is creating a copy with __getitem__()
使用__getitem__()创建副本
In conclusion you need to rethink how to modify that single number with a different mask __setitem()__
总之,您需要重新考虑如何使用不同的掩码__setitem()__修改这个数字
#1
2
Let's generalize your problem a bit:
让我们概括一下你的问题:
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.]])
When the indexing occurs right before the =
, it's part of a __setitem__
and acts on the original array. This is true whether the indexing uses slices, a list or a boolean mask.
当索引发生在=之前时,它是__setitem__的一部分,并对原始数组起作用。无论索引使用的是片、列表还是布尔蒙版,都是如此。
But a selection with the list or mask produces a copy. Further indexed assignment affects only that copy, not the original.
但是带有列表或遮罩的选项会产生一个副本。进一步的索引赋值只影响复制,而不是原始的。
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.]])
The best way around this is to modify the mask itself:
解决这个问题的最好办法是修改面具本身:
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.]])
If the mask
is boolean, you may need to convert it to indexing array
如果掩码是布尔值,您可能需要将其转换为索引数组。
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
Or you can tweak the boolean values directly
或者可以直接调整布尔值
In [179]: mask[1]=False
In [180]: x[0,mask]
Out[180]: array([ 6.])
So in your big problem you need to be aware of when indexing produces a view and it is a copy. And you need to be comfortable with index with lists, arrays and booleans, and understand how to switch between them.
所以在你的大问题中,你需要意识到什么时候索引产生了一个视图,它是一个副本。您需要熟悉使用列表、数组和布尔值的索引,并了解如何在它们之间进行切换。
#2
1
It's not really a masked array what you've created:
它并不是你所创建的蒙面数组
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)
So, this is just a boolean array. To create a masked array you should use numpy.ma module:
这只是一个布尔数组。要创建蒙面数组,应该使用numpy。马模块:
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)
Now you can change your masked array, and accordingly the main array:
现在您可以更改您的屏蔽数组,并相应地更改主数组:
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.]])
And notice that in masked arrays invalid entries marked as True
.
注意,在掩蔽数组中,被标记为True的无效条目。
#3
1
To understand what's going on I suggest reading this http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html
为了理解发生了什么,我建议阅读http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html
This boils down to the misleading use of fancy indexing. The following statements are the same and as you can see it's directly setting to 10 the elements of x using mask.
这可以归结为对花哨的索引的误导使用。下面的语句是一样的,您可以看到它直接使用蒙版将x的元素设置为10。
x[0][mask] = 10
x[0,mask] = 10
x.__setitem__((0, mask), 10)
What you're doing on the other hand is the following
另一方面,你正在做的是下面的事情
x[0][mask][1] = 10
x[0,mask][1] = 10
x[0,mask].__setitem__(1, 10)
x.__getitem__((0, mask)).__setitem__(1, 10)
Which is creating a copy with __getitem__()
使用__getitem__()创建副本
In conclusion you need to rethink how to modify that single number with a different mask __setitem()__
总之,您需要重新考虑如何使用不同的掩码__setitem()__修改这个数字