本文介绍如何根据每行日期与当前日期之间的完整周数,动态重复dataframe中的行,并为每条重复记录生成对应的iso周数(week)和年份(year),实现精准的时间维度展开。
在数据分析中,常需将单条时间记录“展开”为多个时间切片(如按周、月),尤其适用于周报聚合、滚动预测或时间序列对齐场景。本文解决的核心问题是:对每一行的 DATE,计算其到当前日期(pd.Timestamp(‘now’))之间包含多少个完整自然周(含起始周),然后将该行重复对应次数,并为每次重复分配递增的ISO周编号(含跨年处理)。
关键难点在于:
- 周数计算需基于 ISO 周历(isocalendar()),而非简单天数除以7;
- 重复后每行的 WEEK 应从原始日期所在周开始,逐周递增(如2023-12-24属2023年第51周,则后续为52、1、2…);
- 必须正确处理跨年(如2023-W52 → 2024-W01);
- 避免循环操作,保证向量化性能。
✅ 推荐方案(高效、健壮、一行逻辑清晰):
import pandas as pd
# 示例数据
df = pd.DataFrame({
'ID': ['ID001', 'ID002', 'ID003'],
'DATE': ['24/12/2023', '01/02/2024', '12/02/2024']
})
df['DATE'] = pd.to_datetime(df['DATE'], dayfirst=True)
# 步骤1:计算每个日期到当前日期的完整ISO周数(含起始周)
# 使用 Period 进行周对齐,避免日历偏差
current_week = pd.Timestamp('now').to_period('W')
date_weeks = df['DATE'].dt.to_period('W')
n_weeks = (current_week - date_weeks).apply(lambda p: p.n) # 得到整数周差
# 步骤2:按周数+1重复行(+1 因为包含起始周本身)
# 使用 loc + index.repeat 实现向量化重复
repeated = df.loc[df.index.repeat(n_weeks + 1)].copy().reset_index(drop=True)
# 步骤3:为每组重复行生成递增周序列(从原始日期开始,每周+7天)
# groupby(level=0) 不适用(已重置索引),改用 cumcount() 配合原始分组标识
# 更稳健做法:先恢复分组标识,再计算偏移
group_ids = repeated.index.to_series().groupby(repeated.index // 1).ngroup() # 实际可直接用 cumcount 分组
# 简洁写法(推荐):
offset_days = repeated.groupby(repeated.index // 1).cumcount() * 7
repeated['WEEK_DATE'] = df.loc[repeated.index // 1, 'DATE'].values + pd.to_timedelta(offset_days, unit='D')
# 步骤4:提取 ISO 年份与周数
repeated['YEAR'] = repeated['WEEK_DATE'].dt.isocalendar().year
repeated['WEEK'] = repeated['WEEK_DATE'].dt.isocalendar().week
# 最终结果(保留原始列 + YEAR/WEEK)
result = repeated[['ID', 'DATE', 'YEAR', 'WEEK']].copy()
print(result)
? 输出说明(以运行时刻为2024-02-25左右为例):