Группируйте элементы в список и вычисляйте суммы - PullRequest
1 голос
/ 30 мая 2020

У меня есть список с еженедельными цифрами, и мне нужно получить сгруппированные итоги по месяцам.

Следующий код выполняет свою работу, но должен быть более pythoni c способ сделать это с использованием стандартные библиотеки. Недостатком приведенного ниже кода является то, что список должен быть отсортирован.

#Test data (not sorted)
sum_weekly=[('2020/01/05', 59), ('2020/01/19', 88), ('2020/01/26', 95), ('2020/02/02', 89),
 ('2020/02/09', 113), ('2020/02/16', 90), ('2020/02/23', 68), ('2020/03/01', 74), ('2020/03/08', 85),
  ('2020/04/19', 6), ('2020/04/26', 5), ('2020/05/03', 14),
 ('2020/05/10', 5), ('2020/05/17', 20), ('2020/05/24', 28),('2020/03/15', 56), ('2020/03/29', 5), ('2020/04/12', 2),]

month = sum_weekly[0][0].split('/')[1]
count=0
out=[]
for item in sum_weekly:
    m_sel = item[0].split('/')[1]
    if m_sel!=month:
        out.append((month, count))
        count=item[1]
    else:
        count+=item[1]
    month = m_sel
out.append((month, count))

# monthly sums output as ('01', 242), ('02', 360), ('03', 220), ('04', 13), ('05', 67)
print (out)

Ответы [ 5 ]

3 голосов
/ 30 мая 2020

Вы можете использовать defaultdict для сохранения результата вместо списка. Ключи словаря будут месяцами, и вы можете просто добавить значения с тем же месяцем (ключом).

Возможная реализация:

# Test Data
from collections import defaultdict

sum_weekly = [('2020/01/05', 59), ('2020/01/19', 88), ('2020/01/26', 95), ('2020/02/02', 89),
              ('2020/02/09', 113), ('2020/02/16', 90), ('2020/02/23', 68), ('2020/03/01', 74), ('2020/03/08', 85),
              ('2020/03/15', 56), ('2020/03/29', 5), ('2020/04/12', 2), ('2020/04/19', 6), ('2020/04/26', 5),
              ('2020/05/03', 14),
              ('2020/05/10', 5), ('2020/05/17', 20), ('2020/05/24', 28)]


results = defaultdict(int)
for date, count in sum_weekly: # used unpacking to make it clearer
    month = date.split('/')[1]
    # because we use a defaultdict if the key does not exist it
    # the entry for the key will be created and initialize at zero
    results[month] += count

print(results)
1 голос
/ 30 мая 2020

Вы можете использовать itertools.groupby (это часть стандартной библиотеки) - он делает почти то же, что и вы, (группирует вместе последовательности элементов, для которых функция ключа дает одинаковый результат). Это может выглядеть так:

import itertools

def select_month(item):
    return item[0].split('/')[1]

def get_value(item):
    return item[1]

result = [(month, sum(map(get_value, group))) 
            for month, group in itertools.groupby(sorted(sum_weekly), select_month)]
print(result)
0 голосов
/ 30 мая 2020

Вы можете выполнить sh это с помощью Pandas фрейма данных. Сначала вы выделяете месяц, а затем используете groupby.sum ().

import pandas as pd

sum_weekly=[('2020/01/05', 59), ('2020/01/19', 88), ('2020/01/26', 95), ('2020/02/02', 89), ('2020/02/09', 113), ('2020/02/16', 90), ('2020/02/23', 68), ('2020/03/01', 74), ('2020/03/08', 85), ('2020/04/19', 6), ('2020/04/26', 5), ('2020/05/03', 14), ('2020/05/10', 5), ('2020/05/17', 20), ('2020/05/24', 28),('2020/03/15', 56), ('2020/03/29', 5), ('2020/04/12', 2)]

df= pd.DataFrame(sum_weekly)
df.columns=['Date','Sum']
df['Month'] = df['Date'].str.split('/').str[1]
print(df.groupby('Month').sum())
0 голосов
/ 30 мая 2020

метод с использованием pyspark

from pyspark import SparkContext

sc = SparkContext()

l = sc.parallelize(sum_weekly)

r = l.map(lambda x: (x[0].split("/")[1], x[1])).reduceByKey(lambda p, q: (p + q)).collect()

print(r) #[('04', 13), ('02', 360), ('01', 242), ('03', 220), ('05', 67)]
0 голосов
/ 30 мая 2020

Лаконично, но, может быть, не тот питон c:

import calendar, functools, collections

{calendar.month_name[i]: val for i, val in functools.reduce(lambda a, b: a + b, [collections.Counter({datetime.datetime.strptime(time, '%Y/%m/%d').month: val}) for time, val in sum_weekly]).items()}
...