Prophet 预测累计值为什么会低于最后观测值?
数据小许
结论
Prophet 没有通用的“累计”选项,也不保证预测值从最后一个实际观测值开始,或始终递增。它根据拟合出的趋势和季节性生成预测,所以预测值可能低于最后一个观测值。
你给出的预测日期还有一个细节:pd.date_range(str(last_date), freq="D", periods=horizon) 会把 last_date 本身包含在预测范围内。这样,首个预测值对应的是最后观测日期,可能是模型对该日期的拟合估计,而非对次日的预测。
从下一天开始预测
从最后观测日期的次日开始生成预测日期:
future_dates = pd.date_range(
start=last_date + pd.Timedelta(days=1),
freq="D",
periods=horizon,
)
fh = ForecastingHorizon(future_dates, is_relative=False)
y_pred = forecaster.predict(fh)
这样可以避免把最后一天的拟合值当作次日预测。不过,未来预测仍可能低于最后观测值,因为 Prophet 本身没有单调递增约束。
需要强制预测不下降时
如果业务规则要求预测累计值不低于当前值,并且逐日不下降,可以在预测后进行单调化处理:
last_value = forecast_df.iloc[-1]
y_pred = y_pred.sort_index().clip(lower=last_value).cummax()
这段处理会将预测值限制在最后观测值之上,并确保后续预测不低于此前的预测值。它属于后处理,会改变模型的原始预测结果。如果同时展示置信区间,也应说明区间不会因此自动获得统计意义上的单调约束。
如果希望预测过程本身符合累计逻辑,可以先预测每日新增量,再把非负新增量累加为累计值。每日新增量的预测也可能为负,通常需要按业务规则处理,因此这种做法同样会引入模型之外的约束。
检查日期与缺失值处理
代码中的 pd.to_datetime(df.index) 没有将转换结果赋回索引。如果索引还不是日期类型,应显式转换:
df.index = pd.to_datetime(df.index)
此外,resample('D').bfill() 会用后续日期的值填补缺失日期。对于累计序列,这可能把未来观测值填到更早的日期,进而扭曲训练数据。请根据数据含义选择填充方式,并确认 Total_Issues 确实表示按日期统计的累计数量。
备注:内容仅供参考。
