从一个大型蒙面阵列的Numpy平均值

时间:2014-06-23 09:58:07

标签: python numpy

从大型蒙版数组中获取平均值的适当方法是什么?通常情况下我只会调用.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

1 个答案:

答案 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使用更大的累加器来避免溢出。