对numpy.array和numpy.ma.array使用+ =的奇怪行为

问题描述

有人可以向我解释以下结果吗? 我知道这不是通常会执行的操作,但是我发现此结果很奇怪。

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来掩盖bcd的元素仅是通过a(而不是数组的所有元素)限制对掩码元素的赋值仅此而已。

要使事情变得更有趣并且更清晰,请在右侧切换bd的位置:

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}}返回。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...