pandas按ID分组统计每行过去60天内RESULT为1的历史行数高效实现方案
高效解决方案
你完全不需要用双层for循环,用pandas自带的分组+时间滚动窗口就能实现,性能是原生for循环的百倍以上,同时也不会打乱你原有的ID分组和行顺序:
前置准备
首先确保DATE列已经转换为pandas的datetime类型:
import pandas as pd # 转换日期格式,带时区也能正常识别 df['DATE'] = pd.to_datetime(df['DATE']) # 新增临时列保存原始行索引,处理完可以恢复原有行顺序 df['orig_idx'] = df.index
核心计算逻辑
按ID分组后仅在同ID组内做排序和滚动计算,完全不会跨ID干扰:
def calc_cnt(group): # 同ID内按时间升序排列,满足滚动窗口要求 group = group.sort_values('DATE', ascending=True) # 设置日期为索引适配时间滚动窗口 group = group.set_index('DATE') # 60天滚动窗口,closed='left'表示仅统计早于当前行的记录,求和即可得到RESULT=1的数量 group['N_RESULTS_EQUAL_1_PREVIOUS_60_DAYS'] = group['RESULT'].rolling('60D', closed='left').sum().fillna(0).astype(int) # 恢复日期为普通列 group = group.reset_index() return group # 分组计算后按原始索引排序,恢复输入时的行顺序 df = df.groupby('ID', group_keys=False).apply(calc_cnt).sort_values('orig_idx').reset_index(drop=True) # 删除临时索引列 df = df.drop('orig_idx', axis=1)
方案说明
- 所有计算都在同ID分组内完成,不会出现跨ID统计的问题,也不需要全局排序打乱原有排列
- 滚动窗口是pandas底层C实现的矢量化操作,单表百万行级别的数据也能在秒级完成计算
- 自动适配带时区的日期格式,只要所有DATE列的时区一致即可正常计算
内容的提问来源于stack exchange,提问作者Matheus Schaly
相关产品推荐
相关产品推荐

