为了账号安全,请及时绑定邮箱和手机立即绑定

将 += 与 numpy.array 和 numpy.ma.array 一起使用的奇怪行为

将 += 与 numpy.array 和 numpy.ma.array 一起使用的奇怪行为

烙印99 2023-06-13 15:11:02
谁能向我解释以下结果?我知道这不是通常执行此操作的方式,但我发现此结果很奇怪。import numpy as npa = 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.
查看完整描述

1 回答

?
慕娘9325324

TA贡献1783条经验 获得超4个赞

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


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和的位置: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__函数,因此输出是一个掩码数组,但由于您要添加e到b(aka e = np.MaskedArray.__add__(b, e)),因此返回的掩码数据b,而在 中d = d + b,您将添加b到d和数据d被退回。


查看完整回答
反对 回复 2023-06-13
  • 1 回答
  • 0 关注
  • 82 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信