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

Prophet时序预测中增减数据为何影响历史yhat?如何解决?

问题解答

1. 这种行为完全正常

Prophet是基于全量输入数据拟合的时间序列模型,它会用所有数据来学习趋势增长率、季节性波动(年/月周期)、节假日效应等核心参数。哪怕你只删掉最后一个月的数据,整个数据集的统计特征(比如整体均值、季节波动幅度)都会发生细微变化,导致模型重新拟合出的参数不同——最终所有时间点的yhat(包括历史时段的拟合值)都会跟着变。

你看到的历史yhat其实是模型对历史数据的回溯拟合值,不是“仅用该点之前数据做出的预测值”。默认的predict方法是用全量训练好的模型去回测所有时间点,所以只要训练数据变了,所有拟合值都会调整。

2. 实现“每个月yhat仅依赖历史数据”的方法

要满足这个需求,你需要做滚动时间序列预测(Walk Forward Validation):对每个时间点,只用该点之前的历史数据训练模型,再预测该点的值。具体实现代码如下:

import pandas as pd
from prophet import Prophet
pd.set_option('display.float_format', lambda x: '%.2f' % x)

# 读取数据
json_data = '{"ds":{"0":"2017-10-01","1":"2017-11-01","2":"2017-12-01","3":"2018-01-01","4":"2018-02-01","5":"2018-03-01","6":"2018-04-01","7":"2018-05-01","8":"2018-06-01","9":"2018-07-01","10":"2018-08-01","11":"2018-09-01","12":"2018-10-01","13":"2018-11-01","14":"2018-12-01","15":"2019-01-01","16":"2019-02-01","17":"2019-03-01","18":"2019-04-01","19":"2019-05-01","20":"2019-06-01","21":"2019-07-01","22":"2019-08-01","23":"2019-09-01","24":"2019-10-01","25":"2019-11-01","26":"2019-12-01","27":"2020-01-01","28":"2020-02-01","29":"2020-03-01","30":"2020-04-01","31":"2020-05-01","32":"2020-06-01","33":"2020-07-01","34":"2020-08-01","35":"2020-09-01","36":"2020-10-01","37":"2020-11-01","38":"2020-12-01","39":"2021-01-01","40":"2021-02-01","41":"2021-03-01","42":"2021-04-01","43":"2021-05-01","44":"2021-06-01","45":"2021-07-01","46":"2021-08-01","47":"2021-09-01","48":"2021-10-01","49":"2021-11-01","50":"2021-12-01","51":"2022-01-01","52":"2022-02-01","53":"2022-03-01","54":"2022-04-01","55":"2022-05-01","56":"2022-06-01","57":"2022-07-01","58":"2022-08-01","59":"2022-09-01","60":"2022-10-01","61":"2022-11-01"},"y":{"0":3065,"1":3127,"2":8506,"3":2527,"4":2376,"5":2753,"6":2964,"7":3750,"8":4445,"9":3502,"10":3968,"11":3195,"12":3232,"13":3377,"14":7823,"15":2452,"16":2563,"17":2747,"18":2877,"19":3617,"20":3620,"21":4044,"22":3491,"23":2853,"24":3447,"25":3346,"26":7835,"27":2543,"28":2412,"29":1860,"30":759,"31":3630,"32":2216,"33":1247,"34":4455,"35":3178,"36":3502,"37":3475,"38":7311,"39":2296,"40":2136,"41":1717,"42":2200,"43":3764,"44":3697,"45":4007,"46":3566,"47":3043,"48":3457,"49":3256,"50":8564,"51":2218,"52":2815,"53":3389,"54":3816,"55":4853,"56":4406,"57":3859,"58":4152,"59":3421,"60":3965,"61":3590}}'
data = pd.read_json(json_data)
data['ds'] = pd.to_datetime(data['ds'])

def walk_forward_predict(df, min_train_months=12):
    results = []
    # 从有足够训练数据的时间点开始滚动
    for end_idx in range(min_train_months, len(df) + 1):
        # 取当前时间点之前的所有数据做训练集
        train_data = df.iloc[:end_idx]
        # 训练模型
        model = Prophet().fit(train_data)
        # 预测当前时间点的值
        future_df = pd.DataFrame({'ds': [train_data.iloc[-1]['ds']]})
        forecast = model.predict(future_df)
        # 保存结果
        results.append({
            'ds': forecast['ds'].iloc[0],
            'yhat_walk_forward': forecast['yhat'].iloc[0],
            'y': train_data.iloc[-1]['y']
        })
    return pd.DataFrame(results)

# 执行滚动预测,至少用12个月的数据训练模型
walk_forward_df = walk_forward_predict(data, min_train_months=12)

# 对比全量拟合的结果
full_model = Prophet().fit(data)
full_forecast = full_model.predict(data)[['ds', 'yhat']].rename(columns={'yhat': 'yhat_full'})
comparison_df = walk_forward_df.merge(full_forecast, on='ds')

# 查看10月份的对比结果
print(comparison_df[comparison_df['ds'].dt.month == 10])

关键说明

  • 滚动逻辑:每次只使用当前时间点之前的历史数据训练模型,预测该点的值,这样后续数据的增减不会影响之前的预测结果。
  • 训练数据量:设置min_train_months=12是为了让模型能学习到完整的年度季节性特征,你可以根据数据情况调整这个值。
  • 性能注意:滚动预测需要多次训练模型,计算量比全量拟合大很多,如果数据集很大,可以考虑并行训练或者减少滚动次数。

内容的提问来源于stack exchange,提问作者jrvidotti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 02:01:17