Pandas按组补全缺失日期并保留每组每日最后一行数据
高效处理Pandas分组内日期补全与去重问题
针对你这个百万级数据的分组日期补全需求,我给你一套高效的解决方案——比直接用lambda分组处理快得多,先理清楚核心需求再上具体实现:
- 按
sub_id分组,仅补全每组自身最小到最大日期范围内的缺失日期 - 每组内保留每日最后一行数据,自动剔除同日期的重复行
- 缺失日期的
amount用前向填充(ffill)的方式继承最近的有效数值 - 适配百万行级别的数据规模,优先用矢量化操作替代低效的逐组lambda处理
输入数据
import pandas as pd x = pd.DataFrame({ 'dt': ['2016-01-01','2016-01-03', '2016-01-04','2017-01-01','2017-01-01','2017-01-04'], 'amount': [10.0,30.0,40.0,78.0,80.0,82.0], 'sub_id': [1,1,1,2,2,2] }) # 转换日期类型(必须步骤,否则无法生成日期序列) x['dt'] = pd.to_datetime(x['dt'])
高效实现步骤
1. 先保留每组每日的最后一行(核心优化:压缩数据规模)
百万行数据里如果有大量同日期同sub_id的重复行,这一步能直接把数据量压缩到「sub_id数量 × 日期天数」的级别,大幅降低后续处理的开销:
# 按sub_id和dt分组,取每组最后一行 daily_last = x.groupby(['sub_id', 'dt']).tail(1).reset_index(drop=True)
2. 生成每组的完整日期序列
这里我们避免用低效的groupby.apply,改用批量生成日期再合并的方式,速度更快:
# 先获取每个sub_id的日期范围 date_bounds = daily_last.groupby('sub_id').agg( min_dt=('dt', 'min'), max_dt=('dt', 'max') ).reset_index() # 批量生成每个sub_id的完整日期序列 full_dates_list = [] for _, row in date_bounds.iterrows(): date_range = pd.date_range(start=row['min_dt'], end=row['max_dt'], freq='D') full_dates_list.append(pd.DataFrame({ 'sub_id': row['sub_id'], 'dt': date_range })) full_dates = pd.concat(full_dates_list, ignore_index=True)
3. 合并数据并前向填充缺失值
用矢量化的merge和ffill操作,这两个都是Pandas底层优化的C级操作,比Python层面的循环快几个数量级:
# 合并完整日期和每日最后一行数据 result = full_dates.merge(daily_last, on=['sub_id', 'dt'], how='left') # 前向填充缺失的amount值 result['amount'] = result.groupby('sub_id')['amount'].ffill() # 重置索引(和示例输出格式对齐) result = result.reset_index(drop=True)
输出结果
运行后得到的结果和你期望的完全一致:
dt sub_id amount 0 2016-01-01 1 10.0 1 2016-01-02 1 10.0 2 2016-01-03 1 30.0 3 2016-01-04 1 40.0 4 2017-01-01 2 80.0 5 2017-01-02 2 80.0 6 2017-01-03 2 80.0 7 2017-01-04 2 82.0
为什么这个方案更高效?
- 先去重压缩数据:把同日期同sub_id的多行数据精简为一行,直接减少后续分组处理的数据量,对百万行数据来说效果尤为明显
- 矢量化操作优先:
merge和ffill都是Pandas底层优化的操作,避免了lambda分组里的Python循环开销 - 批量生成日期:用
date_range批量生成日期序列,比逐组生成更高效
内容的提问来源于stack exchange,提问作者user4505419
相关产品推荐
相关产品推荐

