跳到主要内容

Prophet:趋势+季节+节假日效应分解

一、直观理解:把业务曲线拆成可加积木​

Prophet 把一条观测序列看成几块可加(或可乘)部件之和:

y(t)=g(t)+s(t)+h(t)+εty(t)=g(t)+s(t)+h(t)+\varepsilon_t
  • g(t)g(t):慢变趋势(分段线性或逻辑增长);
  • s(t)s(t):周期季节(周、年等),用傅里叶项刻画;
  • h(t)h(t):节假日/事件的脉冲效应;
  • εt\varepsilon_t:噪声。

对业务人员而言,这很像:“销量 = 长期增长 + 每年旺季形态 + 春节冲高 + 随机扰动”。即使不完全使用 Facebook/Meta 的 Prophet 库,同一分解思想也可以在 MATLAB 里用回归或 trenddecomp 等工具实现。

它的卖点不是理论最优,而是:对缺失值、节假日、趋势拐点比较宽容,解释性强,调参直觉好。建模竞赛里,若题目提供日历特征或明显节假日,这种分解非常加分。

二、适用场景与优缺点​

类型说明
适用场景日/周粒度业务数据;有多个季节周期;存在已知节假日或促销事件;需要组件解释而非只给黑箱预测;序列有缺失但不想复杂插补。
核心优点结构可解释;易加入回归因子与节假日表;对趋势变点有正则;实现预测区间较方便;与业务沟通成本低。
局限与缺点默认可加结构可能不符;强噪声或高频金融序列未必合适;变点过多会过拟合;MATLAB 无官方 Prophet 时需自建等价回归;仍需训练期外验证。

使用前检查:

  1. 时间索引规则、时区、是否含营业日;
  2. 节假日是否“提前/延后效应”(窗口宽度);
  3. 趋势是线性还是有饱和上界(逻辑增长);
  4. 与 SARIMA、Holt-Winters 的基线对比。

三、核心原理​

1. 趋势项 g(t)g(t)​

分段线性趋势:

g(t)=(k+a(t)⊤δ)t+(m+a(t)⊤γ)g(t)=\bigl(k+\mathbf{a}(t)^\top\boldsymbol{\delta}\bigr)t+\bigl(m+\mathbf{a}(t)^\top\boldsymbol{\gamma}\bigr)

其中 a(t)\mathbf{a}(t) 标记 tt 是否越过变点,kk 为基斜率,δ\boldsymbol{\delta} 为斜率变化。变点可自动按时间网格放置,并对 δ\delta 做稀疏先验(类似 L1),避免处处折线。

逻辑增长趋势用于有容量上界 C(t)C(t) 的场景:

g(t)=C(t)1+exp⁡(−(k+⋯ )(t−m−⋯ ))g(t)=\frac{C(t)}{1+\exp\bigl(-(k+\cdots)(t-m-\cdots)\bigr)}

2. 季节项 s(t)s(t)​

对周期 PP(年 P≈365.25P\approx 365.25,周 P=7P=7)用傅里叶级数:

s(t)=∑n=1N[ancos⁡2πntP+bnsin⁡2πntP]s(t)=\sum_{n=1}^{N}\left[a_n\cos\frac{2\pi nt}{P}+b_n\sin\frac{2\pi nt}{P}\right]

NN 控制季节曲线的灵活度:年季节常用 N=10N=10,周季节 N=3N=3。更大的 NN 更易过拟合。

3. 节假日项 h(t)h(t)​

每个节假日 ii 对应指示变量(可含前后窗口):

h(t)=∑iκi1t∈Dih(t)=\sum_{i} \kappa_i \mathbf{1}_{t\in D_i}

κi\kappa_i 为该事件的效应幅度。相似节日可共享先验,以稳定估计。

整体上,Prophet 的估计常借助贝叶斯/正则化回归思想;在 MATLAB 中可用普通最小二乘或 fitlm 对设计矩阵回归作为工程近似。

四、与 SARIMA / 指数平滑的分工​

需求更合适的方向
短序列、强统计诊断、单位根SARIMA
只需水平/趋势/季节三组件、要快Holt-Winters
多节假日、业务解释、缺失多Prophet 式分解
多个内生变量互相影响VAR

Prophet 不是“更高级的 ARIMA”,而是结构化回归式时间模型。若残差仍有强自相关,可对残差再拟合 ARIMA(回归–ARIMA 两步法)。

五、MATLAB 示例(等价可加分解)​

下列示例用分段趋势 + 傅里叶季节 + 节假日哑变量,演示与 Prophet 相同的信息结构。

%% 模拟 2 年日数据:趋势 + 周季节 + 年季节 + 节假日
rng(3);
t0 = datetime(2022,1,1);
t = t0 + days(0:730);
n = numel(t);
x = days(t - t0); % 数值时间

trend = 100 + 0.05*x;
weekS = 5*sin(2*pi*weekday(t)/7);
yearS = 8*sin(2*pi*x/365.25) + 3*cos(4*pi*x/365.25);
holidayDates = datetime(2022,2,1) + calyears(0:1); % 示例“春节”
isHol = ismember(t, holidayDates) | ismember(t, holidayDates+days(1));
y = trend + weekS + yearS + 12*isHol + 2*randn(n,1);

%% 训练/测试:最后 60 天
T0 = n - 60;
tr = 1:T0; te = T0+1:n;

%% 设计矩阵
% 1) 线性趋势 + 少量变点斜率增量
knots = quantile(x(tr), [0.3 0.5 0.7]);
A = zeros(n, numel(knots));
for j = 1:numel(knots)
A(:,j) = max(0, x - knots(j));
end

% 2) 周/年傅里叶
phi = 2*pi*x;
FWweek = [cos(phi/7), sin(phi/7), cos(2*phi/7), sin(2*phi/7)];
FWyear = [cos(phi/365.25), sin(phi/365.25), ...
cos(2*phi/365.25), sin(2*phi/365.25), ...
cos(3*phi/365.25), sin(3*phi/365.25)];

% 3) 节假日
H = double(isHol(:));

X = [ones(n,1), x(:), A, FWweek, FWyear, H];
tbl = array2table(X, "VariableNames", ...
["const","time", compose("kp%d",1:numel(knots)), ...
"cw1","sw1","cw2","sw2","cy1","sy1","cy2","sy2","cy3","sy3","hol"]);
tbl.y = y(:);

mdl = fitlm(tbl(tr,:), "y ~ . - 1"); % 已含 const
yhat = predict(mdl, tbl);

rmse = sqrt(mean((y(te) - yhat(te)).^2));
fprintf("测试 RMSE = %.3f\n", rmse);

%% 组件可视化(用系数还原)
b = mdl.Coefficients.Estimate;
g = X(:,1:2+numel(knots)) * b(1:2+numel(knots));
s = X(:,3+numel(knots):end-1) * b(3+numel(knots):end-1);
h = X(:,end) * b(end);

figure;
subplot(4,1,1); plot(t,y); hold on; plot(t,yhat,"LineWidth",1.2);
xline(t(T0),"k--"); title("观测与拟合/预测"); legend("y","fit");
subplot(4,1,2); plot(t,g); title("趋势 g(t)");
subplot(4,1,3); plot(t,s); title("季节 s(t)");
subplot(4,1,4); plot(t,h); title("节假日 h(t)");

若已安装 Python Prophet,也可在 MATLAB 中通过 py 接口调用;竞赛若不允许外部库,用上述回归分解即可写清原理与结果。

更完整的流程还应:对残差做 autocorr/lbqtest;若自相关明显,对残差 estimate(arima(...)) 再叠加。

六、如何解释结果​

报告建议包含:

  1. 组件设定:趋势类型、变点个数与位置、季节周期与傅里叶阶数、节假日表;
  2. 各组件图:趋势是否在某时期变陡,季节峰谷是否符合业务;
  3. 节假日效应系数及窗口选择依据;
  4. 训练期外 RMSE/MAE,以及对比 SARIMA、Holt-Winters、季节朴素;
  5. 残差诊断:是否仍有周期泄漏;
  6. 不确定性:可用残差bootstrap或分位回归给区间,不要只给点预测。

解释时避免把傅里叶项单个系数“逐项讲故事”,应看合成后的季节曲线形态。

七、常见误区​

1. 变点过多导致趋势跟着噪声走​

变点网格太密、惩罚太弱,会把随机起伏当成结构变化,预测区间失真。

2. 节假日窗口乱设​

只标节日当天,却忽略“节前备货/节后回落”,效应会被季节项或残差吸收。

3. 可加/可乘结构选错​

波动随水平增大时,应对 yy 取对数或改用可乘季节。

4. 不设基线对比​

若季节朴素(去年同日)已经很好,复杂分解的增量价值有限。

5. 用未来才知道的回归因子​

例如把“当日是否突发新闻”当特征却无法在预测时获得,属于信息泄漏。

八、小结​

Prophet 风格模型的核心是:

用可解释的趋势、季节与节假日组件拼出预测,并把业务日历信息显式写进模型。

它特别适合带日历结构的业务序列。在 MATLAB 中即使没有原生 Prophet,也可用 fitlm 构造等价设计矩阵完成分解与预测。务必坚持训练期外评价、残差检验,并与 SARIMA/指数平滑基线比较,避免“分解很好看但测不准”。