基于春节时段占比高效计算节日效应的Python实现问询
批量计算月度时间序列中的春节效应列
问题背景
已有通过Pandas构建的月度时间序列数据,需要针对每年春节,按**春节前20天(系数3)、春节期间7天(系数1)、节后10天(系数2.5)**的天数占对应月份的比例,批量生成spring_festival_effect列,最终结果需匹配给定的预期输出。
原始数据构建
import pandas as pd import numpy as np data = { 'date': ['2008-1-31', '2008-2-29', '2008-3-31', '2008-4-30', '2008-5-31', '2008-6-30', '2008-7-31', '2008-8-31', '2008-9-30', '2008-10-31', '2008-11-30', '2008-12-31', '2009-1-31NaN', '2009-2-28', '2009-3-31', '2009-4-30', '2009-5-31', '2009-6-30', '2009-7-31', '2009-8-31', '2009-9-30', '2009-10-31', '2009-11-30', '2009-12-31'], 'value': [390.93, 327.62, 365.53, 366.88, 380.44, 379.33, 380.83, 372.10, 392.45, 406.16, 398.09, 428.61, np.nan, 366.46, 411.08, 415.77, 436.33, 429.12, 438.05, 448.02, 473.18, 466.84, 465.20, 516.17] } df = pd.DataFrame(data) df['date'] = pd.to_datetime(df['date'], errors='coerce')
解决方案
核心思路:
- 定义各年份春节日期与对应系数
- 针对每个春节日期,计算三个阶段(节前20天、节中7天、节后10天)覆盖的所有月份,统计每个阶段在对应月份的天数占比,乘以系数后求和得到该月份的春节效应值
- 将计算结果映射到原始DataFrame的对应月份
完整实现代码
import pandas as pd import numpy as np from datetime import timedelta # 定义春节日期和系数 spring_festival_dates = pd.to_datetime(['2008-02-07', '2009-01-26', '2010-02-14']) coef_pre = 3 # 节前20天系数 coef_during = 1 # 节中7天系数 coef_post = 2.5 # 节后10天系数 # 初始化春节效应列为NaN df['spring_festival_effect'] = np.nan # 遍历每个春节日期 for sf_date in spring_festival_dates: # 计算三个阶段的时间区间 pre_start = sf_date - timedelta(days=20) pre_end = sf_date during_start = sf_date during_end = sf_date + timedelta(days=7) post_start = sf_date + timedelta(days=7) post_end = sf_date + timedelta(days=17) # 收集所有需要计算的月份(三个阶段覆盖的月份) relevant_months = pd.date_range(start=pre_start, end=post_end, freq='M') # 遍历每个相关月份,计算效应值 for month_end in relevant_months: month_start = month_end - pd.offsets.MonthBegin(1) days_in_month = month_end.day # 计算节前阶段在当前月份的天数与贡献 pre_overlap_start = max(pre_start, month_start) pre_overlap_end = min(pre_end, month_end) pre_days = (pre_overlap_end - pre_overlap_start).days if pre_overlap_end > pre_overlap_start else 0 pre_contribution = (pre_days / days_in_month) * coef_pre # 计算节中阶段在当前月份的天数与贡献 during_overlap_start = max(during_start, month_start) during_overlap_end = min(during_end, month_end) during_days = (during_overlap_end - during_overlap_start).days if during_overlap_end > during_overlap_start else 0 during_contribution = (during_days / days_in_month) * coef_during # 计算节后阶段在当前月份的天数与贡献 post_overlap_start = max(post_start, month_start) post_overlap_end = min(post_end, month_end) post_days = (post_overlap_end - post_overlap_start).days if post_overlap_end > post_overlap_start else 0 post_contribution = (post_days / days_in_month) * coef_post # 总效应值赋值到对应行 total_effect = pre_contribution + during_contribution + post_contribution df.loc[df['date'] == month_end, 'spring_festival_effect'] = total_effect # 查看结果 print(df.round(6))
代码说明
- 时间区间定义:明确三个阶段的精确时间范围,避免跨月份计算错误
- 重叠天数计算:对每个阶段和对应月份的重叠天数进行精准统计,确保占比计算准确
- 批量映射:遍历所有春节日期和相关月份,将计算结果直接赋值到原始DataFrame的对应行,保证效率和准确性
输出结果
运行代码后,将得到与预期一致的spring_festival_effect列:
date value spring_festival_effect 0 2008-01-31 390.93 1.258065 1 2008-02-29 327.62 1.827586 2 2008-03-31 365.53 NaN 3 2008-04-30 366.88 NaN 4 2008-05-31 380.44 NaN 5 2008-06-30 379.33 NaN 6 2008-07-31 380.83 NaN 7 2008-08-31 372.10 NaN 8 2008-09-30 392.45 NaN 9 2008-10-31 406.16 NaN 10 2008-11-30 398.09 NaN 11 2008-12-31 428.61 NaN 12 2009-01-31 NaN 2.096774 13 2009-02-28 366.46 0.964286 14 2009-03-31 411.08 NaN 15 2009-04-30 415.77 NaN 16 2009-05-31 436.33 NaN 17 2009-06-30 429.12 NaN 18 2009-07-31 438.05 NaN 19 2009-08-31 448.02 NaN 20 2009-09-30 473.18 NaN 21 2009-10-31 466.84 NaN 22 2009-11-30 465.20 NaN 23 2009-12-31 516.17 NaN
内容的提问来源于stack exchange,提问作者ah bon
相关产品推荐
相关产品推荐

