简介:这份资源面向正在修读模式识别、机器学习相关课程的高校学生,提供一套可直接运行的 Python 实验代码与配套实验报告,帮助解决课程实验无从下手、报告难写的问题。包内共 466 个文件,以 400 个 bmp 人脸图像、16 个 py 脚本、13 个 txt 数据文件为主,另含 xml、docx 实验报告及工程配置文件,压缩包约 5.7MB,结构清晰便于按实验模块查阅。内容覆盖贝叶斯分类器(基于身高、体重特征完成性别分类,含最大似然估计与决策规则推导)、Fisher 判别、KNN 以及 PCA 人脸识别,并涉及用 N-交叉法比较不同降维维数和 k 值下的准确率,方便读者调整特征与分类器参数、观察性能变化。目前已有 1632 人学习下载,适合需要快速跑通实验、理解算法流程并完成实验报告的学生参考。
1. 模式识别实验代码跑不起来:从报错到出图的那条最短路径
很多人搜「基于python的模式识别实验可运行代码」,真正卡住的不是算法本身,而是环境。sklearn 装不上、matplotlib 中文乱码、数据集路径写死、随机种子没固定导致每次结果都不一样——这些才是让实验报告难产的真凶。这篇笔记面向正在做模式识别课程实验的本科生和刚转方向的自学者,目标很明确:给你一套结构清晰、依赖干净、能直接跑出分类结果和可视化图的 Python 代码骨架,覆盖数据加载、特征提取、分类器训练、评估与绘图全流程。不依赖任何私有数据集,用 sklearn 内置数据就能跑通。读完你能拿到一份可复现的实验模板,改几行参数就能套到自己的数据集上。
2. 模式识别实验的最小可运行骨架:数据、特征、分类器三件套
2.1 为什么选 sklearn 而不是从零手写算法
模式识别实验的核心目的是验证你对分类边界、特征空间、评估指标的理解,不是让你手写 SMO 算法。常见做法是用 sklearn 提供的datasets模块加载标准数据集,用train_test_split划分训练测试集,用StandardScaler做特征标准化,再调用SVC、RandomForestClassifier或KNeighborsClassifier完成分类。这样代码量控制在 80 行以内,你能把精力放在调参和结果分析上。
如果你确实需要手写算法(比如课程要求实现感知机或 Fisher 线性判别),sklearn 的BaseEstimator和ClassifierMixin可以让你自定义分类器并复用fit/predict/score接口。但第一版实验代码,我强烈建议先用现成分类器跑通全流程,再替换核心算法。
2.2 环境配置:vscode python 环境配置与依赖安装
先确认 Python 版本。打开终端执行:
python --version如果低于 3.9,建议去 python 官网下载 3.10 或 3.11。Windows 用户安装时勾选「Add Python to PATH」,否则后面 vscode 找不到解释器。
创建虚拟环境并安装依赖:
python -m venv pr_env # Windows pr_env\Scripts\activate # macOS / Linux source pr_env/bin/activate pip install scikit-learn matplotlib numpy pandas如果你在 linux 系统安装 python 后 pip 指向了系统自带版本,用python -m pip install代替pip install可以避免装错位置。vscode 里按Ctrl+Shift+P,输入「Python: Select Interpreter」,选中pr_env下的 python 可执行文件。
提示:国内网络环境下 pip 安装 sklearn 可能超时,加
-i https://pypi.tuna.tsinghua.edu.cn/simple换源。不要用sudo pip,会污染系统环境。
2.3 完整可运行代码:鸢尾花分类实验
下面这份代码可以直接复制到pr_experiment.py运行。它完成了数据加载、标准化、SVM 分类、混淆矩阵绘制和决策边界可视化。
# pr_experiment.py # 模式识别实验:鸢尾花数据集分类与可视化 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from sklearn.metrics import classification_report, confusion_matrix, accuracy_score from matplotlib.colors import ListedColormap # 1. 加载数据 iris = datasets.load_iris() X = iris.data[:, [2, 3]] # 只取花瓣长度和宽度两个特征,方便二维可视化 y = iris.target # 2. 划分训练集和测试集,固定随机种子保证可复现 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42, stratify=y ) # 3. 特征标准化 scaler = StandardScaler() X_train_std = scaler.fit_transform(X_train) X_test_std = scaler.transform(X_test) # 4. 训练 SVM 分类器 clf = SVC(kernel='rbf', C=1.0, gamma=0.5, random_state=42) clf.fit(X_train_std, y_train) # 5. 预测与评估 y_pred = clf.predict(X_test_std) print("准确率: %.4f" % accuracy_score(y_test, y_pred)) print("\n分类报告:") print(classification_report(y_test, y_pred, target_names=iris.target_names)) print("\n混淆矩阵:") print(confusion_matrix(y_test, y_pred)) # 6. 绘制决策边界 def plot_decision_regions(X, y, classifier, test_idx=None): markers = ('o', 's', '^') colors = ('red', 'blue', 'lightgreen') cmap = ListedColormap(colors[:len(np.unique(y))]) x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1 x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, 0.02), np.arange(x2_min, x2_max, 0.02)) Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T) Z = Z.reshape(xx1.shape) plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap) plt.xlim(xx1.min(), xx1.max()) plt.ylim(xx2.min(), xx2.max()) for idx, cl in enumerate(np.unique(y)): plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha=0.8, c=colors[idx], marker=markers[idx], label=iris.target_names[cl], edgecolor='black') if test_idx: X_test_plot = X[test_idx, :] plt.scatter(X_test_plot[:, 0], X_test_plot[:, 1], c='none', edgecolor='black', alpha=1.0, linewidth=1, marker='o', s=100, label='测试集') X_combined_std = np.vstack((X_train_std, X_test_std)) y_combined = np.hstack((y_train, y_test)) plot_decision_regions(X_combined_std, y_combined, classifier=clf, test_idx=range(len(y_train), len(y_combined))) plt.xlabel('花瓣长度(标准化)') plt.ylabel('花瓣宽度(标准化)') plt.legend(loc='upper left') plt.title('SVM 分类决策边界(RBF 核)') plt.tight_layout() plt.savefig('decision_boundary.png', dpi=150) plt.show()逻辑说明:第 1 步只取两个特征是为了画二维决策边界,如果你要做完整特征实验,把X = iris.data[:, [2, 3]]改成X = iris.data即可。第 2 步的stratify=y保证训练集和测试集中各类样本比例一致,避免某类样本全被分到一边。第 3 步标准化必须用训练集的均值和方差去变换测试集,否则测试集信息泄露。第 4 步C控制惩罚力度,gamma控制 RBF 核的影响范围,这两个参数是 SVM 实验最常调的。第 6 步的plot_decision_regions函数用网格点预测画出分类边界,测试集用空心圆标出。
参数说明:test_size=0.3表示 30% 做测试,150 个样本中测试集 45 个。random_state=42固定后每次划分结果相同。C=1.0是默认值,增大 C 会减少训练误差但可能过拟合。gamma=0.5是手动指定的,gamma='scale'会按特征数自动计算。dpi=150控制保存图片的清晰度。
运行后你会看到终端输出准确率和分类报告,同时弹出决策边界图并保存为decision_boundary.png。如果 matplotlib 中文显示为方框,在代码开头加:
plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = FalseWindows 用SimHei,macOS 用Arial Unicode MS,Linux 用WenQuanYi Micro Hei。
3. 换数据集与调参:把实验模板套到自己的数据上
3.1 加载自定义 CSV 数据集
课程实验常要求用自己采集或老师提供的数据。假设你有一个data.csv,最后一列是标签,前面是特征:
import pandas as pd from sklearn.preprocessing import LabelEncoder df = pd.read_csv('data.csv') X = df.iloc[:, :-1].values y = df.iloc[:, -1].values # 如果标签是字符串,转成数字 le = LabelEncoder() y = le.fit_transform(y)然后替换掉鸢尾花加载那两行即可。注意检查缺失值:df.isnull().sum(),有缺失就用SimpleImputer填充,不要直接删样本,除非缺失比例很低。
3.2 用 GridSearchCV 自动搜参
手动调 C 和 gamma 效率低,用网格搜索:
from sklearn.model_selection import GridSearchCV param_grid = { 'C': [0.1, 1, 10, 100], 'gamma': [0.001, 0.01, 0.1, 1, 'scale'], 'kernel': ['rbf', 'linear'] } grid = GridSearchCV(SVC(), param_grid, cv=5, scoring='accuracy', n_jobs=-1) grid.fit(X_train_std, y_train) print("最佳参数:", grid.best_params_) print("交叉验证准确率: %.4f" % grid.best_score_)cv=5表示 5 折交叉验证,n_jobs=-1用满所有 CPU 核心。搜索完成后用grid.best_estimator_拿到最佳模型,直接预测测试集。
3.3 多分类器对比实验
模式识别实验通常要求对比至少三种方法。下面这段代码把 KNN、决策树、随机森林、SVM 放在一起跑:
from sklearn.neighbors import KNeighborsClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier classifiers = { 'KNN (k=5)': KNeighborsClassifier(n_neighbors=5), '决策树': DecisionTreeClassifier(max_depth=3, random_state=42), '随机森林': RandomForestClassifier(n_estimators=100, random_state=42), 'SVM (RBF)': SVC(kernel='rbf', C=1.0, gamma=0.5, random_state=42) } results = {} for name, clf in classifiers.items(): clf.fit(X_train_std, y_train) y_pred = clf.predict(X_test_std) acc = accuracy_score(y_test, y_pred) results[name] = acc print(f"{name}: 准确率 = {acc:.4f}") # 画柱状图对比 plt.figure(figsize=(8, 5)) plt.bar(results.keys(), results.values(), color=['#4C72B0', '#DD8452', '#55A868', '#C44E52']) plt.ylabel('测试集准确率') plt.title('不同分类器在鸢尾花数据集上的表现') plt.ylim(0.8, 1.05) for i, (k, v) in enumerate(results.items()): plt.text(i, v + 0.005, f'{v:.3f}', ha='center') plt.tight_layout() plt.savefig('classifier_comparison.png', dpi=150) plt.show()这段代码的输出可以直接放进实验报告的「结果与分析」章节。注意决策树和随机森林对特征缩放不敏感,但 KNN 和 SVM 必须标准化,所以统一用X_train_std没问题。
4. 避坑与排查:模式识别实验代码翻车的五个高频现场
4.1 现象:sklearn 安装报错「No module named 'sklearn'」
原因:包名和导入名不一致。安装用pip install scikit-learn,导入用import sklearn。很多人pip install sklearn装了一个空壳包,实际没有算法模块。
解决:先pip uninstall sklearn卸载错误包,再pip install scikit-learn。如果还报错,检查虚拟环境是否激活,vscode 右下角解释器是否选对。
4.2 现象:准确率每次运行都不一样
原因:没有固定随机种子。train_test_split、SVC、RandomForestClassifier都有随机成分。
解决:在所有涉及随机的函数里加random_state=42。另外np.random.seed(42)可以固定 numpy 的随机状态。如果用了GridSearchCV,它内部的cv划分也受随机影响,给GridSearchCV传random_state不一定生效,更稳妥的是用StratifiedKFold(shuffle=True, random_state=42)作为cv参数。
4.3 现象:混淆矩阵全是对角线,但分类报告里某类 recall 为 0
原因:类别不平衡。比如 90 个 A 类、10 个 B 类,分类器全预测 A 也能拿 90% 准确率,但 B 类完全没识别出来。
解决:看classification_report的macro avg和weighted avg,不要只看准确率。用class_weight='balanced'让分类器自动加权,或者用 SMOTE 过采样少数类。实验报告里要专门讨论这个问题,这是加分项。
4.4 现象:matplotlib 绘图窗口不弹出,或保存的图片是空白
原因:vscode 的 Python 插件默认用交互式窗口,有时后端冲突。或者plt.show()之前调用了plt.savefig()但没指定bbox_inches='tight',导致边缘被裁。
解决:在代码最前面加import matplotlib; matplotlib.use('TkAgg')。如果是在服务器上跑没有图形界面,用matplotlib.use('Agg')只保存不显示。保存图片时用plt.savefig('xxx.png', dpi=150, bbox_inches='tight')。
4.5 现象:测试集准确率远高于交叉验证准确率
原因:数据泄露。常见于先对整个数据集做标准化再划分训练测试集,或者用测试集调参。
解决:标准化必须fit在训练集上,transform在测试集上。调参用交叉验证在训练集内部做,测试集只在最后评估用一次。如果你发现测试集准确率 99% 而交叉验证只有 85%,大概率是泄露了。
5. 让实验代码更抗造:从「能跑」到「可复现」的三个习惯
5.1 用 Pipeline 把预处理和分类器串起来
前面代码里标准化和分类器是分开写的,容易在交叉验证时泄露。用Pipeline可以避免:
from sklearn.pipeline import Pipeline pipe = Pipeline([ ('scaler', StandardScaler()), ('clf', SVC(kernel='rbf', C=1.0, gamma=0.5, random_state=42)) ]) pipe.fit(X_train, y_train) # 注意这里传原始 X_train,不需要手动标准化 y_pred = pipe.predict(X_test) print("Pipeline 准确率: %.4f" % accuracy_score(y_test, y_pred))Pipeline 在交叉验证的每一折内部只对训练部分做fit_transform,对验证部分做transform,彻底杜绝泄露。这是我在实际项目里踩过坑之后养成的习惯,实验代码也建议这么写。
5.2 固定随机种子并记录环境版本
在实验代码开头加一段环境记录:
import sklearn, numpy, pandas, matplotlib print(f"sklearn: {sklearn.__version__}") print(f"numpy: {numpy.__version__}") print(f"pandas: {pandas.__version__}") print(f"matplotlib: {matplotlib.__version__}")把输出复制到实验报告的「实验环境」小节。不同版本的 sklearn 默认参数可能不同,比如SVC的gamma默认值在旧版本是'auto',新版本是'scale'。记录版本号能让你三个月后还能复现自己的结果。
5.3 用 joblib 保存训练好的模型
实验做完把模型存下来,下次直接加载,不用重新训练:
import joblib joblib.dump(pipe, 'svm_model.pkl') # 加载 loaded_model = joblib.load('svm_model.pkl') print("加载模型准确率: %.4f" % accuracy_score(y_test, loaded_model.predict(X_test)))注意保存的是 Pipeline 对象,加载后直接predict原始特征即可,标准化步骤已经包含在 Pipeline 里。如果只保存了SVC对象而没保存StandardScaler,加载后预测新数据会得到完全错误的结果——这个坑我踩过,排查了一下午才发现是标准化没跟上。
5.4 一个具体技巧:用决策边界图判断过拟合
把训练集和测试集的决策边界画在一起,如果边界在训练集上非常曲折、在测试集上错误率明显更高,就是过拟合。具体做法是分别用X_train_std和X_test_std调用plot_decision_regions,对比两张图。SVM 的C越大边界越复杂,gamma越大边界越围绕样本点。我一般会先跑C=1, gamma='scale'作为基线,然后逐步增大 C 到 10、100,观察测试集准确率是先升后降还是持续下降。如果持续下降,说明数据本身线性可分性差,换核函数或换分类器比继续调参更有效。
最后说一个我自己的习惯:每次跑实验前先print(X.shape)和print(np.bincount(y)),确认样本数和类别分布。这个动作花不了三秒,但能避免把标签列当成特征、把字符串标签直接喂给分类器这类低级错误。模式识别实验的代码不难,难的是细节不出错。希望帮到你。
本文还有配套的精品资源,点击获取