Агрегирование данных по start_date для получения значения?

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