计算非零值的平均数

6
我有一些列表,想要求出非零值的平均数。
例如:
 [2,2,0,0,0] -> 2    
 [1,1,0,1,0]  -> 1  
 [0,0,0,9,0] -> 9    
 [2,3,0,0,0] -> 2.5

我现在正在做这件事:

list_ = [1,1,0,1,0]  
non_zero = [float(v) for v in list_ if v>0]
averge = sum(non_zero)/len(non_zero)

如何更高效地进行这个操作?

2
非零意味着 v!=0。而在你的情况下,v>0 意味着正数。 - Moinuddin Quadri
你的输入不是一个列表的列表吗,像这样:[[2, 2, 0, 0, 0], [1, 1, 0 ....]] 或者是一个数组吗? - Divakar
3个回答

12
如果您从一个numpy数组开始,您可以使用np.nonzero来过滤数组,然后取平均值:
a = np.array([2,3,0,0,0])
average = a[np.nonzero(a)].mean()
你还可以通过布尔索引来筛选,这似乎更快:

您可以使用布尔索引进行筛选,这似乎更快:


(注意:要保留原始HTML标记,所以翻译只涉及文本内容)
average = a[a!=0].mean()

您还可以通过使用a>0轻松更改上面的方法以过滤正值。

时间

使用以下设置:

a = np.random.randint(100, size=10**6)

我得到了以下时间:

%timeit a[a!=0].mean()
100 loops, best of 3: 4.59 ms per loop

%timeit a[a.nonzero()].mean()
100 loops, best of 3: 9.82 ms per loop

3

以下是使用向量化方法将列表转换为2D数组后求和的代码:

from __future__ import division
a = np.asarray(list_)
a.sum(1)/(a!=0).sum(1)

样例运行 -

In [32]: list_  #  Input list of lists
Out[32]: [[2, 2, 0, 0, 0], [1, 1, 0, 1, 0], [0, 0, 0, 9, 0], [2, 3, 0, 0, 0]]

In [33]: a = np.asarray(list_) # Convert to array

In [34]: a.sum(1)/(a!=0).sum(1) # Divide row sums by count of non-zeros 
Out[34]: array([ 2. ,  1. ,  9. ,  2.5])

2

您可以使用np.nonzero函数:

l = np.array([2,2,0,0,0])

l[l.nonzero()].mean()
Out[17]: 2.0

将您当前的方法和这个方法封装在函数中的一个简单基准:

def luis_way(l):
    non_zero = [float(v) for v in l if v>0]
    average = sum(non_zero)/len(non_zero)
    return average

def np_way(l):
    return l[l.nonzero()].mean()



In [19]: some_l = np.random.randint(2, size=10000)
In [20]: %timeit luis_way(some_l)
100 loops, best of 3: 4.72 ms per loop
In [21]: %timeit np_way(some_l)
1000 loops, best of 3: 262 µs per loop

对于小规模的输入,你现在的方法可能还可以。但值得注意的是,你当前的答案实际上并没有取到所有的非零元素,而只考虑了正数元素。


嘿,我只使用正数。但是谢谢你的提醒,我没有注意到它。 - Luis Ramon Ramirez Rodriguez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接