ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

MGM(1,m)多变量灰色预测模型:小样本耦合序列的Matlab实现

MGM(1,m)多变量灰色预测模型:小样本耦合序列的Matlab实现 简介这份资源是《多变量灰色预测模型算法的 Matlab 实现》PDF 文档面向从事数据预测、系统建模的研究生、教师与工程技术人员解决多变量、小样本、非线性序列难以建模预测的问题。全文围绕多变量灰色预测模型的建模思路展开介绍一次累加生成序列的构造、动态微分方程组 x(t)Ax(t)Bd(t) 的离散化处理以及用最小二乘法估计参数矩阵 A、B 的推导过程并给出时间响应函数与还原公式最后通过残差均值、方差与均方差比值 C 完成模型精度检验。资源共 1 个 PDF 文件压缩包约 122KB属于篇幅紧凑的期刊论文类技术文档可直接对照公式与算法步骤阅读。文档还附有完整的 Matlab 程序实现与算法流程包括数据预处理、矩阵 L 与 Y 的构造、参数估计、拟合预测值计算等关键环节并结合应用实例说明程序的使用方法与效果。目前已有 154 人学习适合希望快速把灰色预测理论落地到经济预测、工程数据分析等场景的读者参考。1. 从两条曲线互相牵扯说起手里只有几年的年度数据变量之间还互相牵扯硬套回归会因为样本太少而崩掉单独用 GM(1,1) 又只能各做各的、丢掉变量之间的相互作用。多变量灰色预测模型 MGM(1,m) 就是为这种场合准备的把 m 个相关变量打包成一个状态向量用一阶常微分方程组描述它们的联合演化再用最小二乘把发展系数矩阵 A 和灰作用量 B 辨识出来。它真正吃得开的地方是样本量小、变量耦合明显——建筑施工企业就业人数、区域能源与 GDP、工业用水与产值这类场景三到八个观测点就能跑出一个可检验的模型。下面这份 2008 年的工作给的是从建模、参数估计、精度检验到 Matlab 程序落地的完整链路拆开来能直接复用到自己手头的序列上。2. MGM(1,m) 的建模链路1-AGO、紧邻均值与最小二乘辨识2.1 单变量 GM(1,1) 并联为什么不够一个很自然的想法是既然是 m 个变量那就对每个变量单独建 GM(1,1)最后把结果拼成一张表。这么做在变量近似独立时凑合能用但一旦变量之间存在反馈关系就会失真。举个具体的例子建筑施工企业中国有和城镇集体两类的就业人数往往此消彼长——国有缩减时集体并不一定同步缩减反而可能承接一部分转移两条曲线是互相影响的。单独建模等于假设任一序列的演化只由自身历史决定耦合项被强行当成噪声吸收短期一两步还能看一外推误差就发散。MGM(1,m) 的处理思路是把这种耦合显式地写进模型。它不假设变量独立而是把 m 个变量在一次累加生成之后当作一个整体的状态向量用一个一阶微分方程组去拟合它的演化轨迹。这带来两个直接好处一是耦合信息进入参数矩阵二是模型的自由度仍然受样本量约束避免了小样本下多元回归的过参数化。2.2 微分方程组与参数矩阵 A、B 的含义设非负原始数据向量序列为 (X^{(0)}{x^{(0)}(1),x^{(0)}(2),\dots,x^{(0)}(n)})其中每个 (x^{(0)}(k)(x_1^{(0)}(k),\dots,x_m^{(0)}(k))^T) 是 m 维列向量。一次累加生成1-AGO得到[ x_j^{(1)}(k)\sum_{i1}^{k}x_j^{(0)}(i),\quad j1,\dots,m ]记 (X^{(1)}{x^{(1)}(1),\dots,x^{(1)}(n)})MGM(1,m) 的动态微分方程组写成[ \frac{dx^{(1)}}{dt}A,x^{(1)}B ]这里的 A 是一个 (m\times m) 的发展系数矩阵B 是 (m\times 1) 的灰作用量向量。A 的含义值得拆开看对角元 (a_{jj}) 刻画第 j 个变量自身的增长惯性非对角元 (a_{jl}\ (j\neq l)) 刻画第 l 个变量对第 j 个变量的耦合强度符号和量级决定了是拉动还是抑制。B 相当于一个外生的驱动项把未被累加序列本身解释掉的那部分趋势兜住。提示A 的非对角元正负号是判断变量间同向还是反向影响最直接的抓手出模型后先看这一块比看拟合曲线更有信息量。2.3 离散化与最小二乘L 矩阵怎么拼、Y 怎么取要估参数必须先把连续方程离散化。常用的做法是在区间 ([k,k1]) 上对 (x^{(1)}) 取紧邻均值[ z_j^{(1)}(k)\frac{x_j^{(1)}(k)x_j^{(1)}(k1)}{2},\quad k1,\dots,n-1 ]再把导数用差商 (x^{(0)}(k1)x^{(1)}(k1)-x^{(1)}(k)) 近似得到离散形式[ x^{(0)}(k1)A,z^{(1)}(k)B ]把 (k1,\dots,n-1) 逐行堆起来就得到一个标准的最小二乘问题 (YLD)。构造方式如下表矩阵维度第 k 行或列内容L(n-1) × (m1)([z_1^{(1)}(k),\dots,z_m^{(1)}(k),1])最后一列全为 1 吸收 BY(n-1) × m(x^{(0)}(k1))即原始序列从第 2 个时刻起的每一行D(m1) × m前 m 行是 (A^T)最后一行是 (B^T)于是参数估计为[ \hat D(L^TL)^{-1}L^TY ]展开就是把 D 拆成 (\hat A)前 m 行转置和 (\hat B)最后一行转置。对应的 Matlab 构造片段% X0: n×m 原始非负序列每行一个时刻每列一个变量 [n, m] size(X0); X1 cumsum(X0, 1); % 一次累加生成 Z (X1(1:n-1,:) X1(2:n,:)) / 2; % 紧邻均值(n-1)×m L [Z, ones(n-1, 1)]; % 加常数列 Y X0(2:n, :); % 差分序列 D (L * L) \ (L * Y); % 最小二乘避免直接 inv A D(1:m, :); % m×m B D(m1, :); % m×1代码逻辑很直白cumsum走一遍 1-AGO紧邻均值用向量化的一行差分搞定L的最后一列全是 1 用来吸收常数项 B\走 QR 分解求解比inv(L*L)*L*Y在数值上稳得多。返回的 A 需要转置因为最小二乘解出的 D 前 m 行是按 (x_j^{(0)}) 逐一排列的而微分方程里的 A 是列向量系数矩阵转置后才是原式的 A。2.4 时间响应函数与累减还原参数拿到之后解线性常微分方程组初始条件取 (x^{(1)}(1))得到连续时间响应函数[ \hat x^{(1)}(t)e^{A(t-1)},x^{(1)}(1)A^{-1}!\left(e^{A(t-1)}-I\right)B ]离散化到第 k 个时刻就是[ \hat x^{(1)}(k)e^{A(k-1)},x^{(1)}(1)A^{-1}!\left(e^{A(k-1)}-I\right)B ]这里 (e^{A}) 是矩阵指数Matlab 里用expm而不是逐元素exp这一点后面还会专门说。得到的是累加序列的拟合值还要做一次累减才能还原到原始尺度[ \hat x^{(0)}(k)\hat x^{(1)}(k)-\hat x^{(1)}(k-1),\quad k2,3,\dots ]第一项直接取 (\hat x^{(0)}(1)x^{(0)}(1))因为 1-AGO 的第一项和原始序列第一项相同。累减这一步看起来简单但它是误差放大器累加序列的绝对误差被差分之后转化为相对误差如果累加阶段的拟合已经偏了 1%还原回原始序列可能偏到 3%5%。所以后面做精度检验时检验对象是还原后的原始序列而不是累加序列。3. Matlab 实现从论文原脚本到可复用函数3.1 论文原程序的几个硬伤论文给出的 Matlab 片段是课堂讲稿式的写法直接抄进工程用会踩坑几处典型问题一是a(:,j)inv(L*L)*L*Y(1:n-1,j)在循环里反复求解每个变量算一遍同样的 (L^TL)n 大一点就是平方级的浪费二是L[1 ones(n-1,1)]这行漏掉了紧邻均值矩阵正确写法应是L[Z ones(n-1,1)]直接跑会报维度错三是expm2这个函数名在标准 Matlab 里并不存在标准库对应的是expm四是inv(A)在 A 接近奇异时会给出巨大的数值噪声改用左除A\更稳五是响应函数只处理了 (k1) 和 (k1) 两支没有把预测步和拟合步统一起来外推时要手改下标。注意论文里的代码片段用作文档说明没问题但一定要先复现、对比论文给出的参数值确认无误之后再放进生产流程。3.2 向量化重写mgm1m 函数把上面这些问题一并处理重写成一个可以直接调用的函数function [A, B, X0_fit, X0_pred] mgm1m(X0, n_pred) % MGM(1,m) 多变量灰色预测模型 % 输入: % X0 n×m 原始非负数据矩阵每行一个时刻每列一个变量 % n_pred 需要外推的步数填 0 表示只做拟合 % 输出: % A m×m 发展系数矩阵 % B m×1 灰作用量向量 % X0_fit 拟合的原始序列与 X0 同尺寸 % X0_pred 向外推 n_pred 步的预测值 [n, m] size(X0); if n m 2 error(样本点数 n 至少要比变量数 m 多 2); end X1 cumsum(X0, 1); % 1-AGO Z (X1(1:n-1,:) X1(2:n,:)) / 2; % 紧邻均值 L [Z, ones(n-1, 1)]; Y X0(2:n, :); D (L * L) \ (L * Y); % 最小二乘 A D(1:m, :); B D(m1, :); % 统一的时间响应k 从 1 到 nn_pred 一次性算完 N n n_pred; X1_fit zeros(N, m); X1_fit(1,:) X1(1,:); for k 2:N E expm(A * (k - 1)); % 矩阵指数 X1_fit(k,:) (E * X1(1,:) A \ ((E - eye(m)) * B)); end X0_all [X1_fit(1,:); diff(X1_fit, 1, 1)]; % 累减还原 X0_fit X0_all(1:n, :); X0_pred X0_all(n1:end, :); end这段代码的关键改动在三处。expm(A)用的是矩阵指数保证 (e^{A(k-1)}) 这一项在 A 有复特征值振荡型数据时依然正确A \ (...)和(L*L) \ (...)全部改用左除避开显式求逆循环写成从 2 到 N 的统一下标拟合和外推共用同一段公式n_pred 填几就往外走几步。diff(X1_fit,1,1)是沿第一维做一阶差分一次搞定累减还原不需要手写下标。3.3 参数含义与调用示例调用的时候X0 的排布是每行一个时间点、每列一个变量这一点跟多数文献里的列向量约定不同但和 Matlab 里cumsum(X0,1)的习惯一致不容易搞错维度。一个最简单的自检X0 [120 40; 135 44; 148 47; 162 51; 175 54]; % 5 个时刻2 个变量 [A, B, X0_fit, X0_pred] mgm1m(X0, 2); disp(发展系数矩阵 A ); disp(A); disp(灰作用量 B ); disp(B); disp(两步外推 ); disp(X0_pred); resid X0 - X0_fit; fprintf(最大相对残差 %.4f%%\n, ... 100 * max(abs(resid(:) ./ X0(:))));返回的 A 是 2×2看 (a_{12}) 和 (a_{21}) 的符号就能读出两个变量之间的耦合方向B 的单位跟原始序列一致不是无量纲量改量纲比如从万人换成人B 会同步放大A 不受影响。最大相对残差超过 5% 的时候先别急着调模型回头查一下原始序列是不是该先做平移或对数变换这是后面第 4 章要展开的部分。4. 实例复现建筑施工企业就业人数预测与精度检验4.1 数据准备与量纲处理论文用的实例是 1980—1990 年全国国有建筑施工企业和城镇集体建筑施工企业就业人数两个变量分别记为 (x_1) 和 (x_2)单位万人。这类社会经济序列在建模前有三个动作值得固化下来先做非负性检查MGM(1,m) 的 1-AGO 隐含了非负要求出现负值要先整体平移再看量纲是否接近两个变量一个在千万级、一个在百万级时A 的非对角元会被量纲放缩得难以解读必要时对其中一个取对数或按比例缩放最后确认观测点数量m 个变量至少要 n ≥ m2 才不至于让 (L^TL) 病态。把数据塞进上节的函数% 1980-199011 个时刻两个变量 X0 [ 481.0 172.0 505.0 187.0 ... 712.0 270.0 ]; % 按真实数据填入 [A, B, X0_fit, X0_pred] mgm1m(X0, 2); resid X0 - X0_fit; C std(resid, 1, all) / std(X0, 1, all); % 均方差比值 P mean(abs(resid - mean(resid,all)) ... 0.6745 * std(X0, 1, all), all); % 小误差概率 fprintf(C %.5f, P %.2f\n, C, P);论文给出的辨识结果是 (A\begin{bmatrix}0.0970 -0.1289\ 0.2476 -0.3502\end{bmatrix})(B\begin{bmatrix}4652.182\ 61.6411\end{bmatrix})。A 的非对角元一正一负说明两个变量之间的耦合是双向且方向相反的——国有就业增长会压低集体就业反过来集体就业增长对国有就业也有正向拉动这种此消彼长但不完全替代的结构单变量建模是看不出门的。4.2 均方差比值 C 与小误差概率 P 的计算灰色模型的精度检验不看 (R^2)看两个量均方差比值 C 和小误差概率 P。残差 (\varepsilon(k)x^{(0)}(k)-\hat x^{(0)}(k))它的均值和方差分别记 (\bar\varepsilon) 和 (S_2^2)原始序列的均值和方差记 (\bar x) 和 (S_1^2)则[ C\frac{S_2}{S_1},\qquad PP{|\varepsilon(k)-\bar\varepsilon|0.6745,S_1} ]判定标准是通用的一套直接查表即可等级均方差比值 C小误差概率 P一级好C ≤ 0.35P ≥ 0.95二级合格0.35 C ≤ 0.500.80 ≤ P 0.95三级勉强0.50 C ≤ 0.650.70 ≤ P 0.80四级不合格C 0.65P 0.70论文里得到 C 0.011414、P 1判定为一级说明两个变量的联合演化被方程组捕捉得相当好。C 这个量的直观含意是模型残差的波动相当于原始数据波动的一小部分C 越小越好P 则是残差落在合理区间内的频率越大越好。两个指标要一起看只满足其一都不算合格。4.3 1991—1992 外推与结果解读模型通过检验之后把 n_pred 设成 2再调一次mgm1m就能得到 1991、1992 两年的外推值。这时候有两件事必须盯住。一是 A 的特征值如果最大特征值实部接近或超过 1外推几步就会指数爆炸说明模型只适合做短期预测撑不到两步以外二是外推值与已知数据的连续性把拟合段和预测段画在同一条曲线上如果接缝处出现明显折角多半是累减还原在端点附近放大了误差可以考虑改用末段加权或者滚动建模。提示社会经济类序列的 MGM 外推稳妥的步数一般在 23 步以内超过这个范围模型的假设会明显失真不是算法问题。拟合值与预测值列在一张表里对比是最容易说服业务方的呈现方式一列原始值一列拟合值一列相对误差预测段用另一组颜色或标注区分开一眼就能看出模型在哪个时间段最准、在哪个时间段开始漂。4.4 常见失效模式与排查实际跑的时候四类问题出现频率最高维度不匹配。L*L报矩阵维度不一致几乎总是 X0 的排列方式搞反了。检查size(X0)是不是[n, m]而不是[m, n]。A 接近奇异。当 m 个变量线性相关比如两个变量始终按固定比例同步变化(A^{-1}) 会给出天文数字。处理办法是先用cond(A)看条件数超过 1e10 就说明本质上只有一个独立变量退化成单变量 GM(1,1) 或先做主成分再建模。矩阵指数用错。写成exp(A*(k-1))而不是expm(A*(k-1))结果不会报错但会给出完全错误的数值。这属于最容易埋雷的一类错误因为在 A 是对角矩阵时两者恰好相等小样本自测不容易暴露。序列含负值或零。1-AGO 之后虽然可能是正数但原始序列有负值时模型的生物学/经济学解释就站不住了先整体平移到一个正的基准再建模最后把预测值平移回来。5. 工程化技巧让 MGM(1,m) 稳定跑通的几个细节5.1 把响应函数和累减合并成一步递推上面重写的函数每次都算一遍expm对 n 上百的序列稍显冗余。矩阵指数有个好处(e^{A(k-1)}e^{A(k-2)}\cdot e^{A})可以只算一次E1 expm(A)然后沿时间轴做矩阵乘积累推。这样把复杂度从每次一个expm降到每个时间点一次 m×m 矩阵乘法n 大时提速明显。代价是数值误差在递推中缓慢累积n 小于 50 时两种写法差别可以忽略n 上千时才值得换。5.2 用对数变换处理指数型序列当序列本身接近指数增长时直接建模的残差在数值上会随时间迅速放大。常见做法是先把 (X_0) 取对数变成近似线性再走 MGM(1,m) 流程最后指数还原。这相当于把模型从线性微分方程组放宽成对数线性微分方程组对能源消费、疫情早期累计数这类序列效果往往比原版更好。还原的时候要注意偏差修正——对数域里的拟合误差在指数还原后不是无偏的简单做法是在还原时乘一个 (e^{\hat\sigma^2/2}) 的经验因子。5.3 检验指标的滚动监控模型上线之后C 和 P 不该只算一次。常用的做法是每进一批新数据就重跑一次建模把 C 和 P 记进一张监控表一旦 C 连续两次超出上一等级的门限就触发人工复核。这张表同时可以存下 A 矩阵观察非对角元符号有没有翻转——符号翻转往往意味着变量之间的耦合结构发生了质变比 C 值的变化更值得警惕。检查项触发条件处置动作C 值跳档C 连续两次越过上级门限复核原始数据确认无口径变更耦合符号翻转(a_{jl}) 正负号与历史相反检查是否新增外生干预A 条件数cond(A) 1e10判断是否退化为单变量建模外推残差新数据回测相对误差 5%缩短外推步数或切换模型把这套监控跑起来MGM(1,m) 就不再是一次性的论文代码而是一个能在生产里持续值守的小工具。本文还有配套的精品资源点击获取
返回列表