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

Average of numpy array ignoring specified value

我有许多一维 numpy ndarrays,其中包含给定节点与网络中所有其他节点之间的路径长度,我想为其计算平均值。问题很复杂,因为如果两个节点之间不存在路径,则算法 returns 给定连接的值为 2147483647。如果我不处理这个值,它显然会严重夸大我的平均值,因为典型的路径长度在我的网络中介于 1 和 3 之间。

处理这个问题的一个选择是遍历所有数组的所有元素,并将 2147483647 替换为 NaN,然后使用 numpy.nanmean 求平均值,尽管这可能是不是最有效的方法。有没有一种方法可以用 numpy 忽略 2147483647?

的所有值来计算平均值

我应该补充一点,我可以对多达数百万个数组和数百万个值进行平均,因此在如何找到平均值方面的任何性能提升都会产生真正的不同。

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

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

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

哦,我猜你正在计算均值,因为你已经严格检查了基础分布是否正常,所以它有意义,不是吗?

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

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

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