2014-02-08 37 views
6

我有这样的列表。将Python列表值的平均值转换为另一个列表

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]是从与spesific第一列表中的平均值人(6.00从(list[0][1]+list[1][1]+list[3][1])/3

来的时候,使用迭代这样的:

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

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

回答

4

事情是这样的:

>>> 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包含:因为我们使用的OrderedDict这里

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

的有序见过的唯一密钥被保存在这里。

现在我们可以迭代这个字典并获得每个键的列的平均值。 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

3

使用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]] 
5

既然你说你从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将是孤立的问题显著矫枉过正,但如果你从数据库中提取数据,你很可能会想要用数据做多件事情。

+0

这绝对看起来不错。 +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(),在附近添加,使用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]这样的列表。

顺便说一句,如果这是来自数据库,你有没有考虑过在那里做聚合?

1

一个替代解决方案。它有点复杂,但没有进口单线程。

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,[])) 
相关问题