pandas - 如何对 GroupBy 和连续日期条件下的值求和?
问题描述
给定表:
ID | 线 | 地点 | 日期 | 单位 | 全部的 |
---|---|---|---|---|---|
1 | X | AAA | 2017 年 5 月 2 日 | 12 | 30 |
2 | X | AAA | 2017 年 5 月 3 日 | 10 | 22 |
3 | X | AAA | 2017 年 5 月 4 日 | 22 | 40 |
4 | Z | AAA | 2017 年 5 月 20 日 | 15 | 44 |
5 | Z | AAA | 2017 年 5 月 21 日 | 8 | 30 |
6 | Z | BBB | 2017 年 5 月 22 日 | 10 | 32 |
7 | Z | BBB | 2017 年 5 月 23 日 | 25 | 52 |
8 | ķ | CCC | 2017 年 6 月 2 日 | 6 | 22 |
9 | ķ | CCC | 2017 年 6 月 3 日 | 4 | 33 |
10 | ķ | CCC | 2017 年 8 月 12 日 | 11 | 44 |
11 | ķ | CCC | 2017 年 8 月 13 日 | 19 | 40 |
12 | ķ | CCC | 2017 年 8 月 14 日 | 30 | 40 |
对于每一行,如果 ID,LINE ,SITE 等于前一行(天)需要计算如下(最后一天)和(最后 3 天):请注意,需要确保日期在 ID,LINE 的“groupby”下是连续的,网站栏目
ID | 线 | 地点 | 日期 | 单位 | 全部的 | 最后一天 | 过去 3 天 |
---|---|---|---|---|---|---|---|
1 | X | AAA | 2017 年 5 月 2 日 | 12 | 30 | 0 | 0 |
2 | X | AAA | 2017 年 5 月 3 日 | 10 | 22 | 12/30 | 12/30 |
3 | X | AAA | 2017 年 5 月 4 日 | 22 | 40 | 10/22 | (10+12)/(30+22) |
4 | Z | AAA | 2017 年 5 月 20 日 | 15 | 44 | 0 | 0 |
5 | Z | AAA | 2017 年 5 月 21 日 | 8 | 30 | 15/44 | 15/44 |
6 | Z | BBB | 2017 年 5 月 22 日 | 10 | 32 | 0 | 0 |
7 | Z | BBB | 2017 年 5 月 23 日 | 25 | 52 | 10/32 | 10/32 |
8 | ķ | CCC | 2017 年 6 月 2 日 | 6 | 22 | 0 | 0 |
9 | ķ | CCC | 2017 年 6 月 3 日 | 4 | 33 | 6/22 | 6/22 |
10 | ķ | CCC | 2017 年 8 月 12 日 | 11 | 44 | 4/33 | 0 |
11 | ķ | CCC | 2017 年 8 月 13 日 | 19 | 40 | 11/44 | (11/44) |
12 | ķ | CCC | 2017 年 8 月 14 日 | 30 | 40 | 19/40 | (11+19/44+40) |
解决方案
在这种情况下,我通常使用 groupby 进行 for 循环:
import pandas as pd
import numpy as np
#copied your table
table = pd.read_csv('/home/fm/Desktop/stackover.csv')
table.set_index('ID', inplace = True)
table[['Last day','Last 3 days']] = np.nan
for i,r in table.groupby(['LINE' ,'SITE']):
#First subset non sequential dates
limits_interval = pd.to_datetime(r['DATE']).diff() != '1 days'
#First element is a false positive, as its impossible to calculate past days from first day
limits_interval.iloc[0]=False
ids_subset = r.index[limits_interval].to_list()
ids_subset.append(r.index[-1]+1) #to consider all values
id_start = 0
for id_end in ids_subset:
r_sub = r.loc[id_start:id_end-1, :].copy()
id_start = id_end
#move all values one day off, if the database is as in your example (1 line per day) wont have problems
r_shifted = r_sub.shift(1)
r_sub['Last day']=r_shifted['UNITS']/r_shifted['TOTAL']
aux_units_cumsum = r_shifted['UNITS'].cumsum()
aux_total_cumsum = r_shifted['TOTAL'].cumsum()
r_sub['Last 3 days'] = aux_units_cumsum/aux_total_cumsum
r_sub.fillna(0, inplace = True)
table.loc[r_sub.index,:]=r_sub.copy()
您可以创建一个函数并在 groupby 中应用,它会更干净:Apply function to pandas groupby。它会更优雅。希望我能帮助你,祝你好运
推荐阅读
- javascript - 仅在元素上触发“点击”事件而不考虑其填充
- django - URLpattern 匹配没有按预期工作
- angular - 在 Kendo UI 中为 Angular 创建动态网格
- angular - 等待来自有角度的服务器的响应
- javascript - 无法在 ReactJS 上使用 defaultValue 编辑表单
- mysql - SQL Server 数据库部署到要在 Web 应用程序中使用的服务器:
- java - java时间戳用间隔计算重叠持续时间
- postgresql - 如何避免使用 postgres_fdw 在数据库之间触发无限循环?
- javascript - 用户单击按钮后,将列表动态添加到现有列表集
- reactjs - 反应打字稿构造函数状态与属性