python – 来自大型蒙版数组的Numpy平均值

什么是从大型掩模阵列获得平均值的适当方法?通常我只会调用.mean(),但对于非常大的数组,这对我来说是失败的.

考虑创建一个包含百万元素的数组,所有元素的值都为500,如:

a = np.ones(1000000, dtype=np.int16) * 500

然后创建一个随机掩码并将它们组合在一个新的掩码数组中:

mask = np.random.randint(0, 2, a.size)
b = np.ma.masked_array(a, mask=mask)

数组b继承dtype,也是一个int16.

从b获得平均值可以用不同的方式完成,但都可以得到相同的结果.但非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似乎是正确的,但正如所说的那样忽略了掩码并计算整个数组的平均值,这可以在用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)

因此,转换为float64似乎可行,但我宁愿避免这种情况,因为它会大大增加内存占用.

在测试其中一些时,我还注意到在非掩码数组(a)上调用np.ma.average会给出正确的结果,如果大小是一百万而错误的结果是千万,而np.ma.两种尺寸的平均值都是正确的.

在这个例子中,有人可以解释dtype和数组大小之间的关系吗?当发生这种情况时,它对我来说有点神秘,以及如何正确处理它.

所有这些都是在64位Win 7机器上的Numpy 1.8.1中完成的.通过conda安装.

这是一个复制我所做的笔记本:

http://nbviewer.ipython.org/gist/RutgerK/69b60da73f464900310a

最佳答案

this can be shown when changing some of the masked values with b[b.mask] = 1000 for example. I would expect np.mean to do the same though.

这是不正确的,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),以便np.mean使用更大的累加器,以避免溢出.

点赞