资讯动态

模式识别算法MATLAB实现:从手写数字识别到分类器与聚类实战

发布时间:2026/10/17 18:09:53 来源:尧图企业网站定制
简介一份以MATLAB为工具、系统讲解模式识别理论与实现的教材PDF适合计算机、信息工程、自动化等专业学生及算法工程师阅读。全书14章内容覆盖特征选择与优化、相似性测度以及贝叶斯、判别函数、神经网络、决策树、粗糙集等分类器设计并详解K-means、模糊聚类、遗传算法、蚁群与粒子群等聚类方法。各算法均配有实现步骤和可运行的MATLAB代码并统一以手写数字识别为实例便于对照学习不同方法的实际效果。资源包为单份PDF文件大小17.87MB排版清晰可直接作为课程学习或项目研发的参考书。目前已有311人学习下载适合希望从理论到编码完整掌握模式识别方法的读者。1. 模式识别算法 MATLAB 实现一本把理论跑成代码的教材手写数字识别是模式识别里最经典的练兵场而这本书最值钱的地方在于用同一套手写数字样本把贝叶斯分类器、判别函数、六种神经网络、五种聚类方法全部跑通并且给出可直接运行的 MATLAB 代码和效果对比。市面上的算法源码其实不少但数据集不同、预处理不同、参数口径不同拿来做横向对比基本等于瞎对齐。这本书把所有算法收敛到同一条数据链路上特征怎么提、分类器怎么训、聚类怎么评都有对应代码。适合正在做课程设计或本科毕设的人也适合在工作中想换新框架之前、先用 MATLAB 快速验证算法可行性的工程人员。2. 特征工程与相似性测度先把手写数字变成向量2.1 特征库的构建与样品筛选模式识别的第一步永远是把样本变成特征向量。手写数字样本一般是二值图像常见做法是把图像统一缩放到固定网格每个网格作为一维特征。比如缩到 16×16灰度值转成 double 后拉伸成一行就得到 256 维特征向量。书中手写数字特征提取一节走的就是这个思路这也是后面所有分类器和聚类算法的输入。% 图像转特征向量统一尺寸 归一化 function feat img2feat(imgPath) I imread(imgPath); if size(I, 3) 3 I rgb2gray(I); % 彩色图先转灰度 end I imresize(I, [16 16], bilinear); % 缩放到 16x16 网格 I double(I) / 255; % 归一化到 [0,1]消除曝光差异 feat reshape(I, 1, []); % 1x256 特征向量 end这段代码做了三件事去颜色、统一尺寸、归一化。imresize 的 bilinear 是双线性插值对手写笔画这种边缘信息保留比最近邻插值好16×16 是经验值笔画粗细能保留又不至于让特征维度太高。归一化这步很多人会跳过去但对后面算欧氏距离、夹角余弦都有直接影响灰度值范围不一致会让距离测度被高亮样本主导。样品筛选这一步容易被忽略但很关键。我一般会先把每类样本数量打出来检查一遍类别不均衡时贝叶斯分类器会偏向样本多的类神经网络训练也会不稳定。书里对每个数字类别都维护了独立的样本集合训练前人工剔除噪声过大、笔画断成几截的“坏样本”这一步做不做直接决定你后面分类器是 98% 正确率还是 80%。2.2 特征评估与 PCA 降维256 维特征对 10 类手写数字来说过于冗余直接拿去训练分类器不仅慢还容易过拟合。书中特征评估章节提供了两条路一是对单个特征做分布分析看它能不能把类别区分开二是用主成分分析PCA做整体降维把高维特征压缩到低维子空间。% 特征矩阵 X: m 个样本 x n 维特征 [coeff, score, latent] pca(X); % R2012b 以后用 pca % 老版本可替换为 [coeff, score, latent] princomp(X); % 按累计方差贡献率确定保留维度 ratio cumsum(latent) / sum(latent); keep find(ratio 0.95, 1); % 保留 95% 方差对应的维数 Xpca score(:, 1:keep); % 降维后的特征pca 返回三个关键量coeff 是投影矩阵各主成分方向score 是样本在主子空间里的坐标latent 是各主成分的特征值也就是方差大小。用 cumsum(latent)/sum(latent) 算出累计贡献率后一般取 85% 到 95% 对应的维度数。这里有个细节pca 默认对数据做中心化但不做标准化。如果特征量纲差异大比如有些特征本身范围就是 0~255我建议先对 X 做 zscore 标准化再降维否则 PCA 会被量纲大的特征主导。降维后还有个有用的可视化操作取 score 的前两列直接画散点图不同类别用不同颜色标出来。如果 10 类在手写数字上能明显聚成 10 团说明特征有区分度如果混成一团就别对后续分类器抱太高期望。这一步是黑匣子打开前的快速体检。2.3 距离测度怎么选相似性测度这一章看起来全是数学公式实际对应的是分类器里最核心的“怎么判断一个样本离模板近”。书中列了七种测度模板匹配、PCA 模板匹配、类中心欧氏距离、马氏距离、夹角余弦、二值化夹角余弦、二值化 Tanimoto。我重点说三种最常用的。测度计算特点适用场景欧氏距离直接算 L2 范数特征已归一化时的默认选择马氏距离引入协方差矩阵特征维度间强相关时使用夹角余弦只比方向、不比幅值灰度受笔画粗细影响时更稳二值化 Tanimoto交集比并集二值图像匹配效果好% 待测样本 x类中心 mu d_euc sqrt(sum((x - mu).^2)); % 欧氏距离 d_cos 1 - x * mu / (norm(x) * norm(mu)); % 夹角余弦距离欧氏距离实现最简单但要求特征先做归一化夹角余弦只关心方向同样一个字写大一号、小一号灰度幅值变了但方向没变余弦反而更稳。书里把二值化的夹角余弦和 Tanimoto 单独拿出来讲我实际试过当手写数字笔画粗细变化大时二值化 Tanimoto 的鲁棒性明显更好代价是特征必须提前做二值化处理阈值切分。注意马氏距离不是万能的样本数小于特征维度时协方差矩阵奇异直接 inv 求逆会翻车这一步在贝叶斯分类器里同样会遇到。3. 分类器设计从贝叶斯到神经网络的六条路线3.1 贝叶斯分类器贝叶斯分类器是统计模式识别的基石书里分了最小错误率和最小风险两条线。落到代码层面最常见的高斯判别做法是每个类别分别估计均值和协方差然后用对数化的后验概率做判决。对 10 类手写数字就是 10 个高斯模型各自算一个得分取最大者。% 高斯判别训练阶段估计每类均值与协方差 for c 1:10 idx find(trainLabel c); mu(:, c) mean(trainFeat(idx, :), 1); % 类均值 Sigma(:, :, c) cov(trainFeat(idx, :)); % 类协方差 end % 测试阶段计算每类的对数判别函数值 g zeros(1, 10); for c 1:10 diff x - mu(:, c); invS pinv(Sigma(:, :, c)); % 伪逆防奇异 g(c) -0.5 * diff * invS * diff - 0.5 * log(det(Sigma(:, :, c))); end [~, pred] max(g);代码里最值得注意的是用 pinv 而不是 inv。训练样本少、特征维度高时协方差矩阵经常不满秩直接 inv 会报 Matrix is singular这是贝叶斯分类器最常见的翻车点。pinv 能给出伪逆虽然牺牲了一点精度但至少能跑通。如果发现识别率异常低优先考虑是不是协方差估计被噪声样本带偏了解决办法是加正则化项把 Sigma 加上一个小单位阵 I比如 0.01 倍迹。3.2 判别函数判别函数章节的经典路线是线性判别函数 → 感知器 → 增量校正 → LMSE → Fisher → 势函数 → 支持向量机。感知器是最容易理解的一个它在两类样本线性可分时通过迭代修正权向量来找到分类面。% 感知器两类线性可分时迭代更新权向量 w zeros(size(trainFeat, 2), 1); b 0; eta 0.1; % 学习率 for epoch 1:100 mis 0; for i 1:size(trainFeat, 1) y trainFeat(i, :) * w b; % 当前输出 if y * trainLabel(i) 0 % 分类错误则修正 w w eta * trainLabel(i) * trainFeat(i, :); b b eta * trainLabel(i); mis mis 1; end end if mis 0 break; % 全部正确提前退出 end end学习率 eta 是这里最敏感的参数取大了震荡不收敛取小了收敛慢。我一般从 0.1 起步观察迭代轮数如果 100 轮还没收敛把 eta 调小到 0.01。感知器只能处理线性可分问题书上后续的 Fisher 和 SVM 才是解决线性不可分的重点——Fisher 的核心是把高维样本投影到一条直线上且类间距离最大、类内距离最小SVM 则是用核函数把样本映射到高维空间找最大间隔超平面。这里的 MATLAB 实现偏教学化SVM 部分可以直接用 fitcsvm 替代手写。3.3 六种神经网络分类器这一章信息量最大也是全书最厚的一章。六种网络各有侧重我建议拿到资源后先按表格对号入座不要挨个盲目跑神经网络核心思想典型适用场景BP误差反向传播修正权值通用非线性分类、回归RBF径向基函数做隐层映射函数逼近、局部响应自组织竞争无监督竞争学习自动聚类、拓扑保持PNN基于概率密度估计小样本分类、实时性要求高CPN竞争层输出层映射模式映射、向量量化Hopfield反馈型联想记忆模式记忆、恢复残缺图像手写数字识别里 BP 是最常被当作基线的方案。新版 MATLAB 里建 BP 网络的接口已经变了早期教材里的 newff 函数在新版本会直接报 Undefined function要用 feedforwardnet 替代。% 新版 MATLAB 建立 BP 网络 net feedforwardnet([20 10]); % 两个隐层20 和 10 个节点 net.trainParam.epochs 500; % 最大迭代次数 net.trainParam.lr 0.05; % 学习率 net train(net, trainFeat, trainLabelOneHot); % 注意转置 pred net(testFeat);train 函数的输入格式是“样本在列”所以特征矩阵要转置。标签要做 one-hot 编码而不是直接用 0~9 的数字这个坑很多新手踩过直接用数字标签训出来的网络把分类问题当回归问题做结果经常在类别边界上糊成一团。隐层节点数 20 和 10 是经验起始值如果训练误差不降先调这个而不是急着加层数。第 3 版新补充的 PNN 值得单独说。它对小样本特别友好不需要像 BP 那样反复调学习率训练速度也快得多。思路是用每个训练样本构造一个高斯核预测时统计各类别核密度之和。我自己做项目时手写数字这种类别多、样本量又不大的场景经常先用 PNN 出一版基线效果好就交差不好再换 BP/RBF省不少时间。4. 聚类分析从 K 均值到群体智能的五种思路4.1 基本聚类算法聚类分析部分从基础开始讲基于试探的最临近规则算法、最大最小距离算法、层次聚类最短距离、最长距离、中间距离、重心法、类平均距离、K 均值和 ISODATA。最大的价值在于每种算法都拿同一幅待聚类图像去跑直接能看到不同算法对同一数据的聚类结果差异。K 均值是最常用的入门算法但它有两个短板K 值需要预先给定、初始中心选择影响结果。书中用的是手写实现不依赖统计工具箱% 手写 K 均值聚类 function [labels, centers] myKmeans(X, K, maxIter) [n, ~] size(X); % 随机选 K 个样本作为初始中心 centers X(randperm(n, K), :); for iter 1:maxIter % 分配阶段每个样本归到最近中心 labels zeros(n, 1); for i 1:n dist sum((X(i, :) - centers).^2, 2); [~, labels(i)] min(dist); end % 更新阶段重算类中心 for k 1:K centers(k, :) mean(X(labels k, :), 1); end end end这个实现的每次迭代分两步先算每个样本到 K 个中心的距离并归类再按类内均值更新中心。maxIter 直接影响收敛判断一般设为 100如果 maxIter 到了还在震荡说明初始中心选得不好。更稳的初始化方式是预先用最大最小距离算法选几个彼此足够远的样本当初始中心能把随机初始化带来的不确定性压下去。ISODATA 比 K 均值高级在它能动态合并和分裂类别类内样本太少就分裂类间距离太近就合并适合完全不知道 K 是多少的数据。这是书里基础聚类部分收尾的一个亮点读代码时重点看它的“分裂条件”和“合并条件”两个阈值怎么配合。4.2 模糊聚类与模拟退火模糊聚类这部分把模糊集理论引入了聚类的目标函数中典型算法是模糊 C 均值FCM。它跟 K 均值的本质区别是FCM 不给每个样本硬指派一个类别而是给一个隶属度样本可以同时属于多个类只是隶属度大小不同。实际效果是对边界模糊的样本更宽容聚类边界不是硬切开的。% FCM 隶属度更新核心步骤简化 % U: 隶属度矩阵大小 m x K for i 1:n for k 1:K d_ik norm(X(i, :) - centers(k, :)); % 隶属度与距离成反比指数 m 控制模糊程度 U(i, k) 1 / sum((d_ik ./ norm(X(i, :) - centers)).^(2/(m-1))); end end模糊指数 m 一般取 2这是个经验值。m 越大聚类边界越模糊m 接近 1 时 FCM 退化成硬聚类类似 K 均值。还有一个常见问题是所有隶属度加起来必须等于 1代码里分母上的 sum 就是在做归一化漏掉这一步会导致聚类结果完全乱掉。模拟退火聚类则是另一条思路。标准 K 均值是贪心的只接受让目标函数变小的移动所以容易陷进局部最优。模拟退火的改进点是以一定概率接受让目标函数变差的解这个概率随着“温度”下降而减小相当于给聚类过程一个跳出局部最优的机会。书里的改进 K 均值把温度下降策略跟聚类迭代结合起来跑出来的结果往往比裸 K 均值更稳定。4.3 群体智能聚类遗传、蚁群、粒子群书的后三章分别用禁忌搜索、遗传算法、蚁群算法和粒子群算法来做聚类分析这一部分已经是把群智能计算和模式识别结合的新内容了。它们的共同点是不直接对样本聚类而是把“找到一组好的聚类中心”建模成一个优化问题用启发式搜索去逼近最优解。算法关键控制参数调参经验禁忌搜索禁忌表长度、邻域规模禁忌表太短会死循环遗传算法种群规模、交叉概率、变异概率交叉 0.7~0.9变异 0.01~0.1蚁群算法信息素挥发系数、蚂蚁数量挥发系数 0.5 左右起步粒子群算法惯性权重、个体/全局学习因子惯性权重从 0.9 线性降到 0.4以遗传算法聚类为例核心是把 K 个聚类中心串成一个“染色体”适应度函数用类内距离总和来评价。代码片段长这样% 遗传算法聚类的染色体与适应度示意 % 染色体编码K 个类中心拼接成一行 chromosome centers(:); % K*d 维向量 % 适应度 1 / 类内总距离越小越好则取倒数 fitness 1 / sumWithinDist(X, centers);注意这里染色体长度是 K 乘特征维度K 或特征维数一旦变大种群搜索空间会爆炸式增长所以这类算法的代码更适合特征维度低比如 PCA 降维后的聚类任务。蚁群聚类中信息素挥发系数是最容易踩坑的地方挥发太快会让路径信息快速丢失蚂蚁反复走老路挥发太慢又会让收敛变慢。粒子群聚类需要盯住惯性权重权重大的时候全局搜索强后期让它线性降下来局部精细搜索才走得动。书上代码把这些参数写成了可直接改的变量建议每个都留一组基准值和一组参考调整范围。5. 避坑排查跑这些 MATLAB 程序时最常见的五个问题5.1 欧氏距离分类效果差到离谱现象用类中心欧氏距离做手写数字分类测试集正确率只有 60% 甚至更低比随机猜10%好不了多少。 原因特征没有归一化。原始图像灰度值范围可能是 0~255笔画粗细不同造成的灰度差异把距离测度完全带偏了大灰度值的特征在欧氏距离里权重被放大。 解决对每个特征列做 zscore 或 min-max 归一化。代码里加一行X zscore(X);就能解决大部分问题。注意归一化必须用训练集的均值和标准差去处理测试集不能用全量数据混着算否则会引入信息泄漏。5.2 教材代码跑到 newff 直接报错现象照书敲的 BP 神经网络代码运行到net newff(...)时报 Undefined function or variable。 原因MATLAB 在 R2010b 之后重构了神经网络工具箱newff 被废弃新版用 feedforwardnet。 解决把 newff 换成 feedforwardnet或者确认当前环境里有旧版神经网络工具箱。换接口时注意newff 的参数顺序和取值跟 feedforwardnet 不完全一致比如隐层节点用向量[20 10]表示两个隐层训练参数名也从 trainParam.epochs 沿用但一些老参数名如 goal、show 在新版需要单独设置。5.3 PCA 降维后识别率反而下降现象256 维特征训练贝叶斯分类器正确率 90%PCA 降到 30 维之后降到 85%明明“保留 95% 方差”了效果却变差。 原因PCA 只保证方差保留不保证类别可分。有些判別信息恰恰藏在小方差的低秩分量里被降维切掉了。 解决降维不是一刀切。做法是把 keep 从 95% 放宽到 99% 试一轮或者降维后用 Fisher 判别评估一下低维空间的类间/类内距离比。如果还不行考虑用带类别信息的降维方法如 LDA而不是纯无监督的 PCA。5.4 K 均值聚类每次跑出来的结果不一样现象同一份数据同一个 K 值连续跑三次聚类三次结果都有差异有时候还差得很远。 原因K 均值用随机初始化选初始中心而它只保证收敛到局部最优不保证全局最优。初始中心不同最终聚类结果就不同。 解决有三种常见修法。最省事的是多跑几次比如 20 次取类内总距离最小的一次作为结果更好一点是用最大最小距离算法初始化中心让初始中心彼此尽量远离再进一步就是换 ISODATA 或书中后面讲的遗传算法聚类让搜索过程自己找合适的类中心和类别数。5.5 贝叶斯分类器报错 Matrix is singular现象训练阶段算协方差矩阵时MATLAB 报“Matrix is singular to working precision”或类似警告分类结果变成一片 NaN。 原因训练样本数小于特征维度或者某些特征高度相关导致协方差矩阵不满秩、行列式为 0。 解决优先做 PCA 降维把特征压到样本数以下计算协方差逆时用 pinv 代替 inv更稳妥的做法是在协方差矩阵对角线加一个小的正则项Sigma Sigma 0.01 * eye(d);。这三个招可以组合用先降维再正则化最后 pinv。6. 把书中代码改造成自己的实验流程验证与组合技巧书里的代码是“单算法对应单任务”的写法直接拿来跑手写数字没问题但换到自己数据上我建议按三条线改造组合、验证、导出。组合的典型做法是 PCA PNN 的搭配。先用 PCA 把特征降到能保留 95% 方差的维度再用 PNN 做分类两个算法都是书中现成代码拼起来很适合小样本多类别的场景。我实测过在手写数字这种每类几十个样本的数据上这个组合比裸 BP 收敛快正确率还稳定。验证这一步一定要单独写脚本养成习惯。每次训练完打印混淆矩阵不要只看一个总体正确率。比如数字 9 经常被错认成 7光看正确率 95% 根本发现不了混淆矩阵才能告诉你错在哪一类、是不是某两类特征空间重叠严重。我自己每次做识别实验会把训练集和测试集的分割固定下来用随机种子控制保证不同算法之间的对比不是由于数据划分不同造成的。导出的话把训练好的模型参数用save(model.mat, mu, Sigma, coeff)存下来预测阶段单独写一个脚本加载参数、只做前向计算。这样跟实际工程项目接轨模型训练和部署分离也方便复现。还有一个技巧值得单独提换相似性测度有时比换分类器更见效。书上把二值化 Tanimoto 测度放在距离分类那节很多人扫一眼就跳过了。我拿噪声较大的手写数字样本试过一次把内部的距离计算从欧氏换成 Tanimoto识别率稳定提升了两三个百分点而分类器本身完全没换。所以拿到代码包之后别着急替换神经网络结构先花半天时间把几种测度都跑一遍输出的效果对比表会告诉你哪个环节最值得调。从那以后我做识别实验都会强制走一遍固定流程先归一化特征再跑三种以上测度出基线最后才动分类器结构。算法效果说不清的时候先怀疑数据预处理不要一上来就甩锅给模型。希望这本书的代码能帮你少走一样的弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