简介:这份资源面向正在备考或需要完成数据预测作业的学生与初学者,提供一套基于贝叶斯方法的MATLAB实现范例,帮助理解先验概率、似然与后验概率在分类和回归任务中的具体落地方式。压缩包共5个文件,包含3个mat数据文件与2个m脚本文件,整体约5KB,mat文件用于存放训练与测试样本,m脚本则对应数据读取、模型构建、训练与预测等环节,便于直接运行和逐行研读。目前已有387人学习下载,说明其在课程复习与考试准备中具有一定参考价值。通过对照代码与数据,读者可以掌握高斯朴素贝叶斯等模型的参数估计流程,理解准确率、精确率、召回率与F1分数的评估思路,并在此基础上迁移到更复杂的数据预测场景,为应对考试中的理论题与编程题积累可复用的实践模板。
1. 从一份“基于贝叶斯Bayes的数据预测matlab程序.zip”说起:它到底能解决什么
你手上有一串按时间排好的数据,可能是某台设备的振动幅值、某个传感器的温度读数、某条产线的日产量,也可能是某只标的的收盘价。你想知道下一期大概是多少,还想知道这个“大概”有多不靠谱。频率派的做法是给一个点估计加一个置信区间,但样本少的时候区间宽得没法用,样本多的时候又容易过拟合。贝叶斯方法换了个思路:先把“参数长什么样”这件事写成一个先验分布,再用观测数据去更新它,得到后验分布。预测的时候不是拿一个数去猜,而是把参数的不确定性积分掉,得到一个预测分布。这份“基于贝叶斯Bayes的数据预测matlab程序.zip”要干的事,就是把这条链路在 MATLAB 里跑通:读数据、定模型、采样、诊断、出预测区间。
它适合谁?适合手头有几百到几千条时序数据、需要给出带不确定性的预测、又不想从零推导公式的工程师和研究生。MATLAB 在这类任务里的优势是矩阵运算和可视化顺手,缺点是没有 Python 生态里那么现成的概率编程库,所以这份程序的核心价值在于把“怎么写似然、怎么设先验、怎么跑 MCMC、怎么看收敛”这几件事用可复现的脚本串起来。下面我按自己复现这类程序的习惯,把整条路径拆开讲,参数怎么设、哪里容易翻车,都会落到具体命令上。
2. 贝叶斯预测的骨架:先验、似然、后验与预测分布
2.1 为什么预测分布比点估计更值得要
频率派预测通常给你一个数,再加一句“误差正负多少”。贝叶斯预测给的是一个分布:p(y_new | y_obs) = ∫ p(y_new | θ) p(θ | y_obs) dθ。这个积分把参数 θ 的不确定性完整传给了新数据。好处是,当数据少的时候,先验会兜住参数,预测区间不会离谱地宽;当数据多的时候,似然占主导,先验被冲淡。坏处是,这个积分一般没有解析解,得靠数值采样。MATLAB 里最稳的路子是 MCMC(马尔可夫链蒙特卡洛),常用 Metropolis-Hastings 或 Gibbs 采样。程序里如果用了slicesample或自写的 MH 采样器,本质都是构造一条马尔可夫链,让它的平稳分布等于后验分布。
2.2 选模型:线性回归、AR 还是状态空间
标题没限定模型,但“数据预测”在工程里最常见的是三种:贝叶斯线性回归、贝叶斯 AR(p)、贝叶斯状态空间(局部水平/局部趋势)。选哪个看数据形态。如果特征是外生的(比如用温度、压力预测产量),用线性回归;如果只有历史值本身,用 AR;如果数据有明显趋势和噪声分离需求,用状态空间。我一般先用 AR(1) 或 AR(2) 试水,因为参数少、收敛快、诊断直观。下面给一个贝叶斯 AR(1) 的最小实现,模型是y_t = c + φ y_{t-1} + ε_t,ε_t ~ N(0, σ²)。先验取c ~ N(0, 10)、φ ~ N(0, 1)截断在 (-1,1)、σ ~ HalfNormal(1)。这些是弱信息先验,数据量够时影响很小。
% bayes_ar1_mh.m % 贝叶斯 AR(1) 的 Metropolis-Hastings 采样 rng(42); y = load('series.mat'); y = y(:); % 假设数据是一列 T = numel(y); ylag = y(1:end-1); ycur = y(2:end); % 对数后验:先验 + 似然 logpost = @(c, phi, logsig) ... -0.5*(c/10)^2 - 0.5*(phi/1)^2 ... % 先验 c, phi + log(2) - logsig - 0.5*(exp(-logsig))^2 ... % HalfNormal(1) on sigma - 0.5*(T-1)*logsig ... - 0.5*exp(-2*logsig)*sum((ycur - c - phi*ylag).^2); N = 20000; burn = 5000; chain = zeros(N, 3); % [c, phi, logsigma] chain(1,:) = [0, 0.5, log(1)]; prop_sd = [0.1, 0.05, 0.1]; % 提议分布步长,关键参数 for i = 2:N cur = chain(i-1,:); cand = cur + prop_sd .* randn(1,3); if abs(cand(2)) >= 1, chain(i,:) = cur; continue; end lp_cur = logpost(cur(1), cur(2), cur(3)); lp_cand = logpost(cand(1), cand(2), cand(3)); if log(rand) < lp_cand - lp_cur chain(i,:) = cand; else chain(i,:) = cur; end end post = chain(burn+1:end,:);这段代码里,prop_sd是提议分布的步长,直接决定接受率。经验上接受率落在 0.2 到 0.4 之间比较健康。太低说明步长太大,链在原地打转;太高说明步长太小,链走得慢、自相关高。burn是预烧期,用来丢掉还没收敛到后验的样本。logsig用对数参数化是为了让 σ 恒正,同时采样时不用处理边界。跑完以后,post的三列分别是 c、φ、logσ 的后验样本。
2.3 从后验样本到预测区间
有了后验样本,预测就简单了:对每个样本,代入模型生成一个新值,把所有新值收集起来就是预测分布。
% 预测下一期 y_last = y(end); y_pred = post(:,1) + post(:,2)*y_last + exp(post(:,3)).*randn(size(post,1),1); pi90 = quantile(y_pred, [0.05, 0.95]); fprintf('预测均值 %.3f,90%% 区间 [%.3f, %.3f]\n', mean(y_pred), pi90(1), pi90(2));注意这里randn那一步不能省。如果只算c + φ*y_last,你得到的是参数不确定性下的均值,但漏掉了观测噪声,区间会偏窄。这是新手最容易踩的坑之一。
3. 在 MATLAB 里把程序跑起来:数据准备、采样与诊断
3.1 数据读入与平稳化处理
程序第一步永远是读数据。MATLAB 里readmatrix或readtable都行,但要注意缺失值和异常值。贝叶斯方法对异常值不像最小二乘那么敏感,但前提是似然没有假设错。如果数据里有明显的离群点,用 t 分布似然比正态更稳。平稳化方面,AR 模型要求数据是平稳的。如果原始序列有趋势,先差分;如果方差随时间变化,先做对数变换。差分后的序列记得在预测时还原回去,这一步容易漏。
raw = readmatrix('series.csv'); y = raw(:,2); % 假设第二列是观测值 y = fillmissing(y, 'linear'); % 线性插值补缺失 if std(y(1:round(end/2))) > 3*std(y(round(end/2):end)) y = log(y); % 方差前大后小,取对数 end d = 1; % 差分阶数 yd = diff(y, d);fillmissing的'linear'适合短缺口,长缺口建议直接截断。差分阶数d一般取 0 或 1,取 2 的情况很少,因为二阶差分容易放大噪声。
3.2 采样器参数怎么调
MCMC 的调参集中在三处:提议步长、预烧期长度、链长。步长前面说了,接受率 0.2 到 0.4。预烧期看迹图(trace plot),链稳定在一个水平附近不再漂移就够了,一般 2000 到 5000 步。链长看有效样本数(ESS),MATLAB 没有内置 ESS,但可以自己算自相关:ess = N / (1 + 2*sum(rho(1:k))),其中rho是自相关系数,k是自相关降到 0.05 以下的滞后阶数。ESS 至少要到 1000,预测区间才稳。如果 ESS 太低,要么加链长,要么改采样器。Gibbs 采样在条件分布可解析时效率更高,但 AR 模型里 φ 的条件分布不是标准形式,所以 MH 更通用。
3.3 收敛诊断:迹图、自相关、Geweke
诊断三件套:迹图看稳定性,自相关图看混合速度,Geweke 检验看前后段均值是否一致。MATLAB 里画迹图就是plot(chain(:,2)),自相关用autocorr(chain(:,2))。Geweke 检验可以手写:取前 10% 和后 50% 的样本,算均值差除以标准误,绝对值大于 2 就报警。
phi_chain = post(:,2); figure; plot(phi_chain); title('迹图 \phi'); % 应像毛线团,无趋势 figure; autocorr(phi_chain, 50); % 快速衰减到 0 附近 n1 = round(0.1*numel(phi_chain)); n2 = round(0.5*numel(phi_chain)); g = (mean(phi_chain(1:n1)) - mean(phi_chain(end-n2+1:end))) / ... sqrt(var(phi_chain(1:n1))/n1 + var(phi_chain(end-n2+1:end))/n2); fprintf('Geweke z = %.2f\n', g);如果迹图有明显趋势,说明预烧期不够;如果自相关衰减很慢,说明步长太小或模型有强共线性;如果 Geweke 绝对值大,说明链还没混匀。这三步做完再去看预测结果,否则区间不可信。
4. 避坑与排查:贝叶斯预测程序里最容易翻车的五件事
4.1 接受率极低,链几乎不动
现象:跑完 20000 步,chain里大部分值等于上一时刻,接受率不到 5%。原因:提议步长prop_sd设得太大,候选点总落在后验的低密度区。解决:把步长缩小到原来的 1/5 到 1/10,重新跑,观察接受率是否回到 0.2 以上。如果缩小后接受率上去了但 ESS 还是低,说明后验维度高或相关性太强,考虑换 Gibbs 或对参数做重参数化。
4.2 预测区间窄得离谱
现象:90% 预测区间只有点估计上下一点点,明显不符合数据波动。原因:预测时只用了参数后验均值,漏掉了观测噪声,或者似然里 σ 被先验压得太死。解决:检查预测代码里有没有exp(logsig).*randn(...)这一项;检查 σ 的先验是不是太强,比如用了HalfNormal(0.01)这种,数据量少时会把 σ 拉向 0。换成HalfNormal(1)或更弱的先验。
4.3 差分还原时区间对不上
现象:对差分序列建模后,还原到原始尺度,预测区间和实际值偏差很大。原因:差分还原是累加过程,y_new = y_last + yd_new,如果yd_new的分布是对称的,累加后仍然对称,但方差会累积。如果做了对数变换,还要exp回去,这时区间不再对称,直接用exp(quantile)会偏。解决:在对数尺度上算分位数,再exp,或者直接在原始尺度上做后验预测采样,不要走“先算分位数再变换”这条路。
4.4 先验选得太“自信”,数据说了不算
现象:数据明显支持 φ 接近 0.9,但后验集中在 0.5 附近。原因:先验φ ~ N(0, 0.1)太强,把参数拽住了。解决:先验的尺度要跟参数的合理范围匹配。φ 在 (-1,1) 之间,先验标准差取 0.5 到 1 比较弱信息;如果取 0.1,那就是强信息,只有数据量很大才能掰过来。做敏感性分析:换几组先验跑一遍,看后验变不变。如果变了,说明数据信息不足,结论要谨慎。
4.5 程序跑得动但结果不可复现
现象:同一份数据,两次运行预测均值差很多。原因:随机数种子没固定,或者采样器用了rand但没设rng。解决:在脚本开头加rng(42),并且把链长、预烧期、步长都写死在配置区。如果用了并行,注意每个 worker 的随机流要独立设置。可复现是工程代码的底线,尤其是要交给别人复现的时候。
5. 进阶技巧:用后验预测检查验证模型,而不是只看区间
5.1 后验预测检查怎么做
后验预测检查(posterior predictive check)的思路是:用后验样本生成一批“假数据”,看真实数据的某些统计量落在假数据分布里的什么位置。如果真实值落在假数据分布的尾部,说明模型没抓住这个特征。具体做法:对每个后验样本,生成一条长度和观测一样的序列,算它的均值、方差、自相关一阶滞后,收集起来;再把真实数据的这三个统计量放进去看分位。
S = size(post,1); stats_fake = zeros(S,3); for s = 1:S c = post(s,1); phi = post(s,2); sg = exp(post(s,3)); ysim = zeros(T,1); ysim(1) = y(1); for t = 2:T ysim(t) = c + phi*ysim(t-1) + sg*randn; end stats_fake(s,:) = [mean(ysim), var(ysim), corr(ysim(1:end-1), ysim(2:end))]; end stats_real = [mean(y), var(y), corr(y(1:end-1), y(2:end))]; pvals = mean(stats_fake > stats_real); % 双侧的话取 min(p, 1-p)*2 fprintf('均值/方差/自相关的后验预测 p 值: %.3f %.3f %.3f\n', pvals);p 值在 0.05 到 0.95 之间算通过。如果某个统计量的 p 值接近 0 或 1,说明模型在这个维度上系统性偏离。比如方差 p 值接近 1,说明假数据方差普遍比真实大,模型高估了波动;接近 0 则低估。这时候要回去改似然或加结构。
5.2 模型比较:用 WAIC 或 LOO 挑 AR 阶数
AR(1) 和 AR(2) 哪个好?不能只看拟合优度,因为高阶模型总会拟合更好。贝叶斯里常用 WAIC(广泛适用信息准则)或 LOO(留一交叉验证)。WAIC 可以从后验样本直接算:对每个观测点,算对数似然的均值和方差,waic = -2*(sum(mean_ll) - sum(var_ll))。值越小越好。MATLAB 里没有现成函数,但十几行就能写出来。注意 WAIC 在数据量少时不稳定,这时候优先看后验预测检查。
5.3 一个我常犯的错:把先验当装饰
刚上手那会儿,我觉得先验随便设一个宽的就行,反正数据会说话。后来做小样本预测,数据只有 30 个点,先验的尺度直接决定了后验的位置。血泪经验是:先验不是装饰,它是模型的一部分。每次设先验,问自己一句“这个先验在数据为零时意味着什么”。如果答不上来,就换成弱信息先验,或者做敏感性分析。现在我的习惯是,任何贝叶斯预测脚本里,先验配置区必须写注释,说明每个先验的合理范围和来源。这样别人复现的时候,至少知道你的假设是什么。希望帮到你。
本文还有配套的精品资源,点击获取