3

谁能向我解释以下结果?我知道这不像通常会执行此操作,但我发现这个结果很奇怪。

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,  True,  True,  True,  True,  True, 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.

4

1 回答 1

2

我将从一个更简单的示例开始,以便更好地理解:

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)(更具体地说,由于掩码数组是 ndarrays 的子类,它使用__radd__)并且不是就地分配。这意味着它创建一个新对象并在添加时使用等式右侧的更宽类型,因此将 d (这是一个未屏蔽的数组)转换为屏蔽数组(因为b是一个屏蔽数组),因此添加使用有效仅值(在这种情况下没有值,因为 的所有元素b都被屏蔽且无效)。这会产生一个d具有相同掩码的掩码数组,b而数据d保持不变。

这种行为差异不是 Numpy 特有的,也适用于 python 本身。OP 在问题中提到的案例具有类似的行为,正如@alaniwi 在评论中提到的那样,带掩码的布尔索引a并不是该行为的基础。使用a屏蔽b,cd的元素仅限制对屏蔽元素的分配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__函数,因此输出是掩码数组,但是由于您要添加eb(aka e = np.MaskedArray.__add__(b, e)),所以b返回掩码数据,而在 中d = d + b,您正在添加bd和数据d被退回。

于 2020-08-22T01:22:43.703 回答