2016-05-04 3 views
3

У меня есть список, как это: # [YEAR, DAY, VALUE1, VALUE2, VALUE3]питон методы список GroupBy itertools

[[2014, 1, 10, 20, 30], 
[2014, 1, 3, 7, 4], 
[2014, 2, 14, 43,5], 
[2014, 2, 33, 1, 6] 
... 
[2013, 1, 34, 54, 3], 
[2013, 2, 23, 33, 2], 
...] 

и мне нужно сгруппировать по годам и дней, чтобы получить что-то вроде:

[[2014, 1, sum[all values1 with day=1), sum(all values2 with day =1), avg(all values3 with day=1)], 
[2014, 2, sum[all values1 with day=2), sum(all values2 with day =2), avg(all values3 with day=2)], 
.... 
[2013, 1, sum[all values1 with day=1), sum(all values2 with day =1), avg(all values3 with day=1)], 
[2013, 2, sum[all values1 with day=2), sum(all values2 with day =2), avg(all values3 with day=2)],, 
....] 

Как я могу сделать это с itertool ?, Я не могу использовать панд или NumPy, потому что моя система не поддерживает его. Большое спасибо за вашу помощь.

+3

Непонятно, для чего вы хотите группировать. Вы хотите группировать свои записи по годам? день? Год и день? что-то другое? – mgilson

+1

Попробуйте предоставить короткий кусок пригодных для использования данных. Код выше недействителен для кода Python и не очень помогает, когда кто-то пытается экспериментировать с вашим вопросом. –

+0

Ваши данные отсортированы по '(году, дню)' уже? –

ответ

3
import itertools 
import operator 

key = operator.itemgetter(0,1) 
my_list.sort(key=key) 
for (year, day), records in itertools.groupby(my_list, key): 
    print("Records on", year, day, ":") 
    for record in records: print(record) 

itertools.groupby не работает, как в SQL GROUPBY. Он группируется в порядке. Это означает, что если у вас есть список элементов, которые не отсортированы, вы можете получить несколько групп на одном и том же ключе. Итак, допустим, вы хотите сгруппировать список целых чисел в зависимости от их соотношения (даже против нечетного), то вы можете сделать это:

L = [1,2,3,4,5,7,8] # notice that there's no 6 in the list 
itertools.groupby(L, lambda i:i%2) 

Теперь, если вы пришли из мира SQL, вы можете подумать, что это дает вам две группы - одну для четных чисел и одну для нечетных чисел. Хотя это имеет смысл, дело не в Python. Он рассматривает каждый элемент по очереди и проверяет, принадлежит ли он той же группе, что и предыдущий элемент. Если это так, оба элемента добавляются в группу; иначе каждый элемент получает свою собственную группу.

Так с приведенным выше списком, мы получаем:

key: 1 
elements: [1] 

key: 0 
elements[2] 

key: 1 
elements: [3] 

key: 0 
elements[4] 

key: 1 
elements: [5,7] # see what happened here? 

Так что, если вы хотите, чтобы сделать группировку, как в SQL, то вы хотите, чтобы отсортировать список, прежде чем руки, с помощью ключа (критерии), с которым вы хотите группы:

L = [1,2,3,4,5,7,8] # notice that there's no 6 in the list 
L.sort(key=lambda i:i%2) # now L looks like this: [2,4,1,3,5,7] - the odds and the evens stick together 
itertools.groupby(L, lambda i:%2) # this gives two groups containing all the elements that belong to each group 
+1

Не могли бы вы добавить какой-нибудь контекст? – ppperry

+0

@ppperry: проверьте это – inspectorG4dget

1

Я попытался сделать короткий и лаконичный ответ, но я не suceed, но мне удалось получить много питона встроенных модулей, участвующих:

import itertools 
import operator 
import functools 

Я буду использовать functools.reduce делать суммы, но она нуждается в пользовательской функции:

def sum_sum_sum_counter(res, array): 
    # Unpack the values of the array 
    year, day, val1, val2, val3 = array 
    res[0] += val1 
    res[1] += val2 
    res[2] += val3 
    res[3] += 1 # counter 
    return res 

Эта функция имеет счетчик, потому что вы хотите, чтобы вычислить среднее это более интуитивным, чем бег в виду реализацию.

Теперь самое интересное: я группа по первым двум элементам (при условии, они сортируются в противном случае нужно было бы что-то вроде lst = sorted(lst, key=operator.itemgetter(0,1)) до:.

result = [] 
for i, values in itertools.groupby(lst, operator.itemgetter(0,1)): 
    # Now let's use the reduce function with a start list containing zeros 
    calc = functools.reduce(sum_sum_sum_counter, values, [0, 0, 0, 0]) 
    # Append year, day and the results. 
    result.append([i[0], i[1], calc[0], calc[1], calc[2]/calc[3]]) 

calc[2]/calc[3] является средним Value3 Помните последний элемент в функции reduce был счетчиком и сумма делится на подсчетах средней

Давая мне результат:!.

[[2014, 1, 13, 27, 17.0], 
[2014, 2, 47, 44, 5.5], 
[2013, 1, 34, 54, 3.0], 
[2013, 2, 23, 33, 2.0]] 

, используя только те значения, которые вы указали.

Смежные вопросы