模式识别实验Python实战:环境配置、数据预处理与经典算法实现
简介一套基于Python的模式识别课程实验代码包面向需要完成贝叶斯分类、Fisher判别、K近邻与PCA人脸识别等实验的高校学生。资源覆盖性别分类、人脸识别等典型任务配套实验报告与可运行代码能直接对照运行并辅助理解原理。包内共466个文件以400个bmp人脸图像样本为主另有16个py源文件、13个txt数据说明、5个docx实验文档及xml配置等压缩包仅5.7MB结构紧凑、便于检索。目前已有1632人学习下载。实验内容包含用FAMALE.TXT与MALE.TXT构建最大似然估计下的Bayes分类器考察不同特征与参数对性能的影响利用PCA降维结合K近邻实现人脸识别并通过N-交叉法评估不同维数和k值下的准确率同时涵盖Fisher判别等经典方法可对比不同分类器在相同数据上的表现。代码与报告一同打包适合作为课程实验的直接参考或二次开发基础。1. 模式识别实验的代码为什么总要改三遍从“能跑”到“跑对”做过模式识别实验的人基本都有这种经历ppt 里的算法公式看得懂网上的参考代码也能复制一贴到自己环境里就开始花式报错。要么是 numpy 版本对不上要么是数据集格式跟代码预期的不一致要么是代码跑通了但准确率低得没法写进实验报告。真正的问题往往不在算法本身而在数据进入模型之前的那几步。模式识别实验看起来是个算法问题实际做下来你会发现大部分时间都耗在数据清洗、特征格式调整、维度对齐这些“脏活”上。这套基于 Python 的可运行代码就是把这些脏活固定成模板把 KNN、感知机、朴素贝叶斯这些经典模式识别算法从公式变成能直接跑的实验代码同时告诉你每个参数为什么这么设、每个坑出在哪个环节。适合正在做实验报告的学生、准备入门模式识别的开发者以及需要快速验证某个小想法但又不想从零写代码的工程师。2. 先把环境调通Python 版本、numpy 与 scikit-learn 的安装选择2.1 Python 实验环境怎么选才不给自己挖坑网上 python 安装教程非常多但大多数人卡住的不是安装这一步而是装完不知道选哪个版本。模式识别实验涉及的科学计算库对 Python 版本有明确要求特别是 numpy 和 scikit-learn这两个库在新版本 Python 上有时会出现预编译包还没跟上、只能从源码构建的尴尬情况。我的建议是别追新装 Python 3.8 到 3.10 之间的版本最稳。2024 年之后发布的许多教程用上了 3.11 甚至 3.12 的新特性但 scikit-learn 在部分旧版本上的兼容性测试主要覆盖的还是 3.8 到 3.11 区间。如果你用的是实验室的旧电脑3.8 往往是最稳妥的选择。环境变量配置是另一个高频踩坑点。Windows 下安装时没勾选 Add Python to PATH装完在 cmd 里敲 python 就会提示找不到命令。这个问题不需要重装 Python手动把 Python 安装目录和 Scripts 子目录加进系统环境变量就行。用 VSCode 做开发的话还需要装 Python 和 Pylance 两个扩展然后在命令面板里选解释器VSCode 的 python 环境配置本质上就是指定一个可用的 python.exe 路径并不复杂但很多新手第一次配置时会在选择虚拟环境和全局环境的选项上犯迷糊。提示实验代码不建议直接装在系统 Python 里。用python -m venv venv建一个虚拟环境依赖都装在里面实验做完了整个目录删掉也不影响其他项目。这是我从血泪经验里总结出的第一条规矩。2.2 安装 numpy、scikit-learn 与 matplotlib 的命令依赖库的安装是模式识别实验里最简单的部分但顺序有一点讲究。python 安装 numpy 库的方法在网上一搜一大把核心命令就一条pip install numpy。问题往往出在 pip 本身。如果你在装某个库时看到 “WARNING: pip is being invoked by an old script wrapper说明你的 pip 还关联着旧版 Python得用python -m pip install --upgrade pip先升级 pip 本体。scikit-learn 是一个较大的依赖包安装时会自动拉取 numpy、scipy 和 joblib如果你同时装过不同版本的 numpy偶尔会出现 DLL 加载失败的问题最省事的解决办法是全部卸载重装。# 创建虚拟环境并激活Windows 和 Linux 命令略有差异 python -m venv venv # Windows 激活方式 venv\Scripts\activate # Linux/macOS 激活方式 # source venv/bin/activate # 先装 numpy 和 scipy再装 scikit-learn 和 matplotlib pip install numpy scipy pip install scikit-learn matplotlib pip install pandas参数说明虚拟环境路径venv可以改成任意名字但建议别用.venv以外带点的名字有些工具会误判。先装 numpy 和 scipy 再装 scikit-learn 是故意的因为 scikit-learn 的安装脚本会检测已有依赖的版本如果你直接装 scikit-learn它有可能顺手把 numpy 升到你没预期到的版本。pandas 不是所有模式识别实验都需要但做表格数据时确实方便装上不吃亏。2.3 环境验证一条命令确认依赖没冲突装完环境之后直接跑实验代码前要先验证一下依赖有没有冲突。我用过太多回在 import 阶段就崩掉的环境报错信息是ImportError: numpy.core.multiarray failed to import这种问题几乎全是版本不匹配导致的。验证环境的代码很简单能一次跑通就说明基本盘没问题。# verify_env.py import sys import numpy as np import sklearn import matplotlib print(Python 版本:, sys.version) print(numpy 版本:, np.__version__) print(scikit-learn 版本:, sklearn.__version__) print(matplotlib 版本:, matplotlib.__version__)逻辑说明sys.version输出的是解释器完整版本信息用来确认你当前用的确实是 3.8 到 3.10 区间。numpy、sklearn、matplotlib 三个库版本号打印出来后对照 scikit-learn 官方文档里的依赖兼容表看一眼即可。如果 scikit-learn 版本是 1.2 以上numpy 版本必须大于等于 1.19小于 2.0否则会出现某些算法在计算距离时类型转换报错。代码跑出来的第一行如果显示 Python 版本跟你的预期不一致说明 VSCode 选错了解释器Windows 下常见于装了多个 Python 版本的情况。验证通过后我一般会顺手把pip freeze requirements.txt执行一下把当前环境的依赖清单存下来。这是给实验报告附环境说明时最省事的方式也是日后复现时唯一的后悔药。3. 数据进模型前的关键转换从图像文件到可训练的特征矩阵3.1 两种实验数据的加载方式与取舍模式识别实验的常用数据集有两类一类是像 Iris鸢尾花这样的小型表格数据一类是像 MNIST 这样的图像数据。sklearn 自带的load_iris()和load_digits()是最稳的入口不需要联网下载也不会出现文件路径对不上的问题。MNIST 完整版 7 万张图很多课程的实验代码用的是fetch_openml(mnist_784)但这个函数在部分网络环境下会卡在下载环节超时后抛异常。我一般会让初学者先用load_digits()练手它是 MNIST 的缩水版8×8 分辨率、10 个类别、1797 个样本足够演示完整的模式识别流程等流程跑通了再换完整 MNIST。# load_data.py from sklearn.datasets import load_digits, load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 方式一内置图像数据收费版 MNIST digits load_digits() X_digits, y_digits digits.data, digits.target print(digits 数据形状:, X_digits.shape, 标签形状:, y_digits.shape) # 方式二内置表格数据 iris load_iris() X_iris, y_iris iris.data, iris.target print(iris 数据形状:, X_iris.shape, 标签形状:, y_iris.shape)逻辑说明load_digits()返回一个 Bunch 对象.data是样本特征矩阵每一行是一张图拉平后的 64 个像素值.target是对应的数字标签。load_iris()类似特征是 4 个数值型维度。打印出来的形状是后面所有调试工作的起点如果形状比预期多一个维度多半是当初没把图像拉平成向量。这里注意一个典型的初学者错误图像数据在 sklearn 里被处理成(n_samples, n_features)的二维数组不是(n_samples, height, width)的三维数组。模型只认二维矩阵三维数组必须用reshape(n_samples, -1)拉平。3.2 标准化与数据划分两个直接影响准确率的步骤数据划分和标准化这两个步骤是模式识别实验里最容易被跳过、但恰恰是最影响结果的两个操作。没有划分训练集和测试集就训练模型得到的准确率没有任何参考意义因为模型在训练时已经“看过”测试数据了。不标准化就直接喂给距离类算法量纲更大的特征会主导距离计算结果就是模型完全忽略了一些本来有区分度的特征。# split_and_scale.py from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X, y load_digits(return_X_yTrue) # 划分训练集和测试集设置固定随机种子保证实验可复现 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) # 标准化用训练集的均值和标准差去转换训练集和测试集 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) print(训练集样本数:, X_train.shape[0], 测试集样本数:, X_test.shape[0]) print(标准化后训练集均值:, round(X_train_scaled.mean(), 6)) print(标准化后训练集标准差:, round(X_train_scaled.std(), 6))参数说明test_size0.2表示留 20% 的数据做测试这个比例是模式识别实验里最常见的选择数据量小可以提到 0.3数据量大可以降到 0.1。random_state42固定随机种子保证每次运行划分结果一致。stratifyy按类别比例分层采样防止某个类别在测试集里完全没出现这个问题在类别不平衡的数据集上非常致命。fit_transform和transform的区别必须讲清楚先fit_transform训练集计算均值和标准差然后直接用同一个标准化器transform测试集绝对不能在测试集上单独做fit否则会造成数据泄漏——测试集的统计信息进入了训练环节测试结果会虚高这个坑我在第 5 章会再展开。3.3 把图片文件读成特征矩阵用不到但必须会的基本功scikit-learn 自带数据集够用但遇到自采数据就得掌握从图片文件构建特征矩阵的方法。常见做法是使用 opencv 的cv2.imread读取图片再用cv2.resize统一尺寸最后把二维图像拉平。需要注意pip install opencv-python安装的包名是 opencv-python 不是 cv2import 的时候才是import cv2这一点让不少新手困惑过。# load_images.py import cv2 import numpy as np import os def load_images_from_folder(folder, target_size(32, 32)): features [] labels [] for label_name in os.listdir(folder): label_dir os.path.join(folder, label_name) if not os.path.isdir(label_dir): continue for filename in os.listdir(label_dir): if not filename.lower().endswith((.png, .jpg, .jpeg, .bmp)): continue img_path os.path.join(label_dir, filename) img cv2.imread(img_path) img cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转灰度 img cv2.resize(img, target_size) # 统一尺寸 features.append(img.flatten()) # 拉平成向量 labels.append(label_name) return np.array(features), np.array(labels) # 假设数据目录结构是 data/class_name/xxx.jpg X_custom, y_custom load_images_from_folder(./data) print(自定义数据集形状:, X_custom.shape, 类别:, np.unique(y_custom))逻辑说明文件夹名称直接作为标签这是最简单也最容易维护的标注方式。cv2.cvtColor转灰度是因为模式识别实验一般不关心颜色信息彩色转灰度可以把三维数组压缩成二维特征维度直接降到原来的三分之一。img.flatten()是 numpy 数组切片和类型转换的基础操作把 32×32 的二维数组变成 1024 维的一维数组。注意cv2.imread读出来的数组类型是 uint8范围 0 到 255如果后面要用距离类算法这个数据通常需要先除以 255 归一化或者用 StandardScaler 标准化。如果图片是彩色而且颜色本身是重要特征跳过灰度转换把三个通道直接拼接flatten()后特征维度是 height×width×3。4. 三类经典模式识别算法的可运行实现KNN 距离度量与感知机学习率4.1 KNN 分类器的最小可运行代码与 k 值选取KNNK 最近邻是模式识别实验里最直观的算法核心思想是“跟测试样本最像的 k 个训练样本投票决定它的类别”。sklearn 里实现非常简洁但最关键的 k 值选取往往被初学者忽略。k 值太小容易过拟合一个噪声点就能改变结果k 值太大又会让分类边界过于平滑小类别可能被完全淹没。常见做法是用循环扫描 k 从 1 到 20 的准确率选出最优值而不是拍脑袋定一个。# knn_experiment.py from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score X, y load_digits(return_X_yTrue) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) # 扫描 k 值找到准确率最高的那个 best_k, best_acc 1, 0.0 for k in range(1, 21): knn KNeighborsClassifier(n_neighborsk, metriceuclidean) knn.fit(X_train, y_train) acc accuracy_score(y_test, knn.predict(X_test)) print(fk{k:2d} 准确率{acc:.4f}) if acc best_acc: best_k, best_acc k, acc print(f最优 k{best_k}, 准确率{best_acc:.4f})参数说明n_neighbors控制投票邻居数量实验代码里建议固定用奇数防止平票。metriceuclidean是默认的欧氏距离适合数值型特征如果特征是高维稀疏数据可以换成cosine余弦相似度。KNN 不需要训练过程fit只是把训练数据存进去预测时才真正计算距离。这里要注意的是 KNN 的计算复杂度随样本量线性增长当训练集超过几万条时预测会明显变慢所以 KNN 适合小数据集实验。4.2 从零手写感知机30 行代码理解参数更新机制感知机是模式识别课程里必讲的基础模型也是最适合手写的算法。网上能找到的感知机代码很多但大部分跟课程里讲的原始形式对不上——要么用 sklearn 封装好了看不到更新过程要么写得过于奇技淫巧看不明白。我习惯让实验用一份最原始的感知机实现30 行左右把权重更新过程完完整整暴露出来这样调参的时候才知道自己在调什么。# perceptron.py import numpy as np from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler class Perceptron: def __init__(self, learning_rate0.01, n_epochs100, random_state42): self.lr learning_rate self.n_epochs n_epochs self.random_state random_state def fit(self, X, y): rng np.random.RandomState(self.random_state) self.w rng.normal(scale0.01, sizeX.shape[1]) self.b 0.0 for epoch in range(self.n_epochs): errors 0 for xi, yi in zip(X, y): y_pred np.dot(xi, self.w) self.b if yi * y_pred 0: # 分类错误则更新 self.w self.lr * yi * xi self.b self.lr * yi errors 1 if errors 0: print(f第 {epoch 1} 轮全部正确提前收敛) break return self def predict(self, X): return np.sign(np.dot(X, self.w) self.b) # 加载数据并整理成二分类问题只保留数字 0 和 8 X, y load_digits(return_X_yTrue) mask (y 0) | (y 8) X, y X[mask], y[mask] y np.where(y 0, 1, -1) # 正类为 1负类为 -1 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) model Perceptron(learning_rate0.01, n_epochs100) model.fit(X_train, y_train) test_acc (model.predict(X_test) y_test).mean() print(f感知机测试准确率: {test_acc:.4f})逻辑说明原始感知机的更新规则是预测符号与真实标签不一致时权重朝正确方向移动一步步长由学习率控制。y必须是正负一而不是 0 和 1这是感知机更新公式的前提0 和 1 标签会让yi * y_pred的正负判断失去意义。np.dot(xi, self.w)计算的是线性输出这正是感知机只能解决线性可分问题的根因——它本质上是在特征空间里找一条直线线性不可分的数据它永远无法收敛。把感知机限制在数字 0 和 8 的二分类上是因为原始多类别感知机需要一对多策略第一版实验没必要引入这个复杂度。学习率learning_rate的取值范围建议在 0.001 到 0.1 之间。太大会导致权重在最优解附近震荡永远不收敛太小则收敛极慢。上面代码里加了提前收敛的判断训练过程中如果某一轮全部预测正确就直接停止这是训练中常用的效率优化能省掉不少无意义的空转。实验报告里可以把学习率分别设为 0.1、0.01、0.001对比准确率和收敛轮数这是感知机实验最常见的分析角度。4.3 朴素贝叶斯适合小样本数据的模式识别基线朴素贝叶斯在模式识别实验里的地位比较特殊。它假设特征之间相互独立这个假设在大多数真实数据上都不成立但即便如此它在文本分类和小样本表格数据上依然能打。实验中使用高斯朴素贝叶斯是最常见的因为 sklearn 的GaussianNB实现不需要调参直接 fit 就能用作为基线模型非常合适。# naive_bayes.py from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.naive_bayes import GaussianNB from sklearn.metrics import accuracy_score, classification_report X, y load_iris(return_X_yTrue) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) nb GaussianNB() nb.fit(X_train, y_train) y_pred nb.predict(X_test) acc accuracy_score(y_test, y_pred) print(fGaussianNB 测试准确率: {acc:.4f}) print(classification_report(y_test, y_pred, target_names[setosa, versicolor, virginica]))参数说明GaussianNB没有必须手工调整的超参数priors参数可以手动指定类别先验概率如果没有指定则按训练数据的频率自动计算。使用鸢尾花数据主要是为了展示它在小样本上的优势——训练集只有 120 条数据朴素贝叶斯仍然能达到较高的分类准确率。classification_report会输出每个类别的精确率、召回率和 F1 值这是实验报告里比准确率更有说服力的评价指标因为准确率只反映整体水平看不出来哪个类别被模型忽略了。实验报告中如果只用准确率一个指标答辩时大概率会被问到“模型在哪个类别上表现最差为什么”提前跑一遍分类报告能把这个问题答得比较扎实。5. 模式识别实验的五个常见坑数据泄漏到版本不兼容的排查5.1 数据泄漏标准化和特征选择必须只使用训练集的信息现象模型在测试集上的准确率高得离谱比如 99% 以上但换到新采集的数据上准确率骤降到 70%。实验报告里如果出现这种数据通常不是模型优秀而是数据泄漏了。原因最容易犯的泄漏就是在标准化时对全部数据做 fit_transform而不是对训练集 fit、对测试集 transform。测试集的均值、标准差甚至特征选择结果全部混进了训练过程模型等于提前“见过”测试数据的分布。另一个常见泄漏是特征选择在划分前完成用全部数据选出来的特征子集也携带了测试集信息。还有一类隐蔽泄漏做了数据增强或去重后才划分训练测试集导致同一张图的不同版本同时出现在两边。解决划分必须在任何数据变换之前完成。所有基于统计信息的变换标准化、PCA、特征选择都只在训练集上 fit然后 transform 训练集和测试集。实验代码里养成一个习惯写任何预处理前先问一句“这个操作有没有用到测试集的信息”。注意数据泄漏是模式识别实验里最隐蔽也最影响结果可信度的问题它在代码层面完全不报错只会给出不合常理的好结果。所有实验报告的准确率都要先接受这个环节的排查再做解读。5.2 sklearn 版本差异同一个 API 在不同版本行为不一致现象代码在某台电脑上运行正常换一台电脑跑同一个脚本报TypeError: fit() got an unexpected keyword argument或者结果数值对不上。原因scikit-learn 版本升级过程中 API 有细微调整。比如train_test_split的stratify参数在 0.18 版本之前不存在GaussianNB在 1.0 版本之后class_prior_属性的计算方式有变化KNeighborsClassifier的algorithm参数在 1.1 版本后部分取值被弃用。这些都是网上旧代码跟新环境冲突的经典来源。解决实验项目必须锁定版本。第 2 章里生成的requirements.txt就是为此准备的换机器时用pip install -r requirements.txt恢复环境。如果找不到当时的 requirements 文件至少要把sklearn.__version__打印出来写进实验报告这样结果可追溯。5.3 matplotlib 中文乱码和画图坐标轴拥挤现象matplotlib 绘图时中文标题显示成一个个方框或者 x 轴标签叠在一起变成一团黑。频率很高几乎每一个用 matplotlib 画实验图的人都会遇到。原因matplotlib 默认字体不包含中文字符它不知道要用什么字体来渲染中文所以显示为方块。横坐标密集是因为刻度数太多matplotlib 默认会把每个坐标值都标出来产生重叠。解决中文乱码在绘图前手动指定中文字体代码里需要设置matplotlib.rcParams[font.sans-serif] [SimHei]或者[Microsoft YaHei]同时加上matplotlib.rcParams[axes.unicode_minus] False修复负号显示。坐标轴密集用plt.xticks(rotation45)旋转标签或手动设置刻度间隔比如只显示第 0、5、10 个值。# fix_matplotlib.py import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] # Windows 用 SimHeiLinux 用 WenQuanYi Zen Hei plt.rcParams[axes.unicode_minus] False # 修复负号显示 x [i for i in range(20)] y [i ** 2 for i in range(20)] plt.plot(x, y) plt.xticks(ticksx, labels[str(i) for i in x], rotation45) plt.xlabel(样本序号) plt.ylabel(特征值) plt.title(样本特征分布) plt.show()逻辑说明plt.xticks(ticksx, labels...)里强制指定刻度和标签配合rotation45旋转是最直接的规避重叠方式。如果你用 pandas 自带的 plot 接口横坐标密集的问题同样存在可以用df.plot(xindex, figsize(10, 5))这种通过调大画布宽度的方式缓解。5.4 随机种子不固定实验结果无法复现现象同一个代码脚本每次运行训练集和测试集的划分都不一样模型准确率每次都有小幅波动。自己改了一行代码后连 KNN 的准确率都变了根本说不清结果波动是来自改动还是来自随机性。原因机器学习算法里存在多个随机源最常见的是train_test_split的随机划分、感知机权重初始化、KMeans 等需要初始化的聚类算法。不固定随机种子每次实验等于换了不同的数据或者不同的初始化。解决在脚本开头用np.random.seed(42)、random.seed(42)全局固定随机然后每个可能涉及随机操作的调用里显式指定random_state42。sklearn 里几乎所有涉及随机的类和方法都支持random_state参数约定俗成地使用 42 这个值方便自己和他人复现。5.5 numpy 数组形状和类型错误信息千奇百怪的根源现象报错信息五花八门ValueError: operands could not be broadcast together、TypeError: numpy.int64 object is not callable、训练时正常但预测时维度不匹配。原因numpy 广播规则和数据类型转换是 Python 里最容易踩坑的部分。比如图像数据是 uint8 型标准化输出 float64 型如果中途混用可能产生截断误差。load_digits()返回的数据本身就是 int 类型如果不转换成 float标准化时会出现某些操作类型不匹配的问题。另一个常见错误是手写了 one-hot 编码但传入了标签索引。解决在数据进入模型前统一打印形状和数据类型用X.dtype检查必要时用X.astype(np.float64)转换。所有从文件夹加载的自定义图片数据统一在构建特征矩阵的最后一步转成 float。每次写完数据处理代码立刻打印X.shape, y.shape, X.dtype这行小代码能省下几个小时排查问题的时间。6. 让结果可复现的收尾随机种子、PCA 可视化和结果落盘6.1 用 PCA 把高维特征降到二维做可视化模式识别实验报告里通常需要放分类效果的图但像数字图像这种 64 维特征没法直接画在二维平面上。PCA 降维是这里最常用的工具它能把高维特征投影到二维同时尽量保留原始数据的方差信息。实验里用 PCA 不是为了分类而是为了画图验证特征的可分性——如果 PCA 后的二维图上不同类别的点能明显分开说明特征选取方向是对的分类器准确率高也才说得通。# pca_visualize.py import matplotlib.pyplot as plt from sklearn.datasets import load_digits from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler X, y load_digits(return_X_yTrue) X_scaled StandardScaler().fit_transform(X) pca PCA(n_components2) X_2d pca.fit_transform(X_scaled) print(PCA 保留的方差比例:, pca.explained_variance_ratio_) plt.figure(figsize(10, 8)) scatter plt.scatter(X_2d[:, 0], X_2d[:, 1], cy, cmaptab10, s20, alpha0.7) plt.colorbar(scatter) plt.xlabel(第一主成分) plt.ylabel(第二主成分) plt.title(PCA 降维后的数字样本分布) plt.show()逻辑说明n_components2指定降维到两维。打印的explained_variance_ratio_表示每个主成分解释的方差比例两者相加是前两个主成分保留的总信息量数字数据集上通常能达到 25% 到 35%视觉上已经能看出类别团簇。cy让不同数字标签显示不同颜色cmaptab10是 matplotlib 自带的一种离散色图适合类别型数据的着色。6.2 分类结果落盘保存不要只打在终端里实验结果只打印在终端里关掉窗口就丢了。我吃过这个亏跑完一组对比实验忘记录在文件里想写实验报告时又得重新跑一遍。后来我在每个实验脚本末尾都会加一段“结果存文件”的代码把准确率、参数、分类报告写进一个文本文件或者 pandas 表格里方便后面整理数据。# save_result.py import json from datetime import datetime from sklearn.metrics import accuracy_score, classification_report def save_experiment_result(model_name, y_true, y_pred, paramsNone, pathresults.txt): acc accuracy_score(y_true, y_pred) report classification_report(y_true, y_pred) lines [ f实验时间: {datetime.now().strftime(%Y-%m-%d %H:%M:%S)}, f模型: {model_name}, f准确率: {acc:.4f}, f参数: {json.dumps(params, ensure_asciiFalse)}, report ] with open(path, a, encodingutf-8) as f: f.write(\n.join(lines) \n * 60 \n) # 调用示例 # save_experiment_result(KNN, y_test, y_pred, {k: 3, metric: euclidean})逻辑说明json.dumps把参数字典转换成可读的字符串ensure_asciiFalse保证中文字符不被转义成\u序列。追加模式打开文件每次实验结果接在末尾而不是覆盖之前的记录方便多次对比。classification_report输出本身就包含每类的精确率、召回率、F1 值实验报告需要用于对比分析时可以直接引用。我现在的习惯是每个实验脚本都固定一个随机种子、一条打印形状的调试语句、一个落盘结果的过程。这三件事看起来不起眼但正是把模式识别实验从“跑完就忘”变成“能写进报告、能复现、敢拿出来讨论”的关键差别。希望这些踩坑经验和代码模板能帮你把实验做得更快也更扎实。本文还有配套的精品资源点击获取

