为各ID补全不含周末的缺失报告日期并填充指定值
补全账户报告日期缺口的Pandas解决方案
我来帮你搞定这个日期补全的需求,用Pandas可以高效实现你要的所有操作,下面是完整的步骤和代码:
核心思路
我们需要为每个ID生成**2014-07-01到2018-03-13之间的所有工作日(不含周末)**的完整序列,然后将原始数据合并进去,对缺口行按规则填充值,最后统一处理所有ID。
完整代码实现
import pandas as pd # 1. 预处理原始数据:转换日期格式 df['report_date'] = pd.to_datetime(df['report_date'], format='%m/%d/%Y') # 确保日期格式正确 # 2. 生成指定范围内的所有工作日(自动排除周末) full_work_days = pd.date_range(start='2014-07-01', end='2018-03-13', freq='B') # 3. 按ID分组处理每个账户 processed_groups = [] for account_id, group_data in df.groupby('ID'): # 为当前账户创建包含所有工作日的空框架 full_account_dates = pd.DataFrame({ 'ID': account_id, 'report_date': full_work_days }) # 合并原始数据,左连接保留所有日期,缺失的行就是需要补的缺口 merged_data = pd.merge(full_account_dates, group_data, on=['ID', 'report_date'], how='left') # 4. 按规则填充值 # - 缺口行的balance填充为0 merged_data['balance'] = merged_data['balance'].fillna(0) # - 其他变量用缺口前的最后有效值填充(前向填充) merged_data[['other_v1', 'other_v2']] = merged_data[['other_v1', 'other_v2']].ffill() # 5. 可选:添加DAY/GAP标记列(和你示例中的格式一致) # 先计算累计缺口数 merged_data['gap_count'] = merged_data['balance'].eq(0).cumsum() # 生成标签 merged_data['day_tag'] = merged_data.apply( lambda row: f"DAY {row.name + 1}" if row['balance'] != 0 else f"GAP {row['gap_count']} (DAY {row.name + 1})", axis=1 ) # 移除临时的gap_count列 merged_data = merged_data.drop('gap_count', axis=1) processed_groups.append(merged_data) # 6. 合并所有账户的处理结果 final_df = pd.concat(processed_groups, ignore_index=True)
代码解释
- 日期预处理:先把原始的
report_date转换成Pandas的datetime格式,避免后续日期匹配出错。 - 完整工作日序列:用
pd.date_range的freq='B'参数直接生成所有非周末日期,正好对应你说的970个日期。 - 分组处理:每个ID单独处理,确保补全的日期是每个账户专属的完整序列。
- 填充规则:
balance列用fillna(0)直接把缺口行的空值替换为0;other_v1、other_v2用ffill()(前向填充),自动继承上一个非缺口行的有效值,完美符合“缺口前的最后有效值”要求。
- 可选标记列:生成和你示例一致的DAY/GAP标签,方便区分原始行和新增的缺口行。
注意事项
如果某个账户的第一个报告日期晚于2014-07-01,那么起始日期到该账户第一个报告日之间的缺口行,other_v1和other_v2会是NaN。如果需要给这些行设置默认值,可以在ffill()之后再加一步fillna(默认值),比如merged_data[['other_v1', 'other_v2']] = merged_data[['other_v1', 'other_v2']].ffill().fillna(0)。
内容的提问来源于stack exchange,提问作者NightDog
相关产品推荐
相关产品推荐

