You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Prophet模型中针对外汇数据完全排除周末影响?

解决Prophet模型外汇预测中周季节性受周末干扰的问题

我正在开展美元兑墨西哥比索(USD to MXN)的时间序列预测项目,使用Prophet模型。已从训练数据和未来预测日期中过滤掉周末,但周季节性组件仍出现异常,似乎包含周末影响。

现有代码

import seaborn as sns
import matplotlib.pyplot as plt
from prophet import Prophet
import pandas as pd

# 设置Seaborn样式,生成带网格线的清爽可视化效果
sns.set(style="whitegrid")

# 清洗数据:移除汇率列存在空值的行
data_fx = data_fx.dropna(subset=['Exchange Rate'])

# 转换为Prophet要求的格式:ds为日期列,y为目标变量(汇率)
prophet_data = data_fx.reset_index()[['index', 'Exchange Rate']].rename(columns={'index': 'ds', 'Exchange Rate': 'y'})

# 过滤周末数据
prophet_data['weekday'] = prophet_data['ds'].dt.dayofweek
prophet_data = prophet_data[prophet_data['weekday'] < 5]
prophet_data.drop(columns='weekday', inplace=True)

# 初始化Prophet模型
model = Prophet(
    daily_seasonality=False,
    yearly_seasonality=True,
    weekly_seasonality=False,
    changepoint_prior_scale=0.05
)

# 添加美墨两国节假日影响
model.add_country_holidays(country_name='US')
model.add_country_holidays(country_name='MX')

# 添加自定义周季节性
model.add_seasonality(name='custom_weekly', period=5, fourier_order=3)

# 拟合模型
model.fit(prophet_data)

# 生成未来90个工作日的预测日期
future_dates = model.make_future_dataframe(periods=90, freq='B')

# 生成预测结果
forecast = model.predict(future_dates)

# 绘制预测对比图
plt.figure(figsize=(14, 8))
sns.lineplot(data=forecast, x='ds', y='yhat', label='预测汇率', color='blue')
sns.lineplot(data=prophet_data, x='ds', y='y', label='实际汇率', color='orange', alpha=0.7)
plt.fill_between(forecast['ds'], forecast['yhat_lower'], forecast['yhat_upper'], color='blue', alpha=0.2)
plt.title("美元兑墨西哥比索汇率Prophet预测(排除周末及节假日)")
plt.xlabel("日期")
plt.ylabel("汇率(USD to MXN)")
plt.legend()
plt.tight_layout()
plt.show()

# 绘制预测组件图并调整自定义周季节性的X轴
fig = model.plot_components(forecast)
for ax in fig.get_axes():
    if 'custom_weekly' in ax.get_title().lower():
        ax.set_xticks(range(5))
        ax.set_xticklabels(['周一', '周二', '周三', '周四', '周五'])
plt.show()

问题

尽管已过滤周末并添加自定义周季节性,周季节性图表仍显示存在周末影响,期望Prophet将数据视为仅包含周一至周五的交易日,不受周末干扰。

预期结果

  • Prophet完全忽略周末,仅在工作日范围内应用周季节性
  • 预测及组件图表仅反映周一至周五的模式,无周末影响
  • 自定义周季节性组件的X轴仅显示周一至周五五个刻度

解决方案

1. 修正自定义周季节性的周期与生效条件

原代码中period=5不符合Prophet的时间逻辑(Prophet以自然日为单位,周期需对应7天自然周),且未限制季节性仅在工作日生效。修改如下:

# 保留工作日标记列,不要删除
prophet_data['is_business_day'] = prophet_data['ds'].dt.dayofweek < 5

# 初始化模型(保留原有设置)
model = Prophet(
    daily_seasonality=False,
    yearly_seasonality=True,
    weekly_seasonality=False,
    changepoint_prior_scale=0.05
)

# 添加节假日(保留原有设置)
model.add_country_holidays(country_name='US')
model.add_country_holidays(country_name='MX')

# 添加带条件的自定义周季节性
model.add_seasonality(
    name='custom_weekly',
    period=7,  # 对应自然周周期
    fourier_order=3,
    condition=prophet_data['is_business_day']  # 仅在工作日应用该季节性
)

这样Prophet只会在工作日计算周季节性,完全忽略周末的时间间隔。

2. 精确生成排除节假日的未来日期

原代码用freq='B'仅排除周末,未排除两国法定节假日。手动生成更精准的工作日日期:

from pandas.tseries.holiday import USFederalHolidayCalendar, AbstractHolidayCalendar, Holiday
from pandas.tseries.offsets import CustomBusinessDay

# 合并美国和墨西哥节假日规则
class MXUSHolidayCalendar(AbstractHolidayCalendar):
    rules = [
        *USFederalHolidayCalendar.rules,
        Holiday('墨西哥新年', month=1, day=1),
        Holiday('宪法日', month=2, day=5),
        Holiday('贝尼托·华雷斯诞辰', month=3, day=21),
        Holiday('劳动节', month=5, day=1),
        Holiday('独立日', month=9, day=16),
        Holiday('革命日', month=11, day=20),
        Holiday('圣诞节', month=12, day=25)
        # 可根据需求补充其他墨西哥节假日
    ]

# 创建自定义工作日偏移量
mxus_bd = CustomBusinessDay(calendar=MXUSHolidayCalendar())
# 生成未来90个工作日
future_dates = pd.date_range(
    start=prophet_data['ds'].max(),
    periods=90,
    freq=mxus_bd
)
future_dates = pd.DataFrame({'ds': future_dates})

3. 限制组件图表的X轴范围

原代码修改X轴刻度后,仍可能显示周末的空白区域,添加范围限制确保仅显示工作日:

fig = model.plot_components(forecast)
for ax in fig.get_axes():
    if 'custom_weekly' in ax.get_title().lower():
        ax.set_xticks(range(5))
        ax.set_xticklabels(['周一', '周二', '周三', '周四', '周五'])
        ax.set_xlim(-0.5, 4.5)  # 限制X轴仅显示周一到周五的刻度范围
plt.show()

4. 验证数据无额外缺失

确保训练数据的ds列是连续的工作日,无随机缺失值:

# 检查工作日连续性
full_business_days = pd.date_range(
    start=prophet_data['ds'].min(),
    end=prophet_data['ds'].max(),
    freq='B'
)
missing_days = full_business_days[~full_business_days.isin(prophet_data['ds'])]
if not missing_days.empty:
    print(f"发现缺失的工作日: {missing_days}")
    # 根据情况补充缺失数据或标记为节假日

内容的提问来源于stack exchange,提问作者Jean-Luc Saint-Fleur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 08:32:03