问题描述
有人可以向我解释以下结果吗? 我知道这不是通常会执行的操作,但是我发现此结果很奇怪。
import numpy as np
a = np.ma.masked_where(np.arange(20)>10,np.arange(20))
b = np.ma.masked_where(np.arange(20)>-1,np.arange(20))
c = np.zeros(a.shape)
d = np.zeros(a.shape)
c[~a.mask] += b[~a.mask]
print(b[~a.mask])
#masked_array(data=[--,--,--],# mask=[ True,True,True],# fill_value=999999,# dtype=int64)
print(c)
#[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
d[~a.mask] = d[~a.mask] + b[~a.mask]
print(d)
#[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
我希望c
不会改变,但是我想这里与内存中的对象有关。另外,+=
保留原始对象,而=
和+
创建新的d
。
我只是不太了解将数据来自何处的数据添加到c
中。
解决方法
为了更好的理解,我将从一个简单的示例开始:
b = np.ma.masked_where(np.arange(20)>-1,np.arange(20))
#b: [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]
#b.data: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
c = np.zeros(b.shape)
#c: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
d = np.zeros(b.shape)
#d: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
c += b
#c: [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19.]
d = d + b
#d: [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]
#d.data: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
第一个操作c += b
是就地操作。换句话说,它等效于c = type(c).__iadd__(c,b)
根据c
的类型进行加法,该类型不是掩码数组,因此b
的数据用作未掩码。
另一方面,d = d + b
等效于d = np.MaskedArray.__add__(d,b)
(更具体地说,由于掩码数组是ndarray的子类,因此它使用__radd__
)并且是 不就地分配。这意味着它将创建一个新对象,并在添加时在等式的右侧使用较宽的类型,并因此将d(这是一个未掩码的数组)转换为掩码的数组(因为b
是一个掩码的数组),因此,加法仅使用有效值(在这种情况下,由于b
的所有元素均被屏蔽且无效,因此没有有效值)。这样会导致掩码数组d
具有与b
相同的掩码,而d
的数据保持不变。
这种行为差异不是Numpy特有的,它也适用于python本身。 OP在问题中提到的情况具有相似的行为,并且正如注释中提到的@alaniwi一样,使用掩码a
进行布尔索引并不是该行为的基础。使用a
来掩盖b
,c
和d
的元素仅是通过a
(而不是数组的所有元素)限制对掩码元素的赋值仅此而已。
要使事情变得更有趣并且更清晰,请在右侧切换b
和d
的位置:
e = np.zeros(b.shape)
#e: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
e = b + e
#e: [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]
#e.data: [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19.]
请注意,类似于d = d + b
,右侧使用掩码数组__add__
函数,因此输出为掩码数组,但是由于您要向{{1添加e
}}(又名b
),返回e = np.MaskedArray.__add__(b,e)
的掩码数据,而在b
中,您要向d = d + b
添加b
和{{ 1}}返回。