如何计算周度同比数据?适配含53周年份的对齐方案
周度同比计算适配53周年份的解决方案
需要计算周度经济指数(WEI)的同比数据,但部分年份存在53周(如2011、2016、2022年),要求这些年份的第53周与前一年的第52周做同比对比,解决周数对齐问题。现有的calculate_week_on_week函数用shift(52)实现,无法适配该场景,以下是可行的适配方案。
现有代码与数据情况
数据读取与日期处理代码
import pandas as pd df = pd.read_excel('../raw_data/WEI.xls', skiprows=10) df['observation_date'] = pd.to_datetime(df['observation_date']) def add_date_parts(df, date_column): df['year_week_ori'] = df[date_column].dt.strftime('%Y-%V') df['year'] = df[date_column].dt.isocalendar().year df['week'] = df[date_column].dt.isocalendar().week df.loc[df['week'] > 52, 'week'] = 52 df['year_week_modified'] = df['year'].astype(str) + '-' + df['week'].astype(str).str.zfill(2) df['year'] = df[date_column].dt.year df['month'] = df[date_column].dt.month return df df = add_date_parts(df, 'observation_date')
处理后的数据样例
observation_date WEI year_week_ori year week year_week_modified month 0 2008-01-05 1.80 2008-01 2008 1 2008-01 1 1 2008-01-12 1.78 2008-02 2008 2 2008-02 1 2 2008-01-19 1.75 2008-03 2008 3 2008-03 1 3 2008-01-26 1.28 2008-04 2008 4 2008-04 1 4 2008-02-02 0.99 2008-05 2008 5 2008-05 2 .. ... ... ... ... ... ... ... 817 2023-09-02 1.72 2023-35 2023 35 2023-35 9 818 2023-09-09 1.72 2023-36 2023 36 2023-36 9 819 2023-09-16 2.17 2023-37 2023 37 2023-37 9 820 2023-09-23 1.62 2023-38 2023 38 2023-38 9 821 2023-09-30 1.83 2023-39 2023 39 2023-39 9 [822 rows x 7 columns]
各年份周数统计
df.groupby('year')['WEI'].count()
输出:
year 2008 52 2009 52 2010 52 2011 53 2012 52 2013 52 2014 52 2015 52 2016 53 2017 52 2018 52 2019 52 2020 52 2021 52 2022 53 2023 39
未适配的同比计算函数
def calculate_week_on_week(df, value_column, date_column): df = df.sort_values(date_column) df['value_last_year'] = df[value_column].shift(52) df['week_on_week'] = (df[value_column] - df['value_last_year'])/df['value_last_year'] return df
适配方案
方案一:基于修改后的年周标识匹配
利用已生成的year_week_modified字段,直接匹配去年对应的周数(第53周自动对应去年第52周),逻辑直观不易出错。
def calculate_week_on_year_adjusted(df, value_column, date_column): # 确保数据按日期排序 df = df.sort_values(date_column).reset_index(drop=True) # 生成去年对应的年周匹配键 def get_last_year_key(row): current_year, current_week = row['year_week_modified'].split('-') last_year = str(int(current_year) - 1) return f"{last_year}-{current_week}" df['last_year_key'] = df.apply(get_last_year_key, axis=1) # 创建年周键到数值的映射表 week_value_map = df.set_index('year_week_modified')[value_column].to_dict() # 匹配去年对应周的数值 df['value_last_year'] = df['last_year_key'].map(week_value_map) # 计算同比增长率 df['week_on_year'] = (df[value_column] - df['value_last_year']) / df['value_last_year'] # 清理临时列 df = df.drop(columns=['last_year_key']) return df
方案二:动态计算偏移量
通过统计历史53周年份的数量,动态调整shift的偏移量,不需要依赖额外的年周标识列。
def calculate_week_on_year_shift_adjusted(df, value_column, date_column): df = df.sort_values(date_column).reset_index(drop=True) # 统计各年份的周数 year_week_counts = df.groupby('year')['week'].count().to_dict() # 计算累计偏移调整量:每遇到一个历史53周年份,偏移量加1 df['adjustment'] = 0 for i in range(1, len(df)): prev_years = df.loc[:i-1, 'year'].unique() df.loc[i, 'adjustment'] = sum(1 for y in prev_years if year_week_counts.get(y, 52) == 53) # 计算最终偏移量并匹配去年数值 df['value_last_year'] = df[value_column].shift(52 + df['adjustment']) # 计算同比增长率 df['week_on_year'] = (df[value_column] - df['value_last_year']) / df['value_last_year'] # 清理临时列 df = df.drop(columns=['adjustment']) return df
内容的提问来源于stack exchange,提问作者ah bon
相关产品推荐
相关产品推荐

