2014-02-08 36 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,[])) 
相關問題