本文介绍如何使用 pandas 对分组数据批量添加新行,每组依据指定次数(n_times)和日期间隔(interval_days)生成递增的日期序列,并保持原始字段不变。
本文介绍如何使用 pandas 对分组数据批量添加新行,每组依据指定次数(n_times)和日期间隔(interval_days)生成递增的日期序列,并保持原始字段不变。
在实际数据分析中,常需将聚合后的分组记录“展开”为多行时间序列——例如为每个用户生成未来若干天的预测占位、为设备生成周期性维护计划等。核心挑战在于:每组的扩展逻辑不同(如不同 ID 对应不同的重复次数与日期步长),不能简单用 pd.concat 或 repeat() 实现。
以下是一个完整、可复用的解决方案:
✅ 步骤解析
- 定义日期生成函数:封装 pd.date_range,支持自定义起始年份(避免默认 1970 年问题)、灵活的间隔频率;
- 按行应用生成逻辑:使用 df.apply(..., axis=1) 为每组构造一个 DatetimeIndex 列表;
- 展开列表列:借助 explode() 将每个列表展开为多行;
- 格式化输出日期:统一转为 MM-dd 字符串格式。
? 完整代码示例
import pandas as pd
# 原始数据(注意:date 列为字符串格式 'MM-dd')
df = pd.DataFrame({
'Id': [1, 2, 3, 4],
'n_times': [3, 1, 2, 4],
'interval_days': [4, 4, 5, 3],
'date (MM-dd)': ['03-01', '03-02', '03-05', '03-07']
})
def generate_date_range(n_times: int, interval_days: int, start_date: str, year: str = '2024'):
"""生成指定起始日、间隔与长度的日期序列"""
return pd.date_range(
start=f'{year}-{start_date}',
periods=n_times,
freq=f'{interval_days}D'
)
# 设置 Id 为索引便于后续操作(也可不设,改用 reset_index() 衔接)
result = df.set_index('Id')
result['date (MM-dd)'] = result.apply(
lambda x: generate_date_range(x['n_times'], x['interval_days'], x['date (MM-dd)']),
axis=1
)
result = result.explode('date (MM-dd)')
result['date (MM-dd)'] = result['date (MM-dd)'].dt.strftime('%m-%d')
# 恢复 Id 为普通列(可选)
result = result.reset_index()
print(result)⚠️ 注意事项
- 年份必须显式指定:原始 date (MM-dd) 不含年份,pd.date_range 需补全年份(如 '2024-03-01'),否则可能因默认纪元导致异常;
- explode() 要求列元素为 list/tuple/series:确保 generate_date_range 返回的是 DatetimeIndex(它兼容 explode);
- 性能提示:对大数据集,避免 apply(..., axis=1) —— 可改用向量化预处理(如先构造年份列再 pd.to_datetime)提升效率;
- 空值安全:若原始 date (MM-dd) 含缺失值,需在 apply 中加 if pd.isna(...) 判断。
✅ 输出效果
结果严格匹配预期:每组 Id 出现 n_times 次,date (MM-dd) 按 interval_days 等距递增,其余字段(n_times, interval_days)完整保留。
该方法兼具可读性与扩展性,适用于日历填充、模拟采样、报表补零等多种场景。


















