按列计算Python中列表的平均值

38
我有一个列表的列表: 类似于:
data = [[240, 240, 239],
        [250, 249, 237], 
        [242, 239, 237],
        [240, 234, 233]]

我想要像这样对其求平均值:

[average_column_1, average_column_2, average_column_3]

我的代码看起来不太优雅。 它是遍历列表的一种朴素方法,将总和保存在单独的容器中,然后再除以元素数量。

我认为有一种更Pythonic的方法可以做到这一点。 有什么建议吗? 谢谢

5个回答

71

纯Python:

from __future__ import division
def mean(a):
    return sum(a) / len(a)
a = [[240, 240, 239],
     [250, 249, 237], 
     [242, 239, 237],
     [240, 234, 233]]
print map(mean, zip(*a))

打印

[243.0, 240.5, 236.5]

NumPy:

a = numpy.array([[240, 240, 239],
                 [250, 249, 237], 
                 [242, 239, 237],
                 [240, 234, 233]])
print numpy.mean(a, axis=0)

Python 3:

from statistics import mean
a = [[240, 240, 239],
     [250, 249, 237], 
     [242, 239, 237],
     [240, 234, 233]]
print(*map(mean, zip(*a)))

3
"如果你决定选择这种方式,可以使用from future_builtins import map, zip语句。" - georg
2
+1 真整洁..看看第一个解决方案就可以证明 Python 代码可以多么简洁。 - Levon
2
“map” 在任何情况下都不是“Pythonic”的,谁需要在这里使用“numpy”?而就是被接受的答案? - Oleh Prypin
8
NumPy的解决方案更易于阅读,更简明,更快,并且使用的内存更少,因此我提到它是为那些正在使用NumPy的人。至于为什么你认为map()存在,并且在Python 3.x中仍然存在呢? - Sven Marnach
@nealmcb OlehPrypin从未说过该解决方案在Python 3中无法工作。实际上,它仍然可以工作,因为通常您会想要迭代平均值,而不仅仅是打印列表。Python核心开发人员故意将map()保留为Python 3中的内置函数,而其他函数式编程函数则被删除(apply())或移动到模块中(reduce())。这使得代码简洁易读。 - Sven Marnach
显示剩余2条评论

32
data = [[240, 240, 239],
        [250, 249, 237], 
        [242, 239, 237],
        [240, 234, 233]]
avg = [float(sum(col))/len(col) for col in zip(*data)]
# [243.0, 240.5, 236.5]

这能工作是因为zip(*data)会给你一个将列分组的列表,float()调用仅在Python 2.x上必要,因为它使用整数除法,除非使用了from __future__ import division


我相信这个答案是最好的。它也是第一个。 - Oleh Prypin
1
@BlaXpirit:在SO上,过于强调速度,重要的应该是质量。另外请注意,这个答案排名第三(如果我们计算已删除的答案,则为第四)。 - Sven Marnach

15

使用zip(),如下所示:

averages = [sum(col) / float(len(col)) for col in zip(*data)]

zip()接受多个可迭代对象作为参数,并返回这些可迭代对象的切片(以元组形式),直到其中一个可迭代对象无法再返回任何内容。实际上,它执行一种转置操作,类似于矩阵。

>>> data = [[240, 240, 239],
...         [250, 249, 237], 
...         [242, 239, 237],
...         [240, 234, 233]]

>>> [list(col) for col in zip(*data)]
[[240, 250, 242, 240],
 [240, 249, 239, 234],
 [239, 237, 237, 233]]

通过对每个切片执行sum(),你可以有效地得到列的总和。只需除以该列的长度即可得到均值。

补充说明:在Python 2.x中,整数的除法默认向下取整,这就是为什么要调用float()将结果“提升”为浮点类型的原因。


别忘了除以长度 ;) - mgilson
5
值得补充说明的是:zip 是一个函数,它接受多个序列并按“逐列”基础返回元组。因此,它会返回 (x[0][0], x[1][0], x[2][0]),然后是 (x[1][0], x[1][1], x[1][2]) 等等。但是,一旦给定行的项目用完,它就会停止检索。在代码中更容易进行图解,您想展示一下它的工作原理吗? - Chris Pfohl

10
import numpy as np

data = [[240, 240, 239],
        [250, 249, 237], 
        [242, 239, 237],
        [240, 234, 233]]

np.mean(data, axis=0)
# array([ 243. ,  240.5,  236.5])

看起来可以工作。


2
你可以使用mapzip
list(map(lambda x: sum(x)/len(x), zip(*data)))

[243.0, 240.5, 236.5]

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