简介:面向MATLAB用户的多输入多输出回归分析工具包,以相关向量机(RVM)为核心算法,适用于工程、科研及经济预测等需要同时拟合多个相关输出变量的回归建模场景,尤其适合具备一定编程基础的本科及以上学生、研究生和工程技术人员按需扩展与二次开发。压缩包内共4个文件,包括两个m脚本(主程序与RBF核函数实现)、一个xlsx数据表格以及一个asv自动备份文件,整体仅153KB,轻量易用;m脚本承担模型训练与预测流程,数据表提供可直接替换的输入输出样本,便于快速验证。目前已有89人学习使用,可作为理解RVM原理及多输出回归实现的入门参考实例。代码中已提供完整数据与逐段注释,关键函数模块清晰,读者可在此基础上调整核参数、替换数据集或拓展为其他机器学习回归方法,完成算法对比、模型改进或创新研究,从而节省从零搭建环境与处理数据的时间。
1. 回归分析总被黑箱模型坑:相关向量机凭啥值得用
做多输入多输出回归时,大部分人第一反应就是上神经网络。可一旦样本量只有几百、特征又有噪声,神经网络很容易出现过拟合,调参调到怀疑人生。相关向量机(Relevance Vector Machine, RVM)这时候就是更稳的选择:它基于贝叶斯框架,训练出的模型不仅给出预测值,还能直接给出预测方差,相当于告诉你“这次预测置信度有多高”。这个工程性质,做设备寿命预测、软测量、经济指标联动分析时非常实用。这份基于MATLAB的RVM多输入多输出回归代码,把训练、预测、绘图流程全部串好了,数据齐全、带注释,适合研究生拿去做课题基线,也适合工程师快速验证回归思路。
2. 相关向量机的原理与核函数选择:为什么它能给置信区间
2.1 RVM与SVR的本质差异:稀疏性不是唯一亮点
支持向量回归(SVR)靠着结构风险最小化火了二十多年,但它的核函数必须满足Mercer条件,而且惩罚系数C和epsilon-insensitive损失函数要配对调参。更麻烦的是,SVR的预测结果是个点估计,想拿到置信区间得额外走bootstrap或者分位数回归,代码量直接翻倍。RVM走的是另一条路:它假设每个训练样本对应一个权重,但给这些权重加了自动相关性判定(ARD)先验。训练完成后,大部分权重被后验概率压到接近零,剩下的“相关向量”才是真正决定输出的样本,所以模型天然稀疏。这个机制让两个关键事实变得很现实。其一,RVM的核函数选择面更宽,因为贝叶斯框架下不必受Mercer条件限制;其二,预测阶段能解析算出方差,置信区间是副产品,不额外增加计算负担。
2.2 核宽度σ对拟合边界的影响:这是第一个要调的旋钮
这份代码用的是RBF核,也就是高斯核。RBF核的数学形式是核函数矩阵里第i行第j列的值等于exp(-||xi - xj||² / σ²),σ是核宽度。σ的取值决定了核函数矩阵的非对角线衰减速度,直接影响模型对局部结构的敏感程度。
这里是RBFfun.m的实际内容,核心就是算两个输入矩阵逐行之间的欧氏距离平方:
function K = RBFfun(X, Y, sigma) % RBFfun:计算RBF核矩阵 % 输入: % X - 训练输入矩阵,每行一个样本 % Y - 另一个输入矩阵(预测时是待测样本,训练时与X相同) % sigma - 核宽度,需要预选 % 输出: % K - 核矩阵,大小为 size(X,1) × size(Y,1) Dist2 = repmat(sum(X.^2,2), 1, size(Y,1)) + ... repmat(sum(Y.^2,2)', size(X,1), 1) - ... 2 * (X * Y'); K = exp(-Dist2 / sigma^2); end逻辑说明:核函数矩阵不是靠双层循环算的,而是用距离展开式避免for循环挤占时间,这个写法在MATLAB里比pairwise distance之后再exp快得多。Dist2先展开成平方和矩阵,再交叉项减掉,得到的就是完整的欧氏距离平方。参数说明:sigma设置的直觉判断是取训练样本两两距离的中位数左右,太小会让核矩阵近似单位阵,所有样本都变成孤岛,预测值只由最近邻撑起来;太大会让核矩阵所有元素趋近1,模型退化成平均预测,相关向量数量飙升。
3. 代码结构与执行流程:从数据装载到置信区间全链路拆解
3.1 压缩包文件清单:哪些是程序、哪些是备份、哪些是数据
这份资源解压后的文件结构非常干净,明确区分了主程序、备份和原始数据,整理成下表:
| 文件名 | 类型 | 作用 |
|---|---|---|
| main.m | 主脚本 | 数据加载、归一化、训练、预测、绘图全流程 |
| RBFfun.m | 函数文件 | RBF核矩阵计算,被main.m调用 |
| main.asv | 自动备份 | MATLAB编辑器自动保存的历史版本,可忽略 |
| 新建 Microsoft Excel 工作表.xlsx | 数据文件 | 多输入多输出的原始数据表 |
| 代码.rar | 压缩包 | 上述文件的打包载体 |
main.asv是MATLAB编辑器在崩溃退出前自动生成的历史备份,不是核心代码,把它当作后悔药。如果改坏了main.m,可以拿这个文件救回来改名直接用。但正常跑流程时,编辑器里只需要打开main.m和RBFfun.m。
3.2 数据装载与归一化:先看特征尺度再决定用哪种归一化
main.m的第一步是用readtable读Excel数据,然后立刻做归一化。多输入多输出的数据里,各列量纲不一致是非常普遍的现象,某个特征如果数值上千而其他特征只有0到1,RBF核里的距离计算会被大数值特征完全支配,模型退化成一个单变量回归。所以这一步不能省。
% 读取数据:第一列到倒数第二列是输入特征,最后一列是输出 data = readtable('新建 Microsoft Excel 工作表.xlsx'); X = data{:, 1:end-1}; % 输入特征矩阵 Y = data{:, end}; % 输出列,注意这里暂时只取了一列逻辑说明:readtable读Excel后,data是table类型,花括号索引取的是数值矩阵。常见误区是直接用data(:, 1:end-1),取出来还是table,后续运算会疯狂报错。参数说明:代码里Y先取最后一列,是多输入单输出的写法。如果要跑多输出,需要把输出列改成data{:, end-1:end},同时调整后续训练代码里的目标矩阵维度。这一点在4.2节展开。
归一化具体用的是mapminmax,它把每行数据映射到[-1,1]区间。注意mapminmax是按行操作的,而归一化通常是按列做的,所以用的时候要转置两次。这一步的代码和踩坑点密不可分:
% 转置后归一化再转置回来:保证每列特征单独归一化 X_norm = mapminmax(X', -1, 1)'; Y_norm = mapminmax(Y', -1, 1)';逻辑说明:mapminmax的默认行为是对行向量做归一化,转置后X'的每一列是原始的一个特征,归一化后再转置回来,得到的就是每列特征各自缩放到[-1,1]的矩阵。参数说明:上下界选-1和1而不是0和1,是因为RBF核的exp指数部分对负值更敏感,而且预测层的权重先验用零均值高斯时,中心化的输入更好学。预测完成后要反归一化,用mapminmax('reverse', Y_pred, Ps)实现,其中Ps是训练归一化时保存的参数结构体。
3.3 RVM训练与预测:迭代稀疏贝叶斯学习的核心流程
在MATLAB里实现RVM训练,逻辑走向是先构造核矩阵、初始化超参数alpha和beta,然后反复更新权重后验统计量、剪枝掉趋于无穷大的alpha、再更新剩余超参数,直到迭代收敛或达到最大次数。核心训练循环的主体框架如下:
% 核函数矩阵:训练阶段用训练集自身 K_train = RBFfun(X_train_norm, X_train_norm, sigma); N = size(K_train, 1); alpha = ones(N, 1); % 每个权重对应一个先验精度 beta = 1 / var(Y_train_norm); % 噪声方差的倒数 MaxIter = 100; % 最大迭代次数,防止死循环 for iter = 1:MaxIter % 计算后验协方差矩阵Sigma和均值mu Sigma = inv(beta * (K_train'*K_train) + diag(alpha)); mu = beta * Sigma * K_train' * Y_train_norm; % 根据现有后验均值更新alpha,并删除大于阈值的分量 gamma = 1 - alpha .* diag(Sigma); alpha_new = gamma ./ (mu.^2 + eps); keep = alpha_new < 1e3; % 超过阈值的权重视为不相关,剪枝 alpha = alpha_new(keep); % 更新噪声精度beta err = Y_train_norm - K_train(:, keep) * mu(keep); beta = (N - sum(gamma(keep))) / (err'*err + eps); % 收敛判据:alpha变化小于0.01%即停止 if norm(alpha_new(keep) - alpha) / norm(alpha) < 1e-4 break; end end逻辑说明:这一套迭代本质是证据最大化(evidence maximization)。alpha是每个权重的高斯先验精度,beta是噪声精度,后验协方差Sigma是N乘N矩阵,beta乘K'K加上diag(alpha)求逆。每次迭代用gamma值判断哪个样本对模型还有贡献,gamma接近0的样本权重后验方差小而均值小,说明它们被先验压得死死,直接剪枝。参数说明:alpha_new阈值取1e3表示当精度超过1000时认为权重几乎为零,把它从相关向量集合里删掉。MaxIter取100是为了防止收敛判据失效时死循环,实际数据集一般20轮内就收敛。
预测阶段更简单,只需要把待测样本的核矩阵算出来,再乘权重后验均值:
K_test = RBFfun(X_test_norm, X_train_norm(keep, :), sigma); Y_pred_norm = K_test * mu(keep); Y_pred = mapminmax('reverse', Y_pred_norm', Ps)';逻辑说明:K_test是测试样本与训练集中那些被保留的相关向量之间的核矩阵,mu(keep)是对应的后验均值权重。预测值是核矩阵和权重的线性组合。参数说明:X_train_norm(keep, :)取的是保留样本,如果忘记这一步把全量样本塞进核函数计算,预测结果会和训练时不一致,因为训练模型里其它系数已经被剪掉了。
3.4 训练集和测试集划分:别让数据泄漏毁了你的评估指标
数据划分在RVM里容易翻车的点是随机数种子。如果训练和测试集的划分每次都变,评估指标的波动会很大,根本没法判断调参有没有效果。main.m里用了固定种子的方式保证可复现:
rng(42); % 固定随机数种子,保证每次运行结果相同 idx = randperm(N); train_ratio = 0.8; num_train = floor(train_ratio * N); train_idx = idx(1:num_train); test_idx = idx(num_train+1:end);逻辑说明:randperm是生成随机排列,然后用前80%做训练、后20%做测试。rng(42)在每次运行前重置随机数生成器,确保别人复现时拿到的划分完全一致,评估指标的微小差异只可能来自代码改动而不是随机性。参数说明:train_ratio可以根据总样本量调,样本只有几十个时建议改成0.9,测试集只要保证每个输出维度至少有5个样本量,否则误差指标会失真。
4. 数据格式与运行参数调优:做多输出时要改哪些地方
4.1 Excel数据排布要求:输入列和输出列的边界怎么界定
打开“新建 Microsoft Excel 工作表.xlsx”,数据的排布是有约定俗成规矩的。前几列是输入特征,最后一列是输出,中间不能有文本列、缺失值或空行。特别是空行,readtable读进来会变成NaN,核函数矩阵一旦碰到NaN,整个训练循环全部变成NaN,连报错都不太好定位。
| 数据位置 | 内容 | 示例 |
|---|---|---|
| A列至倒数第二列 | 输入特征x1, x2, ..., xp | 温度、压力、流量等 |
| 最后一列 | 输出y | 效率或寿命 |
| 第1行 | 可留可删 | 如果留表头,读取时要用readtable的PreserveVariableNames参数 |
4.2 从单输出改多输出的最小改动方案:核心是Y矩阵扩列
这份代码默认输出是单列,但要做多输入多输出回归,本质区别只在于输出矩阵的宽度。改动很小,但容易漏,推荐按下面两步走。
第一步,改数据读取,把最后一列扩成最后两列或多列。多输出时,Y矩阵改成宽度为输出维数的矩阵即可。第二步,改归一化,mapminmax对Y_norm的处理不变,因为mapminmax本来就支持矩阵逐行归一化。第三步,改预测与误差计算,代码里所有Y的维度从标量向量变成矩阵后,计算误差时用mean((Y_true - Y_pred).^2, 'all')而不是mean((...).^2),否则得到的是每个输出维度分别的MSE,评估阶段会混乱。
4.3 评估指标怎么算:不要只盯着拟合图看
代码跑完会画两条曲线,一条是训练集的预测对比,一条是测试集的预测对比。很多初学者只看图觉得拟合得漂亮就收工了,但曲线重合度高不代表泛化性能好。要量化评估,直接在脚本末尾补上这段:
% 计算评估指标:R2、RMSE和MAE SS_res = sum((Y_true - Y_pred).^2); SS_tot = sum((Y_true - mean(Y_true)).^2); R2 = 1 - SS_res / SS_tot; RMSE = sqrt(mean((Y_true - Y_pred).^2)); MAE = mean(abs(Y_true - Y_pred)); fprintf('R2 = %.4f, RMSE = %.4f, MAE = %.4f\n', R2, RMSE, MAE);逻辑说明:R2是决定系数,越接近1说明模型解释了越多的方差;RMSE是均方根误差,带量纲,适合对比不同模型在同一个数据集上的表现;MAE是平均绝对误差,对离群点不敏感。参数说明:如果Y_true是多列的,计算SS_res时要用element-wise减法之后再sum,否则sum得到的是每列分别的残差平方和,而R2的公式在这种情况下不再成立。
5. 避坑指南:RVM训练与运行中四个高频问题排查
5.1 运行报错“未定义与‘double’类型的输入参数相对应的函数‘RBFfun’”
现象:点击运行main.m时,MATLAB提示找不到RBFfun函数。
原因:脚本和函数文件不在同一个目录下,或者当前工作路径没切到解压目录。
解决:把整个压缩包解压后保持main.m和RBFfun.m的相对位置,然后在MATLAB编辑器里打开main.m,让当前路径自动切换到编辑器所在目录。如果main.m是在“当前文件夹”窗口双击打开的,RBFfun.m没跟着放进来,就会触发这个报错。最简单可靠的验证方式是在命令窗口输入which RBFfun,如果返回路径说明函数可见,如果返回“未找到”就说明路径不对。
5.2 训练完成后预测值全是同一个常数
现象:模型能正常训练,但测试集预测的y值几乎全部相同,拟合图上预测线是一条平线。
原因:sigma取值过大,核矩阵所有元素趋近于exp(0)=1,测试样本与所有训练样本的相似度几乎相同,预测输出退化为一个常数。另一种可能是归一化后没有反归一化,直接把归一化空间里的预测值拿去和原始值作图。
解决:sigma从距离中位数出发向小的方向调,比如先用pdist计算样本距离,sigma取median(dist)除以2、除以5这样的梯度往下试探。注意要同步看训练集本身的核矩阵条件数,可用cond(K_train)检查,条件数超过1e6说明核矩阵接近奇异,训练会不稳定。
5.3 MATLAB提示“矩阵维度必须一致”
现象:main.m运行到核矩阵计算或权重更新时报错,提示内部矩阵维度必须一致。
原因:数据读取阶段Y只取了一列,但代码后续假设Y是多列;或者Excel最后几列有空格,被读成了NaN列,导致X、Y的列数和主脚本期望不一致。
解决:先检查Excel数据的列数,用size(X)和size(Y)打印出来确认。若输出的确是多列,检查输出列的连续性:数据写入时若中间夹了纯文本列,Excel默认会按多种类型读取,肉眼看起来是空白的单元格有可能被识别为空白列,这种情况建议用isnan检查,把NaN列直接用空值填充或删除。
5.4 alpha全部被剪枝,模型变成了空模型
现象:训练结束后相关向量的数量是0,或者只剩一两个,预测值非常接近于训练集均值。
原因:sigma过小导致核矩阵接近单位阵,每个样本只和自身强相关,训练过程认为每个样本的权重都不稳定,alpha更新后在贝叶斯框架里被大量压缩。还有一种可能是数据本身没有非线性结构,线性模型已经够用,RVM把核函数里的非线性成分全部压掉了。
解决:先做一次最朴素的多元线性回归,拿R2做基准。如果线性回归的R2已经达到0.85以上,那RVM的非线性增强空间本来就不大,这时应该把决策焦点从模型选择转向数据增强或特征构造。如果线性回归很差,再把sigma调到距离中位数的量级,同时把alpha阈值从1e3降到500,让更多权重能活下来。
6. 从点预测到区间预测:利用RVM预测方差做置信边界
这个进阶点才是RVM相对于SVR最值得用的地方。代码里训练完成后,其实已经把后验权重协方差Sigma保留下来了。预测阶段待测点的方差不只是噪声方差,还包含权重不确定性传递。要拿到置信区间的上界和下界,在预测代码后追加这一段:
% 预测方差 = 噪声方差 + 核矩阵对权重协方差的映射 K_test_full = RBFfun(X_test_norm, X_train_norm(keep, :), sigma); pred_var = 1/beta + sum((K_test_full * Sigma(keep, keep)) .* K_test_full, 2); std_dev = sqrt(pred_var); Y_lower = Y_pred - 1.96 * std_dev; Y_upper = Y_pred + 1.96 * std_dev;逻辑说明:pred_var的第一项是当前噪声精度beta的倒数,表示数据噪声本身的方差;第二项是把后验协方差Sigma通过核矩阵映射到预测空间的方差,相当于权重不确定性在测试点处的传播结果。1.96是95%置信水平下的高斯分布分位数,实际工程里做软测量时通常看90%区间,对应1.645。
参数说明:Sigma(keep, keep)这一步要有对应的保留索引,否则矩阵维度对不上。绘制区间时把Y_lower和Y_upper用plot画成虚线或者用patch填充半透明色带,就能得到一张带置信带的预测图(编者按:置信区间的质量直接取决于beta估计准不准,如果噪声方差被高估,区间会宽到失去参考价值)。
最后一个值得保留的习惯是:每次换数据集后,我会先跑一遍最小二乘回归作为性能基准,无论RVM的效果看起来多好,先跟它比一把再下结论。如果RVM在测试集上的RMSE比最小二乘好不了5%以上,那就该检查sigma选择和核函数类别,而不是直接认定RVM不行。这个习惯我从第一次跑RVM代码时就开始用,从那以后每逢回归分析报告都强制走一遍这个流程,少走很多弯路,希望帮到你。
本文还有配套的精品资源,点击获取