猿问

将 += 与 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,  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.


烙印99
浏览 110回答 1
1回答

慕娘9325324

我将从一个更简单的示例开始,以便更好地理解: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)which 根据 的类型进行加法c,这不是屏蔽数组,因此 的数据用作b未屏蔽的。另一方面,d = d + b等同于d = np.MaskedArray.__add__(d, b)(更具体地说,由于屏蔽数组是 ndarray 的子类,它使用__radd__)并且不是就地赋值。这意味着它创建一个新对象并在添加时使用等式右侧的更宽类型,因此将 d (这是一个未屏蔽的数组)转换为屏蔽数组(因为它是一个屏蔽数组),因此加法使用b有效仅值(在本例中没有值,因为所有元素都b被屏蔽且无效)。这会产生一个掩码数组,其掩码与数据保持不变时d相同。bd这种行为差异不是 Numpy 特有的,也适用于 python 本身。OP 问题中提到的案例具有类似的行为,正如@alaniwi 在评论中提到的那样,带有掩码的布尔索引a并不是该行为的基础。使用a屏蔽b, ,c和的元素d只是限制对被屏蔽元素的赋值a(而不是数组的所有元素),仅此而已。为了使事情更有趣,实际上更清晰,让我们切换右侧的b和的位置:de = 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__函数,因此输出是一个掩码数组,但由于您要添加e到b(aka e = np.MaskedArray.__add__(b, e)),因此返回的掩码数据b,而在 中d = d + b,您将添加b到d和数据d被退回。
随时随地看视频慕课网APP

相关分类

Python
我要回答