numpy数组的平均值忽略指定的值

时间:2016-08-24 16:05:18

标签: python arrays performance numpy graph-tool

我有一些1维numpy ndarray,包含给定节点和网络中所有其他节点之间的路径长度,我想计算平均值。事情是复杂的,但如果两个节点之间不存在路径,则该算法为该给定连接返回值2147483647。如果我不理会这个值,那么显然会大大夸大我的平均值,因为我的网络中典型的路径长度介于1到3之间。

处理此问题的一个选择是循环遍历所有数组的所有元素,并将2147483647替换为NaN,然后使用numpy.nanmean查找平均值,尽管可能不是最有效的方法。有没有办法用numpy计算平均值而忽略2147483647的所有值?

我应该补充一点,我可以拥有多达数百万个数组,其平均值超过数百万,因此平均值的任何性能提升都会产生真正的差异。

3 个答案:

答案 0 :(得分:3)

为什么不使用常规的numpy过滤?

m = my_array[my_array != 2147483647].mean()

顺便说一下,如果你真的想要速度,你的整个算法描述看起来肯定是天真的,可以通过很多改进。

哦,我猜你正在计算平均值,因为你已经严格检查了基础分布是否正常,这意味着什么,不是吗?

答案 1 :(得分:1)

np.nanmean(np.where(my_array == 2147483647, np.nan, my_array))

<强>计时

a = np.random.randn(100000)
a[::10] = 2147483647

%timeit np.nanmean(np.where(a == 2147483647, np.nan, a))
1000 loops, best of 3: 639 µs per loop

%timeit a[a != 2147483647].mean()
1000 loops, best of 3: 259 µs per loop

import pandas as pd

%timeit pd.Series(a).ne(2147483647).mean()
1000 loops, best of 3: 493 µs per loop

答案 2 :(得分:1)

一种方法是一次性获取所有元素的总和,然后从无效元素中删除贡献。最后,我们需要得到平均值本身,除以有效元素的数量。所以,我们会有这样的实现 -

def mean_ignore_num(arr,num):
    # Get count of invalid ones
    invc = np.count_nonzero(arr==num)

    # Get the average value for all numbers and remove contribution from num
    return (arr.sum() - invc*num)/float(arr.size-invc)

验证结果 -

In [191]: arr = np.full(10,2147483647).astype(np.int32)
     ...: arr[1] = 5
     ...: arr[4] = 4
     ...: 

In [192]: arr.max()
Out[192]: 2147483647

In [193]: arr.sum() # Extends beyond int32 max limit, so no overflow
Out[193]: 17179869185

In [194]: arr[arr != 2147483647].mean()
Out[194]: 4.5

In [195]: mean_ignore_num(arr,2147483647)
Out[195]: 4.5

运行时测试 -

In [38]: arr = np.random.randint(0,9,(10000))

In [39]: arr[arr != 7].mean()
Out[39]: 3.6704609489462414

In [40]: mean_ignore_num(arr,7)
Out[40]: 3.6704609489462414

In [41]: %timeit arr[arr != 7].mean()
10000 loops, best of 3: 102 µs per loop

In [42]: %timeit mean_ignore_num(arr,7)
10000 loops, best of 3: 36.6 µs per loop