ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

机器学习课程设计实战:从梯度下降到PCA的完整代码解析与调优指南

机器学习课程设计实战:从梯度下降到PCA的完整代码解析与调优指南 简介面向机器学习期末大作业与课程设计场景的完整项目合集包含配套实验报告与源码适合高校学生、自学者快速上手。压缩包共十五个文件其中十个是使用Python语言编写的脚本代码覆盖分类、回归、聚类等基础实验模块同时还配有CSV格式的数据文件、data格式的原始数据、txt说明文档以及Word格式的实验报告压缩包总体积仅为2.94MB部署门槛低下载后简单配置即可运行。预览显示其与西电机器学习大作业相关包含多个实验子项目代码注释充分结构清晰新手也能读懂便于对照实现思路与撰写实验报告。目前已有382人浏览/学习这份合集对于备战期末大作业、课程设计或需要参考高分范本的同学可直接借鉴其整体框架和细节实现节省大量从零搭建的时间。1. 从西电机器学习大作业合集开始这套代码覆盖了期末要考的大部分重点很多人在期末周下载了西电机器学习大作业合集解压后面对一堆 C4-1.py、C7-1.py 和 data 文件夹不知道先跑哪个。这个合集的价值不在代码量而在目录结构本身就映射了机器学习课程最常见的实验路线线性回归、逻辑回归、分类器对比、SVM、聚类、PCA 和神经网络。每个 Cx-y.py 对应第 x 章的第 y 个实验代码里带了较完整的注释配套的实验报告把推导和结果分析也补全了所以它既可以当期末大作业的模板也可以作为课程设计复现的参考。适合能看懂基础 Python 但需要一份可运行代码撑起报告的读者。这套东西拿来直接交差是下策真正值得做的是把每个文件拆开弄清梯度下降在哪收敛、评估矩阵为什么用 F1、聚类的 K 是依据什么定的这些正是答辩时会被追问的点。2. 环境搭建与工程结构先跑通 C2-1把线性回归的梯度下降调起来2.1 从目录命名反推实验安排解压后先看目录不要急着双击运行。典型的目录结构如下西电机器学习大作业.zip ├── code-master │ └── MLHomework │ ├── C2-1.py │ ├── C3-1.py │ ├── C4-1.py │ ├── C4-2.py │ ├── C4-3.py │ ├── C5-1.py │ ├── C6-1.py │ ├── C6-2.py │ ├── C7-1.py │ └── C8-1.py ├── data └── 机器学习实验报告.docx文件名格式 Cx-y.py 暗示了它是第 x 章的第 y 个作业这种命名方式在很多学校的机器学习课程里都能看到。下面这张表是根据常见教学大纲做的推断具体某个 py 对应什么实验以实验报告里的目录为准。文件名常见对应实验主要依赖C2-1.py线性回归与梯度下降numpy, matplotlibC3-1.py逻辑回归与决策边界sklearn, numpyC4-1.py ~ C4-3.py分类器对比KNN/决策树/朴素贝叶斯sklearnC5-1.py支持向量机与核函数sklearnC6-1.py / C6-2.py神经网络或集成学习sklearn / tensorflowC7-1.pyKMeans 聚类sklearnC8-1.pyPCA 降维sklearn, matplotlib实际运行时data 目录会通过相对路径被多个脚本引用所以不要单独把某个 py 文件拖到桌面运行最好保持原始目录不动。建议先花十分钟浏览实验报告把每个 py 对应的小节标题标出来再决定从哪个文件开始。2.2 用虚拟环境隔离依赖这份代码用到的库比较常规但不同 py 文件可能依赖不同版本的 sklearn 和 matplotlib直接用系统 Python 跑容易遇到冲突。我一般会为它单独建一个虚拟环境python -m venv mlhw source mlhw/bin/activate # Windows 下执行 mlhw\Scripts\activate pip install --upgrade pip pip install numpy pandas scikit-learn matplotlib如果你的实验里有 C6 系列是用 TensorFlow 写的还要额外装 tensorflow这时注意 Python 版本不要高于 3.11否则某些旧版 TF 会直接拒绝导入。装完后用python -c import sklearn; print(sklearn.__version__)验证一下sklearn 版本在 1.0 到 1.3 之间大概率不会踩到函数签名变更的坑。2.3 跑通 C2-1线性回归的最小批量梯度下降C2-1 一般是第一个要跑的实验因为它只依赖 numpy 和 matplotlib逻辑最直白。下面这段代码是 C2-1.py 核心逻辑的整理版用全批量梯度下降拟合带噪声的线性数据import numpy as np # 生成带噪声的线性数据 rng np.random.default_rng(42) x rng.uniform(-3, 3, 200).reshape(-1, 1) true_w, true_b 1.7, -0.4 y true_w * x true_b rng.normal(0, 0.5, sizex.shape) # 特征标准化让梯度下降收敛更快更稳 x_mean, x_std x.mean(), x.std() x_norm (x - x_mean) / x_std X np.column_stack([np.ones_like(x_norm), x_norm]) lr, epochs 0.1, 1000 w np.zeros((2, 1)) m len(y) for epoch in range(epochs): y_pred X w # 预测值 grad (1 / m) * X.T (y_pred - y) # 损失对参数的梯度 w - lr * grad if epoch % 200 0: loss np.mean((y_pred - y) ** 2) print(fepoch {epoch:4d} loss {loss:.4f}) # 标准化是线性变换系数可以还原到原尺度 w1_unnorm w[1, 0] / x_std w0_unnorm w[0, 0] - w1_unnorm * x_mean print(f真实 w{true_w[0]:.3f} b{true_b:.3f} f预测 w{w1_unnorm:.3f} b{w0_unnorm:.3f})这里最关键的是特征标准化。如果不做标准化x 的取值范围是 -3 到 3而偏置项对应常数 1两个维度量纲不一致梯度下降很容易震荡。学习率 lr 设 0.1 在标准化后是安全的但如果数据方差特别大可以降到 0.01 再观察 loss 曲线。矩阵表达式X.T (y_pred - y)是一次算出所有样本的梯度等价于对每个参数做偏导的均值。loss 每 200 轮打印一次如果最后两行数值接近说明收敛正常。2.4 常见报错和排错跑这份作业时最常遇到三个问题。第一个是ModuleNotFoundError: No module named sklearn说明虚拟环境没激活或者依赖没装全回去执行pip install scikit-learn。第二个是FileNotFoundError因为 py 文件里直接用了data/xxx.csv这种相对路径而运行目录不在 code-master 下。一个稳妥的改法是让路径基于脚本所在目录定位import os base_dir os.path.dirname(os.path.abspath(__file__)) data_path os.path.join(base_dir, .., data, xxx.csv)第三个是 matplotlib 中文乱码。实验报告里如果用到plt.title(损失曲线)这类中文标题先设置字体plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False除了这些还要留意 sklearn 老代码里train_test_split(test_size0.3)的随机种子问题新版如果 stratify 参数没配跑出的训练测试划分每次都不一样实验报告里截图和代码输出对不上会被认为结果不可复现。建议在每个 py 文件开头统一加上random_state42。3. 分类器实验拆解C3-1 的决策边界与 C4 系列的评估矩阵3.1 C3-1逻辑回归的决策边界可视化逻辑回归不只是一个分类模型它本质上是先用线性加权求 z再通过 sigmoid 函数把 z 压缩到 0 和 1 之间输出的是正类概率。许多同学的误区是只看最终分类结果忽略了predict_proba给出的概率值。实验报告里如果能画出概率等高的决策边界比单纯输出一个 accuracy 分数要有说服力得多。from sklearn.datasets import make_classification from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split import numpy as np import matplotlib.pyplot as plt X, y make_classification(n_samples300, n_features2, n_redundant0, n_clusters_per_class1, random_state42) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42) # C 是正则化强度的倒数C 越小正则化越强 clf LogisticRegression(C1.0, solverlbfgs, max_iter500) clf.fit(X_train, y_train) # 构造网格画预测概率的等高线 xx, yy np.meshgrid( np.linspace(X[:, 0].min() - 1, X[:, 0].max() 1, 200), np.linspace(X[:, 1].min() - 1, X[:, 1].max() 1, 200) ) Z clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1] Z Z.reshape(xx.shape) plt.contourf(xx, yy, Z, levels20, cmapRdBu_r, alpha0.6) plt.scatter(X[:, 0], X[:, 1], cy, edgecolork, s20) plt.title(Logistic Regression Decision Boundary) plt.colorbar() plt.savefig(C3-1_boundary.png, dpi150)参数里solverlbfgs适合中小数据集它不需要设置学习率但迭代次数受max_iter限制如果反正不收敛就把 max_iter 提到 1000。levels20控制等高线分段数分段越多颜色过渡越细。predict_proba输出的是形状为 (n_samples, 2) 的概率矩阵取第二列代表正类概率。报告里可以写一句决策边界附近样本的概率都在 0.5 附近说明分类器在这些区域置信度低。3.2 C4 系列三种分类器的交叉验证对比C4-1、C4-2、C4-3 三个文件通常是要求在同一个数据集上跑三种不同分类器比较准确率和稳定性。常见组合是决策树、KNN 和高斯朴素贝叶斯。这里用 sklearn 自带鸢尾花数据演示一个可复用的对比框架from sklearn.tree import DecisionTreeClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.naive_bayes import GaussianNB from sklearn.model_selection import cross_val_score, GridSearchCV from sklearn.datasets import load_iris X, y load_iris(return_X_yTrue) classifiers { decision_tree: DecisionTreeClassifier(random_state42), knn: KNeighborsClassifier(), gaussian_nb: GaussianNB(), } for name, clf in classifiers.items(): scores cross_val_score(clf, X, y, cv10, scoringaccuracy) print(f{name:14s} accuracy {scores.mean():.4f} ± {scores.std():.4f}) # 对 KNN 做网格搜索选出 n_neighbors 和 weights grid { n_neighbors: [3, 5, 7, 9], weights: [uniform, distance], } gs GridSearchCV(KNeighborsClassifier(), grid, cv5) gs.fit(X, y) print(gs.best_params_, gs.best_score_)决策树不需要特征标准化但 KNN 基于距离计算如果特征量纲不同数值范围大的特征会主导距离导致分类结果被某个无关特征带偏。交叉验证的 cv10 表示把数据切 10 份轮流拿 1 份当验证集最后输出 10 轮分数的均值和标准差。均值高说明模型整体强标准差小说明模型对数据划分不敏感这两个数字在报告中要一起写不能只看 mean 忽略 std。网格搜索输出的best_params_就是调参过程的可复现依据。3.3 评估矩阵与 ROC 曲线很多课程设计只要求输出正确率但期末答辩时老师常追着问精确率和召回率的区别。下面这张表是从代码里直接读含义最快的方式指标公式含义使用场景Accuracy(TPTN)/(TPFPTNFN)类别平衡时适合PrecisionTP/(TPFP)误报代价高的场景RecallTP/(TPFN)漏报代价高的场景F1-score2PR/(PR)样本不均衡时综合评估AUCROC 曲线下面积对排序敏感衡量区分度在 C4 系列实验里建议在对比完准确率之后再对最优模型输出一份classification_reportfrom sklearn.metrics import classification_report, roc_auc_score y_pred gs.predict(X) print(classification_report(y, y_pred, target_names[setosa, versicolor, virginica]))分类报告会针对每个类别输出 precision、recall 和 f1-score。在多分类任务里要注意宏观平均和加权平均的区别前者是每个类别的算术均值后者按样本量加权。实验报告里如果数据不平衡一定要明确写用的是哪种平均方式。3.4 报告里的图表规范从这份合集的实验报告 docx 能看出高分作业的共性不是代码多复杂而是图表规范。每张图都要有标题、坐标轴标签、图例颜色不要用默认的红色绿色堆在一起。保存图片时用bbox_inchestight去掉多余留白分辨率设 150 到 300plt.savefig(C4_compare.png, dpi300, bbox_inchestight, facecolorwhite)如果是对比实验三张子图的纵轴范围必须一致否则视觉上放大的波动会误导读者。这里被问到的概率很高建议在图下面补一段文字说明为什么这个模型在这个数据集上表现更好是数据线性可分还是模型假设更匹配。4. 回归到聚类C5-1 到 C8-1 的参数调优与实验串联4.1 C5-1SVM 的核函数选择与网格搜索SVM 是 C5 系列的核心很多人的代码能跑但回答不了为什么选 rbf 核。SVM 的基本思想是找最大间隔超平面当数据线性不可分时核函数把原始特征映射到高维空间让样本在高维变得线性可分。linear 核适合特征维度高、样本量小的情况rbf 核是默认选择因为它只依赖两个超参数 C 和 gammapoly 核容易过拟合并且计算慢数据量大的时候不建议优先尝试。下面是一个完整的网格搜索框架from sklearn.svm import SVC from sklearn.model_selection import GridSearchCV from sklearn.datasets import make_moons X, y make_moons(n_samples200, noise0.15, random_state42) param_grid { kernel: [linear, rbf, poly], C: [0.1, 1, 10], gamma: [scale, auto], } svm SVC(probabilityTrue, random_state42) gs GridSearchCV(svm, param_grid, cv5, scoringaccuracy) gs.fit(X, y) print(Best params:, gs.best_params_) print(Best score:, gs.best_score_)C是误分类惩罚系数C 越大模型对每个训练样本的分类要求越严格边界越窄也越容易过拟合。gamma控制单个训练样本的影响半径scale会自动根据特征数量做缩放auto直接用 1/特征数。网格搜索会暴力组合上面参数的每一种取值在 5 折交叉验证下分别跑 5 次最终选出平均分最高的一组。对小样本数据rbf 核加 C1 通常是稳健起点。4.2 C6 系列MLP 与随机森林的对比C6-1 和 C6-2 在不同学校的课程里可能对应神经网络也可能对应集成学习。这里用一个通用的对比方式处理把 MLP 和随机森林放在同一个分类任务上比较 f1-macro 分数。MLP 代表深度模型的基本形态随机森林代表 Bagging 集成思路。from sklearn.neural_network import MLPClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score X, y make_classification(n_samples500, n_features10, n_informative6, n_redundant2, random_state42) mlp MLPClassifier( hidden_layer_sizes(32, 16), max_iter300, alpha1e-4, random_state42 ) rf RandomForestClassifier(n_estimators200, max_depth6, random_state42) for model in (mlp, rf): score cross_val_score(model, X, y, cv5, scoringf1_macro).mean() print(f{model.__class__.__name__:22s} f1_macro {score:.4f})MLP 对特征缩放非常敏感所以使用 MLP 之前必须做标准化而随机森林不需要。hidden_layer_sizes(32, 16)表示两个隐藏层神经元数分别为 32 和 16这个结构在小数据集上已经能拟合复杂边界。alpha1e-4是 L2 正则化系数防止隐藏层过多时过拟合。随机森林的n_estimators200是树的数量太多会增加计算时间但不会显著提升效果max_depth6限制每棵树深度也是防止单棵树过拟合。如果实验报告要求画训练过程MLP 可以保存损失曲线mlp.fit(X, y) plt.plot(mlp.loss_curve_) plt.xlabel(iteration) plt.ylabel(loss) plt.savefig(C6_mlp_loss.png, dpi150)loss_curve_是 MLP 每轮迭代后的损失值列表长度不会超过 max_iter。曲线如果突然上升再下降说明学习率偏大如果一直平缓下降且最后趋于平缓说明训练充分。4.3 C7-1KMeans 肘部法则与轮廓系数KMeans 聚类是 C7-1 的核心。聚类这个实验最容易被问的问题就是K 为什么选 3如果回答老师说的或者看着像 3 类肯定拿不到高分。正确做法是用肘部法则配合轮廓系数共同决策from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score from sklearn.preprocessing import StandardScaler from sklearn.datasets import load_iris import numpy as np X, _ load_iris(return_X_yTrue) X_s StandardScaler().fit_transform(X) inertias, silhouettes [], [] for k in range(2, 9): km KMeans(n_clustersk, n_init10, random_state42) labels km.fit_predict(X_s) inertias.append(km.inertia_) silhouettes.append(silhouette_score(X_s, labels)) print(k, list(range(2, 9))) print(inertia, np.round(inertias, 2)) print(silhouette, np.round(silhouettes, 3))inertia_是样本到最近簇中心的平方距离之和K 越大惯性矩越小但下降速度会在某个 K 之后变缓形成肘点。silhouette_score衡量每个样本与自身簇的紧密程度和与最近其他簇的分离程度取值在 -1 到 1 之间越接近 1 说明聚类效果越好。选择 K 时先看惯性矩肘点再看轮廓系数在哪个 K 取得局部最大值两个方法指向同一个 K报告里就可以写肘部法则显示 K3 之后下降趋缓轮廓系数在 K3 时最高因此选择 3。n_init10表示用 10 组不同的初始质心分别运行取最优结果避免陷入局部最优。4.4 C8-1PCA 降维与分类器联动C8-1 一般是 PCA 降维实验。PCA 做的事情是把原始高维特征投影到一组互相正交的新坐标系上新坐标按方差从大到小排列。高方差方向通常代表数据的主要结构低方差方向往往是噪声。实验里最常见的是把 PCA 和分类器串联先降维再分类观察精度变化。from sklearn.decomposition import PCA from sklearn.neighbors import KNeighborsClassifier from sklearn.pipeline import Pipeline pca PCA(n_components2, random_state42) knn KNeighborsClassifier(n_neighbors5) pipe Pipeline([ (pca, pca), (knn, knn) ]) pipe.fit(X_s, y) print(explained variance ratio:, pca.explained_variance_ratio_) print(total explained:, pca.explained_variance_ratio_.sum()) print(pipeline accuracy:, pipe.score(X_s, y))explained_variance_ratio_是每个主成分解释的方差比例sum()得到前两个主成分总共保留的信息量。如果这个值低于 70%说明降到 2 维损失过大可视化虽然方便但分类精度会明显下降。报告里建议同时给出累计方差曲线和降维后的散点图并配合一句分析前两个主成分保留了约 95% 的方差因此用 2 维 PCA 代替原始 4 维特征是合理的。5. 用实验报告反推满分作业的写法以及提交前必做的五项验证5.1 从实验报告 docx 里提取写作框架打开机器学习实验报告.docx不要逐字复制先看目录结构。高分报告的骨架通常是实验目的、实验环境、算法原理、核心代码、结果分析、思考题。其中算法原理要写公式不能只贴名词结果分析要带截图并且每张截图下面都有至少两句话的解释。这份合集里的代码注释已经覆盖了大部分为什么这样设参数的说明写报告时把注释里强调的 C、gamma、n_neighbors、n_clusters 这些超参数单独列出来解释它们的物理含义和调整方向就是最扎实的得分点。5.2 提交前必做的五项验证第一解压到全新目录在 MLHomework 目录下依次执行所有 py 文件确保没有FileNotFoundError和ModuleNotFoundError。可以写一个快速验证脚本for f in C2-1.py C3-1.py C4-1.py C4-2.py C4-3.py C5-1.py C6-1.py C6-2.py C7-1.py C8-1.py; do echo running $f python $f || break done第二检查生成的图表路径plt.savefig保存的图片要保证在报告同目录下不要出现绝对路径。第三核对实验报告里的数值和代码输出是否一致比如 loss 最后几轮的数字、grid search 的 best_params_不一致会被认为造假。第四把当前环境依赖导出到 requirements.txt方便答辩时复现pip freeze requirements.txt第五用grep -n random_state *.py检查所有脚本是否固定随机种子没有固定的话多跑一次结果可能就不一样这会直接影响实验报告里的截图可信度。这五项验证做完再打包提交才能在答辩时保证现场跑出来的结果和你报告里写的一致。本文还有配套的精品资源点击获取
返回列表