将 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 肯定不错。)
说明
defaultdict
和 for
循环创建从名称到值列表的映射。
'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 列表值的平均值转换为另一个列表的主要内容,如果未能解决你的问题,请参考以下文章