如何在动态日期区间内按class_1&class_2分组计算DataFrame均值
动态日期区间内分组计算均值的解决方案
需求说明
对DataFrame按class_1和class_2分组,计算动态日期区间内的均值:
- 结束日期:当前行
date字段的前一天(对应现有列end) - 起始日期:结束日期的前一年(对应现有列
1yr) - 计算目标:同分组下
placement等于1的数值在该区间内的占比均值
样本DataFrame
| date | class_1 | class_2 | placement | end | 1yr |
|---|---|---|---|---|---|
| 12/05/21 | math | math | 1 | 12/04/21 | 12/04/20 |
| 12/04/21 | math | eng | 3 | 12/03/21 | 12/03/20 |
| 12/03/21 | eng | math | 4 | 12/02/21 | 12/02/20 |
| 12/02/21 | math | math | 4 | 12/01/21 | 12/01/20 |
| 12/01/21 | math | math | 1 | 11/30/21 | 11/30/20 |
| 11/30/21 | math | math | 2 | 11/29/21 | 11/29/20 |
期望输出
| date | class_1 | class_2 | placement | end | 1yr | Mean |
|---|---|---|---|---|---|---|
| 12/05/21 | math | math | 1 | 12/04/21 | 12/04/20 | 0.3333 |
| 12/04/21 | math | eng | 3 | 12/03/21 | 12/03/20 | 0 |
| 12/03/21 | eng | math | 4 | 12/02/21 | 12/02/20 | 0 |
| 12/02/21 | math | math | 4 | 12/01/21 | 12/01/20 | 0.5 |
| 12/01/21 | math | math | 1 | 11/30/21 | 11/30/20 | 0 |
| 11/30/21 | math | math | 2 | 11/29/21 | 11/29/20 | 0 |
解决方案
步骤1:转换日期列格式
首先将所有日期列转为datetime类型,确保能进行日期比较:
import pandas as pd # 创建样本数据 df = pd.DataFrame({ 'date': ['12/05/21', '12/04/21', '12/03/21', '12/02/21', '12/01/21', '11/30/21'], 'class_1': ['math', 'math', 'eng', 'math', 'math', 'math'], 'class_2': ['math', 'eng', 'math', 'math', 'math', 'math'], 'placement': [1, 3, 4, 4, 1, 2], 'end': ['12/04/21', '12/03/21', '12/02/21', '12/01/21', '11/30/21', '11/29/21'], '1yr': ['12/04/20', '12/03/20', '12/02/20', '12/01/20', '11/30/20', '11/29/20'] }) # 转换日期格式 for col in ['date', 'end', '1yr']: df[col] = pd.to_datetime(df[col], format='%m/%d/%y')
步骤2:分组计算动态区间均值
通过groupby结合apply,对每个分组内的行逐一筛选符合日期区间的记录,计算placement=1的占比:
def calculate_dynamic_mean(group): # 对当前分组的每一行,计算对应区间内的均值 group['Mean'] = group.apply( lambda row: group[ (group['date'] >= row['1yr']) & (group['date'] <= row['end']) ]['placement'].eq(1).mean(), axis=1 ) return group # 应用到所有分组 result_df = df.groupby(['class_1', 'class_2'], group_keys=False).apply(calculate_dynamic_mean) # 格式化均值保留4位小数 result_df['Mean'] = result_df['Mean'].round(4)
步骤3:查看结果
运行后result_df即可得到与期望一致的输出:
print(result_df)
性能优化提示
如果数据量较大,逐行apply效率偏低,可以考虑使用向量化操作或滚动窗口优化;中小规模数据下,上述方法足够直观易维护。
内容的提问来源于stack exchange,提问作者ManOnTheMoon
相关产品推荐
相关产品推荐

