
本文介绍如何根据每行日期与当前日期之间的完整周数,动态重复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左右为例):
- ID001(2023-12-24)→ 跨年覆盖 W51(2023)、W52(2023)、W01–W07(2024),共9行;
- ID002(2024-02-01)→ 从 W05 开始至 W07,共3行;
- ID003(2024-02-12)→ 仅 W07(因2月12日属第6周?实际需看ISO规则;示例中显示为W07,表明当前为2月25日前后)。
⚠️ 注意事项:
- pd.Timestamp('now') 在生产环境中建议替换为固定基准日期(如 pd.Timestamp('2024-02-25')),确保结果可复现;
- isocalendar() 返回的 week 是 ISO 8601 标准(周一为每周第一天,W01为包含当年第一个周四的周),与 strftime('%U') 或 %W 行为不同;
- 若需严格按“日历周”(周日为始)而非ISO周,请改用 .dt.strftime('%Y-%U') 并手动解析;
- 大数据量时,避免 for 循环和 loc[i] 赋值——原问题中循环覆盖索引导致逻辑错乱,正是性能与正确性双重风险点。
? 总结:使用 Period('W') 对齐周粒度 + index.repeat() 向量化重复 + cumcount() 构建偏移序列,是处理此类“时间维度展开”任务的最优范式。它兼顾准确性(ISO周历)、简洁性(无显式循环)与扩展性(易于适配月/季度等粒度)。










