如何用Pandas计算周度数据X列的同比变化(适配52/53周)
周频数据同比变化率计算(适配52/53周年份)
要解决周频数据的同比计算问题,核心是精准匹配「今年同一ISO周次」与「去年同一ISO周次」的数据——普通周数计算可能存在跨年错位,而ISO周是国际标准,能正确区分每年52/53周的情况。以下是具体实现步骤:
关键前提
假设你的数据框df包含:
- 日期列
date(已转为datetime类型) - 需要计算同比的数值列
x1、x2、x3
步骤1:提取ISO年份与周次
ISO周规则:每年最多53周,周一是一周起始,部分跨年日期(如12月31日)可能归属下一年的第1周,这能保证同周次的业务一致性。
import pandas as pd # 提取ISO年份和周数 df['iso_year'] = df['date'].dt.isocalendar().year df['iso_week'] = df['date'].dt.isocalendar().week
步骤2:匹配去年同周数据(两种实现方式)
方式一:Merge自连接(直观易验证)
复制一份去年的数据,将年份加1后与原数据按「ISO年份+ISO周次」合并,确保每一行都匹配到去年同周的数值:
# 复制并处理去年数据 df_prev = df.copy() df_prev['iso_year'] += 1 # 去年年份+1,对应今年的年份 df_prev = df_prev[['iso_year', 'iso_week', 'x1', 'x2', 'x3']].rename( columns={'x1': 'x1_prev', 'x2': 'x2_prev', 'x3': 'x3_prev'} ) # 合并原数据与去年同周数据 df_merged = pd.merge(df, df_prev, on=['iso_year', 'iso_week'], how='left')
方式二:Groupby分组计算(简洁高效)
按ISO周次分组,在每个组内按年份排序后计算同比变化率:
# 先按周次、年份排序 df = df.sort_values(['iso_week', 'iso_year']) # 每个周次组内计算同比(periods=1表示取上一年的数据) for col in ['x1', 'x2', 'x3']: df[f'{col}_yoy'] = df.groupby('iso_week')[col].pct_change(periods=1) * 100
步骤3:计算同比变化率
同比公式为:(今年值 - 去年值) / 去年值 * 100(百分比形式),如果用Merge方式,代码如下:
# 批量计算所有X列的同比 for col in ['x1', 'x2', 'x3']: df_merged[f'{col}_yoy'] = (df_merged[col] - df_merged[f'{col}_prev']) / df_merged[f'{col}_prev'] * 100 # 保留核心列(可选) result = df_merged[['date', 'x1', 'x2', 'x3', 'x1_yoy', 'x2_yoy', 'x3_yoy']]
处理53周的特殊情况
如果某一年存在第53周,但去年没有对应周次,匹配后去年的数值会是NaN,同比结果也会是NaN。你可以根据业务需求处理:
- 删除缺失行:
result = result.dropna(subset=['x1_yoy', 'x2_yoy', 'x3_yoy']) - 用前一周同比填充:
result[['x1_yoy', 'x2_yoy', 'x3_yoy']] = result[['x1_yoy', 'x2_yoy', 'x3_yoy']].fillna(method='ffill') - 忽略该周数据:直接保留
NaN,后续分析时排除
内容的提问来源于stack exchange,提问作者ah bon
相关产品推荐
相关产品推荐

