将 Python 列表值的平均值转换为另一个列表

Posted

技术标签:

【中文标题】将 Python 列表值的平均值转换为另一个列表【英文标题】:Convert Average of Python List Values to Another List 【发布时间】:2014-03-06 02:51:58 【问题描述】:

我有这样的清单。

list = [["Joe", 5, 7], ["Joe", 6, 9], ["Mike", 1,4], ["Joe", 7,4], ["Mike", 5,7]]

如何将此列表转换为这样的列表:

list2 = [["Joe", 6.00, 6.66], ["Mike", 3.00, 5.50]]

list2[0][1] 和 list2[1][1] 是第一个列表中特定人群的平均值(6.00 来自(list[0][1]+list[1][1]+list[3][1])/3

我应该像这样使用迭代:

for i in range(len(list)):
...

或者..类似的东西?因为我是从 SQLite 导入列表,而列表总是在变化。

【问题讨论】:

【参考方案1】:

类似这样的:

>>> from collections import OrderedDict
>>> lis = [["Joe", 5, 7], ["Joe", 6, 9], ["Mike", 1,4], ["Joe", 7,4], ["Mike", 5,7]]
>>> d = OrderedDict()
>>> for item in lis:
...     d.setdefault(item[0], []).append(item[1:])

现在d 包含:

>>> d
OrderedDict([('Joe', [[5, 7], [6, 9], [7, 4]]), ('Mike', [[1, 4], [5, 7]])])

我们在这里使用了OrderedDict,所以这里保留了曾经见过的唯一键的有序排列。

现在我们可以遍历这个字典并获得每个键的列的平均值。 zip* 让我们可以很容易地得到一个列表的转置:

>>> zip(*[[5, 7], [6, 9], [7, 4]])
[(5, 6, 7), (7, 9, 4)]
>>> 

最终列表理解:

>>> [[k] + [sum(x)/float(len(x)) for x in zip(*v)] for k, v in d.items()]
[['Joe', 6.0, 6.666666666666667], ['Mike', 3.0, 5.5]]

您可以在 Python3 中删除 float 调用。如果名称 'Joe'、'Mike' 在输出列表中的顺序无关紧要,那么您可以简单地使用带有dict.setdefault 的普通字典或使用collections.defaultdict

【讨论】:

【参考方案2】:

使用itertools.groupby

>>> from itertools import groupby
>>> data = [["Joe", 5, 7], ["Joe", 6, 9], ["Mike", 1, 4], ["Joe", 7, 4], ["Mike", 5, 7]]
>>> data.sort()
>>> result = []
>>> for _, groups in groupby(d, lambda x: x[0]):
        it = iter(zip(*groups))
        row = [next(it)[0]]
        for values in it:
            row.append(sum(values) / len(values))
        result.append(row)

>>> result
[['Joe', 6.0, 6.666666666666667], ['Mike', 3.0, 5.5]]

【讨论】:

【参考方案3】:

既然你说你是从 sqlite 导入列表,你可能有兴趣使用现有的数据处理包,而不是逐个函数滚动你自己的函数。例如,在pandas 中,您可以将数据加载到DataFrame

>>> df = pd.DataFrame(yourlist)
>>> df
      0  1  2
0   Joe  5  7
1   Joe  6  9
2  Mike  1  4
3   Joe  7  4
4  Mike  5  7

[5 rows x 3 columns]
>>> df.groupby(0).mean()
      1         2
0                
Joe   6  6.666667
Mike  3  5.500000

[2 rows x 2 columns]

现在使用pandas 单独解决问题会显得过于矫枉过正,但如果您从数据库中提取数据,您可能需要对数据执行多项操作。

【讨论】:

这绝对看起来不错。 +1【参考方案4】:

这适用于您要求和的任意数量的值(在您的情况下为两个):

Python 3

from collections import defaultdict

rows = [["Joe", 5, 7], ["Joe", 6, 9], ["Mike", 1,4], ["Joe", 7,4], ["Mike", 5,7]]

d = defaultdict(list)
for k, *v in rows:
    d[k].append(v)

averages = [[k] + [sum(x) / len(v) for x in zip(*v)] for k, v in d.items()]
print(averages)

Python 2

items() 替换为iteritems(),在sum(x) 周围添加float,使用空格而不是括号使用print,并将for 循环更改为

for row in rows:
   d[row[0]].append(row[1:])

(Python 3 肯定不错。)


说明

defaultdictfor 循环创建从名称到值列表的映射。

'Mike': [[1, 4], [5, 7]], 'Joe': [[5, 7], [6, 9], [7, 4]]

k, v in d.items() 遍历每个名​​称和列表列表。

zip(*v) 接受[[5, 7], [6, 9], [7, 4]] 之类的内容并将其转换为[[5, 6, 7], [7, 9, 4]]。然后我们将这些相加并除以原始列表的数量。

我们附加[k] 和这个平均值列表以获得类似['Joe', 6.0, 6.67] 的列表。

顺便说一句,如果这是来自数据库,您是否考虑过在那里进行聚合?

【讨论】:

【参考方案5】:

另一种解决方案。它有点复杂,但没有进口的单衬里。

map(lambda x : [x[0],float(x[1])/x[3],float(x[2])/x[3]],reduce(lambda x,y : x[0:(len(x)-1)] + [[x[-1][0],x[-1][1]+y[1],x[-1][2]+y[2],x[-1][3]+1]] if ((y[0] == x[-1][0]) if (len(x)>0)  else False) else x + [[y[0],y[1],y[2],1]] ,arr,[]))

【讨论】:

以上是关于将 Python 列表值的平均值转换为另一个列表的主要内容,如果未能解决你的问题,请参考以下文章

列表推导(list comprehension)--Python

将对象列表转换为另一个对象

将spring服务列表转换为另一个Entity作为响应

根据名称将列表元素替换为另一个列表元素

Python将列表转换为具有多个键值的字典[关闭]

Swig:将成员变量(指向值的指针)转换为 python 列表