我有一些1维numpy ndarray,包含给定节点和网络中所有其他节点之间的路径长度,我想计算平均值。事情是复杂的,但如果两个节点之间不存在路径,则该算法为该给定连接返回值2147483647。如果我不理会这个值,那么显然会大大夸大我的平均值,因为我的网络中典型的路径长度介于1到3之间。
处理此问题的一个选择是循环遍历所有数组的所有元素,并将2147483647
替换为NaN
,然后使用numpy.nanmean
查找平均值,尽管可能不是最有效的方法。有没有办法用numpy计算平均值而忽略2147483647
的所有值?
我应该补充一点,我可以拥有多达数百万个数组,其平均值超过数百万,因此平均值的任何性能提升都会产生真正的差异。
答案 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