从大型蒙版数组中获取平均值的适当方法是什么?通常情况下我只会调用.mean()
,但对于非常大的数组,这对我来说是失败的。
考虑创建一个包含百万元素的数组,所有元素的值都为500,如:
a = np.ones(1000000, dtype=np.int16) * 500
然后创建一个随机掩码并将它们组合成一个新的masked array
:
mask = np.random.randint(0, 2, a.size)
b = np.ma.masked_array(a, mask=mask)
数组b
继承dtype
,也是int16
。
从b
获取平均值可以通过不同的方式完成,但都可以得到相同的结果。但是non-ma
函数忽略了掩码,不应该使用它。
print(np.average(b), np.mean(b), np.ma.average(b), np.ma.mean(b))
(500.0, 500.0, 500.0, 500.0)
但如果我将原始数组大小从一百万增加到一千万,结果就会变成:
print(np.average(b), np.mean(b), np.ma.average(b), np.ma.mean(b))
(500.0, -359.19365132075774, -359.19365132075774, -359.19365132075774)
现在只有np.average
似乎正确,但正如所说的那样忽略了掩码并计算整个数组的平均值,这可以在用{{更改一些掩码值时显示1}}例如。我希望b[b.mask] = 1000
能做同样的事情。
将屏蔽数组np.mean
投射到b
会导致:
float32
将蒙面数组b = b.astype(np.float32)
print(np.average(b), np.mean(b), np.ma.average(b), np.ma.mean(b))
(511.18945, 510.37895680000003, 510.37895680000003, 510.37895680000003)
强制转换为b
(根据文档默认情况下应该这样做)会导致:
float64
所以转换为b = b.astype(np.float64)
print(np.average(b), np.mean(b), np.ma.average(b), np.ma.mean(b))
(500.0, 500.0, 500.0, 500.0)
似乎有效,但我宁愿避免这种情况,因为它会大大增加内存占用量。
在测试其中的一部分时,我还注意到,如果大小是一百万,那么在非掩码数组(a)上调用float64
会得到正确的结果,当它的一千万时,它会得到错误的结果,而{ {1}}对于这两种尺寸都是正确的。
在此示例中,有人可以解释np.ma.average
与数组的np.ma.mean
之间的关系吗?当发生这种情况时,它对我来说有点神秘,以及如何正确处理它。
所有这些都是在64位Win 7机器上的Numpy 1.8.1中完成的。通过conda安装。
这是一个复制我所做的笔记本:
http://nbviewer.ipython.org/gist/RutgerK/69b60da73f464900310a
答案 0 :(得分:2)
例如,在使用
b[b.mask] = 1000
更改某些屏蔽值时,可以显示此信息。我希望np.mean能做同样的事情。
这是不正确的,b.mask为True,其中有掩码值。当您为屏蔽值指定新值时,您将取消屏蔽它们,因此有效地使数组中的所有值都有效,您可以使用b[np.invert(b.mask)]
。
所以这应该有效:
import numpy as np
a = np.ones(10000000, dtype=np.int64) * 500
mask = np.random.randint(0, 2, a.size)
b = np.ma.masked_array(a, mask=mask)
b[np.invert(b.mask)] = 1000
print(np.average(b), np.mean(b), np.ma.average(b), np.ma.mean(b))
除了np.average
之外,它会为您提供正确的值。
除此之外,当你得到负值/不正确值时,这是因为你得到一个整数溢出。使用dtype=np.int64
代替它应该解决它,
编辑:另一种选择是使用带有dtype=object
的Python整数而不是固定宽度的整数,但这会更慢,这种变化会导致np.average
崩溃,但是其余方法正常工作。
编辑2:正如评论中所说,在这种情况下,没有必要增加数组元素的大小,我们可以调用np.mean(b, dtype=np.float64)
以便{{1使用更大的累加器来避免溢出。