#python #list #dictionary
#питон #Список #словарь
Вопрос:
У меня есть следующий список диктантов. Я хотел бы сгруппировать и агрегировать по годам и месяцам и суммировать значения. Проблема заключалась в том, что в моем текущем выводе я мог вывести только start_date, и я хотел бы каким-то образом показать дату окончания, которая будет последней датой начала элемента dict в списке за этот месяц и год. Это то, что я пробовал до сих пор.
from itertools import groupby u = [ { "start_date": "2018-12-01", "val": 5436, }, { "start_date": "2018-12-02", "val": 5376, }, { "start_date": "2018-12-03", "val": 5608, }, { "start_date": "2018-12-04", "val": 5671, }, { "start_date": "2018-12-05", "val": 5800, }, { "start_date": "2018-12-06", "val": 5834, }, { "start_date": "2018-12-07", "val": 5800, }, { "start_date": "2018-12-08", "val": 5658, }, { "start_date": "2018-12-09", "val": 5709, "year_month": "2018-12" }, { "start_date": "2018-12-10", "val": 5673, }, { "start_date": "2018-12-11", "val": 5661, }, { "start_date": "2018-12-12", "val": 5889, }, { "start_date": "2018-12-13", "val": 6197, }, { "start_date": "2018-12-14", "val": 6163, }, { "start_date": "2018-12-15", "val": 6376, }, { "start_date": "2018-12-16", "val": 5762, }, { "start_date": "2018-12-17", "val": 5733, }, { "start_date": "2018-12-18", "val": 6207, }, { "start_date": "2018-12-19", "val": 5600, }, { "start_date": "2018-12-20", "val": 5815, }, { "start_date": "2018-12-21", "val": 5533, }, { "start_date": "2018-12-22", "val": 5346, }, { "start_date": "2018-12-23", "val": 5478, }, { "start_date": "2018-12-24", "val": 5276, }, { "start_date": "2018-12-25", "val": 5205, }, { "start_date": "2018-12-26", "val": 5246, }, { "start_date": "2018-12-27", "val": 5234, }, { "start_date": "2018-12-28", "val": 5233, }, { "start_date": "2018-12-29", "val": 5102, }, { "start_date": "2018-12-30", "val": 5240, }, { "start_date": "2018-12-31", "val": 5248, }, { "start_date": "2021-12-04", "val": 808, } ] def yss(): result = [] for k, v in groupby(u, key=lambda x: x['start_date'][:7]): result.append({'date': k '-01', 'value': sum(int(d['val']) for d in v)}) return result yss()
Выход есть —
[{'date': '2018-12-01', 'value': 174109}, {'date': '2021-12-01', 'value': 808}]
Я хочу, чтобы результат был
[{'start_date':'2018-12-01', 'end_date': '2018-12-31','value':174109}, {'start_date':'2021-12-04','end_date':'2021-12-04','value':808}]
Ответ №1:
Когда вы groupby
сохраните сгруппированные данные в список кортежей и используете его для построения результата:
result = [] for k, v in groupby(u, key=lambda x: x['start_date'][:7]): date_values = [(d["start_date"], d["val"]) for d in v] result.append({'start_date': min(d[0] for d in date_values), 'end_date': max(d[0] for d in date_values), 'value': sum(d[1] for d in date_values)}) gt;gt;gt; result [{'start_date': '2018-12-01', 'end_date': '2018-12-31', 'value': 174109}, {'start_date': '2021-12-04', 'end_date': '2021-12-04', 'value': 808}]
Альтернативно, с pandas
использованием Именованной агрегации:
import pandas as pd df = pd.DataFrame(u) result = (df.groupby(pd.to_datetime(df['start_date']).dt.to_period('M')) .agg(start_date=("start_date", "min"), end_date=("start_date","max"), value=("val","sum")) .to_dict(orient='records') ) gt;gt;gt; result [{'start_date': '2018-12-01', 'end_date': '2018-12-31', 'value': 174109}, {'start_date': '2021-12-04', 'end_date': '2021-12-04', 'value': 808}]
Ответ №2:
Вы можете использовать pandas
:
import pandas as pd df = pd.DataFrame(u)[['start_date','val']] df['start_date'] = pd.to_datetime(df['start_date']) df['year_month'] = df['start_date'].dt.to_period('M') out = (df.groupby('year_month').agg({'start_date':['first','last'],'val':'sum'}) .droplevel(0, axis=1).rename({'first':'start_date', 'last':'end_date', 'sum':'value'}, axis=1) .reset_index(drop=True)) out[['start_date','end_date']] = out[['start_date','end_date']].apply(lambda x: x.dt.strftime('%y-%m-%d'), axis=1) out = list(out.T.to_dict().values())
Выход:
[{'start_date': '18-12-01', 'end_date': '18-12-31', 'value': 174109}, {'start_date': '21-12-04', 'end_date': '21-12-04', 'value': 808}]
Ответ №3:
Это должно сработать:
import pandas as pd df = pd.DataFrame(u) # Convert start date df["start_date"] = pd.to_datetime(df['start_date']) df["year"] = df["start_date"].apply(lambda x: x.year) df["month"] = df["start_date"].apply(lambda x: x.month) result = [] for (year, month), group in df.groupby(["year", "month"]): start_date = group["start_date"].min() end_date = group["start_date"].max() value = group["val"].sum() result.append({"start_date": start_date, "end_date": end_date, "value": value})
Ответ №4:
Здесь это как единое вложенное понимание, просто для развлечения:
gt;gt;gt; [( ... lambda p=[(d["start_date"], d["val"]) for d in g]: { ... "start_date": p[0][0], ... "end_date": p[-1][0], ... "value": sum(v for _, v in p) ... } ... )() for _, g in groupby( ... sorted(u, key=lambda d: d["start_date"]), ... key=lambda d: d["start_date"][:7] ... )] [{'start_date': '2018-12-01', 'end_date': '2018-12-31', 'value': 174109}, {'start_date': '2021-12-04', 'end_date': '2021-12-04', 'value': 808}]