相关新闻

电力负荷预测课程设计:基于多特征LSTM的完整实现与避坑指南

电力负荷预测课程设计:基于多特征LSTM的完整实现与避坑指南

简介:面向高校学生与期末大作业场景,一套基于 Python 深度学习的多特征电力负荷预测课程设计项目,覆盖从数据预处理、特征构造、LSTM 模型训练到预测结果可视化的完整流程,也适合深度学习入门者进行项目实践。压缩包仅 8 个文件&a…

2026/10/12 20:34:13 阅读更多 →
Access进销存系统实战:从表设计到VBA库存自动计算

Access进销存系统实战:从表设计到VBA库存自动计算

简介:这是一份使用Access数据库编写的进销存系统,覆盖采购、销售与库存管理,适合中小企业管理人员以及希望掌握桌面数据库开发的读者。压缩包共十三个文件,整体大小约381KB,文件类型涵盖数据库文件、编译运行版、界面控…

2026/10/12 20:33:11 阅读更多 →
多智能体协同围捕算法Python实现:从源码到避坑指南

多智能体协同围捕算法Python实现:从源码到避坑指南

简介:这是一份面向计算机专业课程设计、期末大作业及项目实战的多智能体协同围捕算法Python实现,适合需要完成高分毕设,或想系统学习多智能体规划、强化学习与机器人仿真控制的学习者。项目以Voronoi剖分与MADDPG为核心方案,覆盖单…

