灰色-马尔可夫组合预测
一、直观理解:灰色抓趋势,马尔可夫修偏差
GM(1,1) 擅长从短序列里抽出一条较光滑的指数型趋势,但对局部波动、转折和系统偏差常常“抹平”。马尔可夫链则擅长描述状态之间的跳转概率,却不直接建模连续趋势。
灰色–马尔可夫组合的基本想法是:
- 先用 GM(1,1)(或其改进)得到趋势预测 ;
- 考察相对残差或绝对残差落在哪个区间(状态);
- 用马尔可夫链预测下一期残差状态,并折算成修正量;
- 得到修正预测 (或乘性修正)。
可以把它理解成:主模型负责大方向,马尔可夫负责把经常出现的“偏高/偏低”纠正回来。这在样本量不大、又存在一定波动节律的社会经济序列中较常见。
二、适用场景与优缺点
| 类型 | 说明 |
|---|---|
| 适用场景 | 序列较短但仍有趋势;GM(1,1) 趋势可用,残差呈现可分档的状态转移;需要比纯灰色更贴合局部起伏;等级修正有解释价值。 |
| 核心优点 | 保留灰色方法的小样本趋势能力;用转移概率量化残差修正;实现相对直接;常能降低纯 GM 的系统偏差。 |
| 局限与缺点 | 误差来源叠加(灰色设定误差 + 状态划分误差 + 转移估计误差);状态数与区间边界敏感;长步预测时修正效果衰减;不能替代严格的时间序列诊断。 |
使用前应确认:
- 纯 GM(1,1) 是否已有可接受的趋势拟合;
- 残差是否并非纯白噪声(若已是白噪声,再修正意义有限);
- 训练期残差是否足够估计转移矩阵;
- 最终仍以训练期外误差为准,而不是样本内“越修正越好”。
三、核心原理
1. 灰色主模型
对非负序列 建立 GM(1,1),得到拟合与预测值 。相对残差定义为
也可用绝对残差 。相对残差便于跨量级比较,但当 接近 0 时不稳定。
2. 残差状态划分
将训练期残差分成 个状态。例如按分位数:
或按等宽/业务阈值。状态 对应一个代表修正量 (组中值、组内均值或中位数)。
3. 转移与修正
由残差状态序列估计转移矩阵 。若第 期残差状态为 ,则
加性修正:
若使用相对残差状态,则常用
多步预测时,灰色部分可继续外推,马尔可夫部分用 演进;但 增大后分布趋向平稳,修正会靠近“平均残差”,信息量下降。
四、实施要点与模型选择
- 先诊断再组合:若 GM 残差已近似白噪声且无自相关,组合未必改进测试误差;
- 状态数:实践中 较常见,优先保证每态有足够样本;
- 只在训练期估计一切:GM 参数、残差分位边界、代表值、 全部来自训练期;
- 改进灰色:对波动大的序列可先用缓冲算子、新陈代谢 GM、或离散灰色模型,再套马尔可夫;
- 对比组:至少比较 纯 GM、纯指数平滑/ARIMA(若长度允许)、灰色–马尔可夫。
五、MATLAB 示例
下面给出可运行的加性修正框架(GM 部分手写,马尔可夫修残差)。
%% 数据:短趋势序列(示例)
y = [560 596 642 699 752 801 860 912 968 1025 1090 1158]';
T0 = 9; % 前 9 点训练,后 3 点测试
yTrain = y(1:T0);
yTest = y(T0+1:end);
%% ---------- GM(1,1) 拟合与预测 ----------
gmPredict = @(y0, h) local_gm11(y0, h);
[yhat_train, param] = local_gm11(yTrain, 0); % 样本内拟合
[yhat_all, ~] = local_gm11(yTrain, numel(yTest));
yhat_gm_test = yhat_all(T0+1:end);
%% ---------- 训练期残差与状态 ----------
eTrain = yTrain(:) - yhat_train(:);
m = 3;
edges = [-inf, quantile(eTrain, [1/3 2/3]), inf];
sTrain = discretize(eTrain, edges);
% 各状态代表修正量:组内均值
c = accumarray(sTrain, eTrain, [m 1], @mean, 0);
% 转移计数 + 平滑
alpha = 0.3;
N = alpha * ones(m,m);
for t = 1:numel(sTrain)-1
N(sTrain(t), sTrain(t+1)) = N(sTrain(t), sTrain(t+1)) + 1;
end
P = N ./ sum(N,2);
%% ---------- 测试期逐步修正(滚动:每步用真实残差状态更新)----------
% 竞赛中若未来真实 y 未知,则只能用预测状态链;这里演示已知测试 y 的评估框架
yhat_corr = zeros(size(yTest));
s_prev = sTrain(end);
for k = 1:numel(yTest)
pi = zeros(1,m); pi(s_prev) = 1;
pi = pi * P;
e_hat = pi * c;
yhat_corr(k) = yhat_gm_test(k) + e_hat;
% 若做滚动评价且能观察到 yTest(k),可更新状态
e_k = yTest(k) - yhat_gm_test(k);
s_prev = discretize(e_k, edges);
end
rmse_gm = sqrt(mean((yTest(:) - yhat_gm_test(:)).^2));
rmse_corr = sqrt(mean((yTest(:) - yhat_corr(:)).^2));
fprintf("测试 RMSE 纯GM=%.3f 灰色-马氏=%.3f\n", rmse_gm, rmse_corr);
disp("转移矩阵 P:"); disp(P);
disp("状态代表残差 c:"); disp(c.');
%% ========== 本地 GM(1,1) 函数 ==========
function [yhat, param] = local_gm11(y0, h)
y0 = y0(:).';
n = numel(y0);
x1 = cumsum(y0);
z = 0.5*(x1(2:n) + x1(1:n-1)); % 背景值
B = [-z(:), ones(n-1,1)];
Y = y0(2:n).';
ab = B \ Y; % [a; b]
a = ab(1); b = ab(2);
% 时间响应式
k = 1:(n+h);
x1_hat = (y0(1) - b/a) * exp(-a*(k-1)) + b/a;
yhat = zeros(1, n+h);
yhat(1) = y0(1);
yhat(2:end) = x1_hat(2:end) - x1_hat(1:end-1);
param = struct("a",a,"b",b);
end
说明:
- 真正的未来预测应将
s_prev按 链推,而不是用未来真实残差; - 上例在测试循环里用真实 更新状态,属于滚动一步修正评价,与完全多步外推不同,论文中必须写清;
- 若相对误差更合适,把
eTrain换成相对残差,修正改为乘性。
六、如何解释结果
完整报告应包括:
- 灰色模型阶次与参数 ,级比检验是否通过;
- 残差定义(绝对/相对)与状态区间端点;
- 转移矩阵与代表修正量;
- 纯 GM 与组合模型在测试集上的 RMSE/MAE/MAPE;
- 修正主要发生在哪些状态(例如“连续偏低后倾向于回补”);
- 组合是否在统计上稳定(可做滚动原点评价);
- 局限:若测试期出现训练期未见的残差幅度,修正可能失效。
不要把“样本内残差变小”写成主要成绩;组合模型参数更多,样本内必然更易贴合。
七、常见误区
1. 残差已是白噪声仍强行上马尔可夫
无自相关的残差没有稳定状态转移可学,测试集容易越改越差。
2. 状态边界用了含测试期的分位数
造成泄漏。边界与 、 必须锁在训练期。
3. 只展示修正后的漂亮曲线
必须同时给纯 GM、朴素基线,并报告训练期外指标。
4. 混淆滚动一步与多步外推
能看到前期真实值再预测下一步,比一次性预测未来多期容易得多。两种协议不可混报。
5. 状态数随手设定
应对 做敏感性分析,避免只报告最好的一次。
八、小结
灰色–马尔可夫组合预测的核心是:
用灰色模型提取短序列趋势,再用残差状态的马尔可夫转移对系统偏差做概率修正。
它适合“样本不多、趋势为主、波动可分档”的题目,但不是万能增益器。正确用法是:严格时间外推验证、写清残差与状态定义、与纯 GM 及经典时间序列基线对比,并在残差确有结构时才采用。