机器学习大作业六次合集:从建模闭环到可复现项目实战
简介面向机器学习期末大作业与课程设计场景这份合集覆盖KNN手写数字识别、回归模型、参数估计与非参数估计、朴素贝叶斯分类器、层次聚类、决策树分类器六类典型任务代码与实验报告配套完整适合需要快速完成课程项目并争取高分的本科生及自学者。全部源码带注释实验文档说明思路下载后简单配置即可运行可作为课程设计或期末大作业的完整参考方案。压缩包共340个文件、约63.56MB以Python源码、可视化图表、CSV数据集、PDF/Word报告和Jupyter Notebook为主py文件实现算法png展示结果csv提供数据pdf与md记录原理目录与六次作业一一对应。内容覆盖数据准备、模型训练到结果分析全流程实验报告可辅助答辩讲解已有5351人浏览学习适合期末答辩、课程展示或自学复用。1. 把机器学习大作业当成小项目来做为什么六次作业合集能拉开你和周围人的差距很多人的机器学习期末大作业是最后三天赶出来的代码一个 python 文件跑到底跑完就把终端输出截图贴进实验报告图是有了结论没有老师问两句就露馅。而这门课的六次大作业合集恰恰是拉开差距的地方——它不是六个孤立的任务而是把 sklearn、XGBoost、深度学习这些零散知识点串成完整体系的六次机会。每次作业本质上都是一次独立的建模闭环数据清洗、探索分析、模型选型、参数调整、指标评估、实验报告六次走完你就拥有了一套可以迁移到任何表格数据上的方法论。适合谁读呢正在补机器学习期末/课程设计的在校生以及想把期末代码改造成简历项目的准工程师。2. 六次作业的任务拆解分类、回归、聚类、深度学习各考什么先说一个常见误解六次作业不是六个互不相关的题目老师通常是在按“模型家族”设计训练路径。最常见配置是有监督两次一分类一回归、无监督一次聚类加降维、集成学习一次、深度学习一次最后一次做综合性任务。你如果前面五次都用同一套“读数据—拆数据集—建模—评估”的习惯去做最后一次会非常轻松反过来前面每次换一种文件结构、换一种写法最后一次就会在整理上耗费大量时间。2.1 两次有监督建模分类拼指标选择回归拼误差拆解有监督部分的分类作业通常落在鸢尾花、肿瘤数据或垃圾短信这类二分类任务上回归作业则常见房价、电力负荷、温度预测这类连续值问题。这里第一个要分清楚的是指标分类别只报 accuracy必须附上 precision、recall、F1 和混淆矩阵尤其在类别不平衡时 accuracy 会骗人——垃圾短信 95% 是正常短信你全预测成正常短信也有 95% 的准确率这在报告里根本不是满分表现。回归则看 RMSE、MAE 和 R2三个数字要同时给因为 RMSE 对大误差敏感MAE 反映平均偏差R2 说明模型解释了百分之多少的方差。我一般会在第一次有监督作业里就把“对比基线”的规矩立住分类至少跑 KNN、逻辑回归、决策树三个模型回归至少跑线性回归、岭回归、随机森林三个模型然后把你选的最终模型和最简单的基线摆在一起。这一步在老师眼里就是“这人不是来混学分的”第一信号。第二次有监督作业应该复用第一次的代码骨架只换数据集和评估指标然后在报告里讲清楚“为什么同一个流程能处理两类问题”——这就是泛化能力的最好证明。2.2 无监督与降维聚类、PCA、t-SNE噪声数据最容易翻车无监督作业通常是 KMeans 聚类加 PCA 降维很多同学的翻车点在于数据集里明明只有两个类别KMeans 却画出五个簇还硬解释成“合理”。真实业务数据里噪声很常见噪声样本会把聚类中心拉偏这是机器学习里面非常经典的问题。这时候解决套路有三个先用 PCA 看方差累积曲线定降维维数再用轮廓系数而不是“看着顺眼”来选 k最后用 t-SNE 做可视化辅助判断但注意 t-SNE 只适合看不适合用来当特征工程输入因为它每次运行结果都不稳定。轮廓系数选 k 的代码我建议每个同学都存一份import numpy as np from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score from sklearn.datasets import make_blobs # 构造带噪声的示例数据n_features5其中两维是纯噪声 X, _ make_blobs(n_samples800, centers3, n_features5, cluster_std1.2, random_state42) noise np.random.normal(0, 3, size(X.shape[0], 2)) X np.hstack([X, noise]) best_k, best_score 2, -1 for k in range(2, 8): km KMeans(n_clustersk, n_init10, random_state42) labels km.fit_predict(X) score silhouette_score(X, labels) print(fk{k} silhouette{score:.4f}) if score best_score: best_k, best_score k, score print(fbest k{best_k})这段代码最关键的是n_init10和random_state42。KMeans 初始质心是随机的不固定种子每次跑出来的轮廓系数都不一样n_init10表示用十个随机起点取最优这是 sklearn 新版为了避免局部最优的默认做法但很多人并不知道自己在报告里写“KMeans 结果不稳定”然后归咎于数据其实是参数没设对。噪声维度我故意加了两个标准差很大的列你跑出来就会发现最佳 k 大概率不是 3这就是噪声数据对聚类最直观的影响。作业里如果遇到类似情况应该在报告里写“先用 PCA 降维去掉噪声维再聚类”而不是直接堆一个高维矩阵进去。2.3 集成学习与视觉迁移XGBoost 和 MobileNetV2 代码跑通的价值集成学习作业现在基本绕不开 XGBoost 和随机森林。表格数据里 XGBoost 基本就是天花板级别的通用模型你的决策树作业如果只报了 82 分换 XGBoost 很可能直接到 90 分——这不是玄学是 boosting 算法在偏差和方差上的双重优势。写作业的时候提一句“XGBoost 采用加法训练每棵树拟合前一棵树的负梯度”老师就知道你不是只会调包。深度学习部分很多课程作业会出到“猫狗识别”或 CIFAR-10 分类。很多同学的翻车点在电脑是 CPU 机器一个 CNN 从头训练要跑一小时。我的建议是直接用 MobileNetV2 预训练权重做迁移学习理由有三个它体积小CPU 也能在十分钟内跑完预训练权重在 ImageNet 上学过的特征能直接迁移到小数据集报告里可以写“微调最后一层全连接冻结前面所有层”——这是深度学习作业拿高分的一个常见套路。注意你的数据集如果是 32x32 的 CIFAR-10需要先 resize 到 MobileNetV2 要求的 224x224并且归一化方式要跟预训练权重保持一致这个细节漏掉准确率会掉一大截。2.4 最后一次综合作业把前五次串成一条可运行的完整管道最后一门综合作业的常见做法是给一份真实场景数据比如用户行为或传感器日志要求完成“数据清洗—特征工程—模型对比—结果解释”的完整流程。这时候老师最反感的就是代码里五个步骤各写一个文件头尾不互通中间数据格式还对不上。正确做法是拿前两次有监督作业的骨架改造成一个管道统一的load_data()、统一的preprocess()、统一的建模入口换数据集只改配置。你甚至在报告里可以直接写“本作业的预处理与建模流程复用前几次作业的模板”这句话在老师眼里是极强的加分项因为它证明你把这门课的知识连成了体系。3. 代码怎么组织把“一个 py 文件跑到底”改成可复现的项目骨架代码结构决定了老师愿不愿意认真看你的作业也决定了你自己半个月后还能不能看懂。我见过太多期末作业叫final.py、最终版2.py、真最终版3.py里面全是魔法数字和注释掉的旧代码。六次作业合集的价值就在于“复用”所以要在一开始就定好统一的目录模板后面五次作业全部套用。3.1 目录与文件命名六个作业共用一个模板我一般会建这样一个结构每次作业复制一份改名字mkdir -p hw1/{data,src,results,figures} touch hw1/README.md hw1/requirements.txt hw1/run.py目录结构的设计逻辑是data只放原始数据和不经修改的中间产物src放所有模块代码每个模块只做一件事results放模型输出、预测结果和指标 jsonfigures放报告要用的所有图片。run.py是唯一入口老师只要执行python run.py就能从原始数据一路得到指标和图表不需要去猜哪个文件是对的。你可能觉得一个作业才几百行代码分这么细有点小题大做但最后一次综合作业代码量到一千行以上时这个结构能救你一命。README 里至少写三件事数据集来源和字段含义、怎么运行、运行环境版本。requirements.txt 别手写用pip freeze requirements.txt生成虽然会多出不少无关包但保证老师在同样环境能跑起来。写作业是给老师看更是给两周后的自己看——你当时调参时写在代码注释里的“为什么这里要取 log”比任何报告都有价值。3.2 最小可复现的建模脚本以 XGBoost 为例看参数设置这里给出一个可以直接套用的 XGBoost 分类脚本它包含了我认为提交作业前必须有的所有元素固定随机种子、训练验证测试三段切分、早停、指标输出。import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline from xgboost import XGBClassifier from sklearn.metrics import classification_report, roc_auc_score SEED 42 # 假设 data.csv 最后一列是标签 df pd.read_csv(../data/data.csv) X df.drop(columns[target]) y df[target] # 先切出测试集测试集从头到尾不参与任何训练决策 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_stateSEED, stratifyy ) # 再从训练集里切出验证集专门用于早停 X_train, X_val, y_train, y_val train_test_split( X_train, y_train, test_size0.2, random_stateSEED, stratifyy_train ) model XGBClassifier( n_estimators500, max_depth4, learning_rate0.05, subsample0.8, colsample_bytree0.8, random_stateSEED, ) model.fit( X_train, y_train, eval_set[(X_val, y_val)], early_stopping_rounds20, verboseFalse, ) pred model.predict(X_test) print(classification_report(y_test, pred)) print(fROC-AUC: {roc_auc_score(y_test, pred):.4f})三个关键点你要清楚。第一stratifyy在分类任务里必须加否则切分后测试集的类别比例可能和原始数据不一致小数据集上尤其明显。第二max_depth4配learning_rate0.05是保守组合树不深、步子小配合 500 棵树和早停基本不会严重过拟合如果你用默认max_depth6又只跑 100 棵树很容易在验证集上看到分数先升后降。第三早停的eval_set不能用测试集否则你等于拿测试集调参最后的报告数字就失去了说服力。树模型其实对标准化不敏感但我还是会在管道里加StandardScaler原因是让自己习惯统一的建模流程后面遇到线性模型不至于忘。3.3 指标和画图的固定套路混淆矩阵、ROC 和学习曲线报告里图的质量直接影响印象分我不建议截图终端输出应该用代码生成矢量图。下面这段代码保存混淆矩阵和 ROC 曲线到figures目录import matplotlib.pyplot as plt from sklearn.metrics import ( ConfusionMatrixDisplay, RocCurveDisplay, confusion_matrix ) # 混淆矩阵 cm confusion_matrix(y_test, pred) ConfusionMatrixDisplay(cm).plot(cmapBlues) plt.title(fConfusion Matrix | acc{ (pred y_test).mean():.3f }) plt.savefig(../figures/confusion_matrix.png, dpi150, bbox_inchestight) plt.close() # ROC 曲线 RocCurveDisplay.from_estimator(model, X_test, y_test) plt.title(ROC Curve) plt.savefig(../figures/roc_curve.png, dpi150, bbox_inchestight) plt.close()savaefig后一定要plt.close()不然跑多个模型时图会叠加在同一个 figure 上。dpi150是够用的清晰度bbox_inchestight是防止标题被截掉。我见过很多人在报告里贴一张没有标题的图下面写“结果如上”这种图等于没放。图标题里最好直接写结论——“Confusion Matrix | acc0.932”老师扫一眼就知道你从这个图里读出了什么而不是让他替你读。4. 实验报告怎么写才能在批改时拿到高分老师在看什么代码写得好报告写得烂照样拿不到高分。实验报告不是代码注释的拼接也不是把每个人的博客抄一遍。你要站在批改老师的角度想他手上有几十份作业每份只能花十分钟怎么在这十分钟里让“满分项目”这个标签落到你头上答案是结构清晰、有对比、有失败记录、能复现。4.1 报告骨架从“做了什么”到“比较过什么”我推荐的报告结构是一个七段模板摘要、数据说明、基线模型、改进模型、实验对比、失败尝试、结论与复现说明。摘要控制在两百字内说清任务是什么、最终模型是什么、最优指标是多少数据说明写清样本量、特征类型、缺失值处理和类别分布基线模型一定用最简单的方法比如分类用“多数类预测”回归用“均值预测”改进模型再上你的正式算法实验对比用表格呈现失败尝试专门记录翻车过程最后写明随机种子、硬件环境、依赖版本。这七个部分里最容易拉开分差的是“失败尝试”。很多同学只报喜不报忧所有实验看起来都一次成功这反而不可信。我的习惯是写一次真实踩过的坑比如“先用 0.1 的学习率跑 XGBoost验证集 loss 在前 20 轮震荡不降定位到学习率过大后改 0.05配合早停稳定收敛”——这个记录比十页理论推导都有说服力因为它证明你调试过、思考过。4.2 图表与数字的配合每张图都要有结论报告里的每一张图都应该具备“不看正文也能读懂”的独立性。图的标题写结论图例写清楚是哪个模型坐标轴有物理含义和单位同一个对比实验里的图统一坐标系范围。表格则要少而精只放三种模型对比表、参数搜索表、误差分析表。模型对比表每行一个模型列放准确率、F1、训练时间参数搜索表列放参数名、搜索范围、最优值误差分析表列放错误类型、样本数、占比。我见过一份作业把五折交叉验证每一折的数字都贴上去整整两页表格老师根本不想看。正确做法是只报“均值±标准差”比如0.912 ± 0.008然后把五折的数字画成箱线图放附录。表格是用来支撑结论的不是用来凑字数的。4.3 附录里的复现说明让报告经得起现场提问很多课程会有答辩环节老师会现场打开你的代码跑一遍。这个时候最尴尬的情况就是“报告里的数字和当场跑出来的不一样”。我自己的规矩是交作业前一天从零开始重新执行一遍run.py把终端输出完整保存成log.txt放进results报告里的所有数字必须和这份 log 完全一致。环境信息要写在附录里Python 版本、numpy/sklearn/xgboost 版本、操作系统、CPU 还是 GPU——XGBoost 在 CPU 和 GPU 上跑出的浮点结果会有细微差异这一点提前写清楚答辩时老师就没法拿这个挑刺。5. 机器学习作业避坑清单五个最常让满分手翻车的点以下五条是我看作业和帮人调代码时遇到频率最高的问题每一条都对应真实翻车现场。把它们排掉你的作业基本就能从“看起来能跑”上升到“经得起验证”。5.1 数据泄漏验证集分数异常高先怀疑预处理顺序现象测试集上的准确率高得不正常比如真实业务数据 AUC 高达 0.99明显不符合直觉。原因你在切分训练测试集之前就对全量数据做了标准化、缺失值填充或独热编码测试集的信息通过统计量泄漏到了训练过程里。解决所有预处理必须fit在训练集上transform在测试集上sklearn 的 Pipeline 能强制保证这一点。检测方法也简单训练集分数远低于测试集分数或者测试集分数高到离谱就立刻检查有没有泄漏。5.2 随机种子没固定每次跑结果都不一样现象同一个模型、同一份数据昨天跑 88 分今天跑 91 分你都不知道该信哪个。原因XGBoost、随机森林、KMeans 全部有随机性包括数据切分也有随机性不固定random_state一切皆波动。解决在所有可能的地方固定random_state42包括train_test_split、模型构造、KMeans 和 PCA如果你是深度学习的作业还要固定 PyTorch 或 TensorFlow 的全局种子。注意这时候报告里的数字才具有唯一性和可复现性。5.3 报告里的数字和脚本对不上提交前重跑一遍现象老师拿到代码后一跑脚本输出的准确率和你报告里写的差了 3 个百分点答辩当场翻车。原因报告里的数字是三天前某个旧版本跑出来的代码后来改过但没人重新跑一遍更新数据。解决提交前从头到尾执行一次完整流程用输出 log 校验报告里所有图表和指标如果报告里的图和代码生成的图对不上就重新截图重新插入。这是一道纯流程题不需要任何机器学习知识但大量满分项目就是死在这一步。5.4 数据集不到一千条还硬上深度模型loss 不降是必然现象深度学习作业里你自己写了一个五层 CNN在几百条样本的数据集上训练loss 怎么调都不降。原因数据量根本喂不饱一个带几万参数的模型特征没学出来梯度在深层网络里也很难稳定传播。解决先看样本量小于一万条就优先用预训练模型做迁移学习或者在报告里如实写“数据量不足改用 XGBoost 作为最终方案”——把模型选择理由写清楚比硬凹一个深度学习模型更有说服力。如果老师规定了必须用深度学习用 MobileNetV2 预训练权重微调是最省算力的路子注意输入图像尺寸要跟模型要求一致。5.5 调参靠玄学没有验证集调着调着就过拟合了现象模型在训练集上 98 分测试集上 80 分差距巨大。原因你在全量训练集上反复调参模型已经被你“记住”了数据的特定模式而你没有一块独立的验证集来观察真实的泛化趋势。解决把数据切成训练、验证、测试三份早停和参数搜索只在验证集上看结果测试集最后只用一次出一个最终数字写进报告。这一点在机器学习里面叫“避免测试集泄漏”比数据预处理泄漏更容易被忽略但后果一样严重。6. 把六次作业变成作品集一个能当面试佐证的验收方法课程结束后六次作业的全部代码和报告不要删压缩打包存好这是你简历上“机器学习项目经验”的第一手素材。但我见过太多人存完就再也不打开半年后问他项目细节他已经说不出 XGBoost 里colsample_bytree是干什么的了。所以这里给你一个具体的验收方法把六次作业里的建模流程抽象成一个通用入口换成任何一份新数据集半小时内跑出基线结果。我习惯在每个项目文件夹里留一个run_baseline.py内容是一个通用函数def run_baseline(df_path, target_col, taskclassification, seed42): df pd.read_csv(df_path) X df.drop(columns[target_col]) y df[target_col] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_stateseed ) if task classification: model XGBClassifier(random_stateseed) else: model XGBRegressor(random_stateseed) model.fit(X_train, y_train) print(f{task} baseline score: {model.score(X_test, y_test):.4f})这个函数本身很粗糙但它定义了一个好习惯每份新数据来了第一步永远是跑出一个可比较的基线而不是直接上复杂模型。你把六次作业里的数据处理、可视化、调参记录都整理到对应的 README 里半年后再打开时不靠回忆也能快速捡起来这就是这份大作业合集真正的长期价值。我自己的血泪经验是毕业找工作时面试官根本不关心你期末作业得了多少分但他会问你“这个项目里你遇到的最大困难是什么”。如果你当时在报告里留了失败尝试的记录你就能脱口而出如果你当时只贴了满分的图你就会卡壳。所以六次作业的最后一次提交请你认真写一次失败记录——那是给未来的自己留的后悔药。希望这些整理和踩坑经验能帮到你让你这门课的成绩和工作简历都好看一点。本文还有配套的精品资源点击获取