2014-02-08 3 views
6

У меня есть списки, подобные этому.Преобразование среднего значения списка питов в другой список

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]] 

песни2 [0] [1] и песни2 [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 содержит:

>>> 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]] 

Вы можете удалить float вызов в Python3. И если порядок имен «Joe», «Mike» не имеет значения в списке выходных данных, вы можете просто использовать обычный dict с 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(), добавьте float вокруг sum(x), используйте print с пространством, а не Паренс, и изменить цикл for к

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

(Python 3 обязательно хорошо.)


Объяснение

defaultdict и for loop создайте карту от имени до списка значения.

{'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,[])) 
Смежные вопросы