Pandas DataFrame按组每N行聚合:解决分组错位的计算问题
按组对每N行数据执行聚合计算的解决方案
问题说明
本需求与“对pandas Series每N行求和”的场景不同,核心是按指定分组字段(如示例中的ID),在每个组内对每N行数据执行聚合计算。但使用全局索引分组时,会因各组行号未对齐导致聚合结果错误,且日期可能完全不规则。
示例数据与预处理代码
import pandas as pd df = pd.DataFrame({'ID':['AA','AA','AA','BB','BB','BB'], 'DATE':['2021-01-01','2021-01-03','2021-01-08','2021-03-04','2021-03-06','2021-03-08'], 'VALUE':[10,15,25,40,60,90]}) df['DATE'] = pd.to_datetime(df['DATE']) df = df.sort_values(by=['ID','DATE'])
预处理后的DataFrame:
| ID | DATE | VALUE |
|---|---|---|
| AA | 2021-01-01 | 10 |
| AA | 2021-01-03 | 15 |
| AA | 2021-01-08 | 25 |
| BB | 2021-03-04 | 40 |
| BB | 2021-03-06 | 60 |
| BB | 2021-03-08 | 90 |
错误实现及结果
使用全局索引分组的代码:
# 错误的计算方式 df.groupby(['ID', df.index//2]).agg({'VALUE':'mean', 'DATE':'median'}).reset_index()
得到的错误结果:
| ID | VALUE | DATE |
|---|---|---|
| AA | 12.5 | 2021-01-02 |
| AA | 25 | 2021-01-08 |
| BB | 40 | 2021-03-04 |
| BB | 75 | 2021-03-07 |
预期结果
| ID | VALUE | DATE |
|---|---|---|
| AA | 12.5 | 2021-01-02 |
| AA | 25 | 2021-01-08 |
| BB | 50 | 2021-03-05 |
| BB | 90 | 2021-03-08 |
解决方案
问题根源是全局索引df.index//2是对整个DataFrame的索引分组,而非每个ID组内的行号。正确做法是在每个组内生成独立的行号,再基于组内行号进行分组聚合。
方法1:高效生成组内行号(推荐大数据集)
N = 2 # 定义每N行聚合一次 # 生成每个ID组内的连续行号 df['group_row_num'] = df.groupby('ID').cumcount() # 按ID和组内行号//N分组执行聚合 result = df.groupby(['ID', df['group_row_num']//N]).agg( {'VALUE': 'mean', 'DATE': 'median'} ).reset_index(drop=True, level=1).reset_index() print(result)
方法2:组内独立处理(逻辑直观)
N = 2 def aggregate_n_rows(group): # 对单个组按每N行分组聚合 return group.groupby(group.index//N).agg({'VALUE':'mean', 'DATE':'median'}) result = df.groupby('ID').apply(aggregate_n_rows).reset_index(level=1, drop=True).reset_index()
两种方法均可得到预期结果,其中方法1效率更高;方法2逻辑更直观,适合调试。此外,pandas对datetime类型的median计算天然支持,即使日期完全不规则也能正确输出中间值。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