2026/10/12 20:33:09 阅读更多 →

最新新闻

VUE集成UEditor完整指南:从组件封装到图片上传与问题排查

VUE集成UEditor完整指南:从组件封装到图片上传与问题排查

把VUE集成UEditor这事儿,你在搜索引擎里能翻出一百篇帖子,但真正能一次跑通的,估计不到三成。写帖子的人大多是贴了个组件就完事,没告诉你UEditor那套偏老旧的纯前端架构,跟现在VUE工程化构建之间隔了多少条沟。你照着…

2026/10/12 21:31:18 阅读更多 →
投影仪标定实战:从针孔模型到光束法平差的完整指南

投影仪标定实战:从针孔模型到光束法平差的完整指南

简介:ProCamCalib 是一款面向计算机视觉与三维重建研究者的投影仪-相机系统校准工具,用 Java 编写,可对投影机-相机系统完成几何与颜色校准,并支持多相机、多投影仪配置。它通过置于原点的首台相机进行立体校准,校准板…

2026/10/12 21:31:18 阅读更多 →
进程控制块PCB:操作系统进程控制的物理基石

进程控制块PCB:操作系统进程控制的物理基石

1. 这道题为什么让很多人栽在“进程控制块”上?“第2单元进程的描述与控制考试T1”——光看标题,你可能以为这只是某次课堂小测的普通编号题。但实际接触过的学生反馈,这道题的失分率常年高于65%,远超同卷其他基础题。它不考代码、…

2026/10/12 21:31:18 阅读更多 →
大厂Java社招面试高频题与解析:JVM、并发、MySQL、Redis全覆盖

大厂Java社招面试高频题与解析:JVM、并发、MySQL、Redis全覆盖

面完一轮头部互联网公司的社招Java岗,我把整轮面试遇到的高频题和参考答案重新整理了一遍。一开始是打算凭记忆复盘的,结果越整理越觉得,大厂社招Java面试其实翻来覆去就那么几座山:JVM、并发、MySQL、Redis、分布式场景、还有一两…

2026/10/12 21:31:17 阅读更多 →
OpenClaw深度解析:从零构建你的个人AI助手(金元宝生成)

OpenClaw深度解析:从零构建你的个人AI助手(金元宝生成)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:31:17 阅读更多 →
STM32定时器编码器四倍频原理与配置实战

STM32定时器编码器四倍频原理与配置实战

1. 为什么编码器四倍频值得单独拿出来说做电机控制或者位置检测的朋友,对增量式编码器肯定不陌生。这种编码器一般输出A、B两路正交信号,转一圈输出固定数量的脉冲。但很多人第一次用STM32的定时器接编码器时,会发现读出来的计数值和手册上的…

2026/10/12 21:30:16 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →