简介:这份资源是机器学习期末大作业的六次作业合集,面向高校学生、课程设计者及需要快速完成机器学习实践任务的学习者,涵盖从基础分类到概率建模的完整实验链路。包内共340个文件,以109个Python源码、107张结果图、22份CSV数据集为主,辅以13份PDF实验报告、10份Markdown说明及少量R脚本、Jupyter笔记本与PPT,压缩包约63.56MB,结构清晰便于按项目检索。六次作业分别对应基于KNN的手写数字识别、回归模型、参数估计与非参数估计、朴素贝叶斯分类器、层次聚类和决策树分类器,每项均含源码与实验报告,代码附有注释,新手也能理解部署。目前已有84人学习下载。读者可直接获得六套可运行的完整方案、配套数据集与结果图表,用于课程设计参考、实验复现或期末冲刺,省去从零搭建与调试的时间。
1. 机器学习期末大作业合集:六次作业怎么从零跑到满分
每到期末,机器学习大作业就成了分水岭。有人六次作业一路绿灯,有人第一次交完就被助教打回重做。这个标题指向的是一套完整的六次大作业合集,包含可运行代码和配套实验报告,覆盖从数据预处理、传统机器学习模型到深度学习模型的典型任务链路。它解决的不是"某个算法怎么写",而是"六次作业怎么排期、每份报告怎么写出得分点、代码怎么组织才能复用"。适合两类人:一是正在赶机器学习期末、需要一份能对照复现的参考;二是想系统过一遍机器学习入门到应用流程的自学者。下面按我实际带人做作业的顺序拆开讲,重点放在能直接抄的代码骨架、报告结构,以及那些让分数从 80 掉到 60 的细节。
2. 六次作业的任务拆解与代码目录怎么组织
2.1 先看清六次作业通常覆盖哪些算法
机器学习期末大作业的六次任务,不同学校命名不同,但内核高度重合。常见组合是:第一次数据清洗与特征工程,第二次线性模型(线性回归/逻辑回归),第三次决策树与集成学习,第四次支持向量机与核方法,第五次无监督学习(聚类/降维),第六次深度学习模型(CNN 或简单神经网络)。也有学校把第六次换成计算机视觉大作业或图像处理作业,本质还是"用机器学习检测/分类"。
我一般建议先做一张任务映射表,把每次作业的输入、输出、评估指标、报告页数要求列清楚。这张表决定了你后面代码目录怎么分、报告模板怎么复用。很多同学翻车就翻在"每次作业单独建一个文件夹,代码复制粘贴改一改",到第六次发现前面写的预处理函数有 bug,六份报告全要返工。
| 作业序号 | 典型任务 | 核心算法 | 评估指标 | 报告重点 |
|---|---|---|---|---|
| 1 | 数据清洗与特征工程 | 缺失值填充、标准化、独热编码 | 数据质量报告 | 特征分布图、处理前后对比 |
| 2 | 线性回归/逻辑回归 | 最小二乘、梯度下降、正则化 | MSE / 准确率 / F1 | 损失曲线、正则化系数对比 |
| 3 | 决策树与集成 | ID3/C4.5/CART、随机森林、GBDT | 准确率、特征重要性 | 树深度与过拟合关系 |
| 4 | SVM 与核方法 | 线性核、RBF 核、软间隔 | 准确率、支持向量数 | 核函数选择依据、C 与 gamma 影响 |
| 5 | 聚类与降维 | K-Means、DBSCAN、PCA、t-SNE | 轮廓系数、方差解释率 | 聚类可视化、降维前后对比 |
| 6 | 深度学习模型 | MLP、CNN、迁移学习 | 准确率、混淆矩阵 | 网络结构图、训练曲线 |
这张表不是让你照抄,而是让你在拿到题目后先填一遍。填不出来的格子,就是你要去查资料的地方。
2.2 代码目录按"数据-模型-报告"三层分
六次作业如果各自为政,最后一定乱。我习惯用一个仓库管六次作业,目录结构如下:
ml-homework/ ├── data/ │ ├── raw/ # 原始数据,只读 │ ├── processed/ # 清洗后数据 │ └── external/ # 外部数据集 ├── src/ │ ├── common/ │ │ ├── io.py # 读写、路径管理 │ │ ├── preprocess.py # 通用预处理 │ │ └── metrics.py # 评估指标 │ ├── hw1/ │ │ ├── run.py # 入口 │ │ └── config.yaml # 参数 │ ├── hw2/ │ └── ... ├── reports/ │ ├── hw1.md │ └── figures/ # 所有图统一放这 ├── requirements.txt └── README.md这样分的好处是:common里的预处理和评估函数只写一次,六次作业共用;每次作业的config.yaml只改参数,不改逻辑;报告里的图统一从reports/figures/引用,不会出现"图在哪个文件夹"的尴尬。
2.3 用一份配置驱动六次作业的参数
很多同学把超参数硬编码在代码里,换一次作业就改一次代码,改到最后自己都不知道哪个版本是对的。我一般用 YAML 配置把参数抽出来:
# src/hw2/config.yaml data: path: data/processed/hw2_train.csv target: label test_size: 0.2 random_state: 42 model: name: logistic_regression params: C: 1.0 penalty: l2 solver: lbfgs max_iter: 1000 output: model_path: outputs/hw2_model.pkl report_path: reports/hw2.md对应的读取代码:
import yaml from pathlib import Path def load_config(path: str) -> dict: """读取 YAML 配置,路径统一转成绝对路径,避免相对路径踩坑。""" with open(path, "r", encoding="utf-8") as f: cfg = yaml.safe_load(f) base = Path(path).resolve().parent.parent.parent cfg["data"]["path"] = str(base / cfg["data"]["path"]) cfg["output"]["model_path"] = str(base / cfg["output"]["model_path"]) return cfg逻辑说明:load_config把配置里的相对路径统一转成基于项目根目录的绝对路径。参数说明:path是配置文件路径,base取的是项目根目录(根据你的目录层级调整.parent次数)。这样无论从哪个目录运行脚本,数据路径都不会错。这是六次作业能复用的第一个基础设施,后面每次作业只需要换config.yaml。
3. 实验报告怎么写才能拿到满分:结构、图表与得分点
3.1 报告结构按"问题-方法-实验-分析"四段走
实验报告不是代码说明书。助教看报告的时间通常只有几分钟,结构清晰比内容多更重要。我一般用这个骨架:
- 问题描述:用两三句话写清任务目标、输入输出、评估指标。
- 方法:写清用了什么算法、为什么选它、关键公式(不用推导,写结论即可)。
- 实验设置:数据规模、划分方式、超参数、运行环境。
- 结果与分析:表格放指标,图放曲线和可视化,每张图下面写一句"从图中可以看出……"。
- 问题与改进:写一两个实际遇到的坑和你的处理,这是拉开分差的地方。
很多同学把"方法"写成教科书摘抄,把"分析"写成"效果很好"。助教一眼就能看出你有没有真跑过。分析部分一定要有具体数字,比如"当 C 从 0.1 增到 10,训练集准确率从 0.82 升到 0.97,但验证集准确率在 C=1 后开始下降,说明模型进入过拟合"。
3.2 图表规范:每张图都要能独立看懂
报告里的图,标准是"截出来单独发给别人,对方也能看懂"。这意味着:标题、坐标轴标签、图例、单位一个都不能少。用 matplotlib 时我固定一套样式:
import matplotlib.pyplot as plt plt.rcParams.update({ "figure.dpi": 150, "savefig.dpi": 150, "font.size": 11, "axes.titlesize": 13, "axes.labelsize": 11, "axes.grid": True, "grid.alpha": 0.3, "figure.autolayout": True, }) def save_fig(fig, name: str): """统一保存到 reports/figures,避免图散落各处。""" out = f"reports/figures/{name}.png" fig.savefig(out, bbox_inches="tight") print(f"saved: {out}")逻辑说明:rcParams统一了所有图的字体、网格、分辨率,避免每张图风格不一致。save_fig强制图片输出到固定目录。参数说明:dpi=150是报告打印的够用值,再高文件会很大;bbox_inches="tight"去掉多余白边。六次作业所有图都走这个函数,报告里引用路径统一,不会出现图裂。
3.3 得分点藏在"对比实验"和"失败分析"里
满分报告和及格报告的差距,往往不在主实验,而在附加分析。我一般会加两组对比:
- 参数对比:同一个模型,换 3 到 5 个关键参数,画一张指标变化表。
- 模型对比:至少两个算法在同一数据上的表现,说明为什么选最终那个。
失败分析更关键。比如聚类作业里 K-Means 对非球形簇效果差,你可以补一张 DBSCAN 的对比图,写清"K-Means 在月牙形数据上轮廓系数只有 0.31,DBSCAN 达到 0.58,原因是 K-Means 假设簇为凸形"。这种分析助教一看就知道你真做了实验,不是抄的。
提示:报告里的所有数字必须和代码输出一致。我见过有人手改报告里的准确率,结果助教跑代码对不上,直接判抄袭。跑完代码把指标打印到日志,报告里从日志复制。
4. 六次作业常见算法的最小可运行代码骨架
4.1 传统机器学习模型:以逻辑回归和随机森林为例
第二次和第三次作业通常落在传统机器学习模型上。下面是一个可复用的训练评估骨架,逻辑回归和随机森林都能套:
import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score, f1_score, classification_report def train_eval(cfg: dict): df = pd.read_csv(cfg["data"]["path"]) X = df.drop(columns=[cfg["data"]["target"]]) y = df[cfg["data"]["target"]] X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=cfg["data"]["test_size"], random_state=cfg["data"]["random_state"], stratify=y, ) scaler = StandardScaler() X_train_s = scaler.fit_transform(X_train) X_test_s = scaler.transform(X_test) if cfg["model"]["name"] == "logistic_regression": clf = LogisticRegression(**cfg["model"]["params"]) else: clf = RandomForestClassifier(**cfg["model"]["params"]) clf.fit(X_train_s, y_train) pred = clf.predict(X_test_s) print("accuracy:", accuracy_score(y_test, pred)) print("f1:", f1_score(y_test, pred, average="weighted")) print(classification_report(y_test, pred)) return clf, scaler逻辑说明:先划分训练测试集,stratify=y保证类别比例一致;标准化只在训练集上fit,测试集只transform,避免数据泄漏。参数说明:test_size常用 0.2,数据少时用 0.3;random_state固定后结果可复现,报告里写清楚这个值;C是逻辑回归正则化强度的倒数,越小正则越强。随机森林的n_estimators从 100 起步,max_depth不设或设 10 到 20 之间。
4.2 深度学习模型:一个能跑通的 MLP 训练循环
第六次作业如果是深度学习模型,很多同学卡在环境配置和训练循环上。下面是一个最小 MLP 骨架,用 PyTorch:
import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset class MLP(nn.Module): def __init__(self, in_dim: int, hidden: int, n_class: int): super().__init__() self.net = nn.Sequential( nn.Linear(in_dim, hidden), nn.ReLU(), nn.Dropout(0.3), nn.Linear(hidden, hidden // 2), nn.ReLU(), nn.Linear(hidden // 2, n_class), ) def forward(self, x): return self.net(x) def train_mlp(X_train, y_train, X_val, y_val, cfg: dict): device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = MLP(X_train.shape[1], cfg["hidden"], cfg["n_class"]).to(device) opt = torch.optim.Adam(model.parameters(), lr=cfg["lr"]) loss_fn = nn.CrossEntropyLoss() train_ds = TensorDataset(torch.tensor(X_train, dtype=torch.float32), torch.tensor(y_train, dtype=torch.long)) train_loader = DataLoader(train_ds, batch_size=cfg["batch_size"], shuffle=True) for epoch in range(cfg["epochs"]): model.train() total_loss = 0.0 for xb, yb in train_loader: xb, yb = xb.to(device), yb.to(device) opt.zero_grad() loss = loss_fn(model(xb), yb) loss.backward() opt.step() total_loss += loss.item() model.eval() with torch.no_grad(): val_logits = model(torch.tensor(X_val, dtype=torch.float32).to(device)) val_pred = val_logits.argmax(dim=1).cpu().numpy() val_acc = (val_pred == y_val).mean() print(f"epoch {epoch+1}: loss={total_loss/len(train_loader):.4f} val_acc={val_acc:.4f}") return model逻辑说明:MLP用两层隐藏层加 Dropout,防止小数据集过拟合;训练循环里每个 epoch 后在验证集上评估,方便画训练曲线。参数说明:hidden从 128 或 256 起步;lr用 1e-3;batch_size用 32 或 64;epochs先跑 50 看曲线,没收敛再加。注意X_train要提前标准化,神经网络对尺度敏感。
4.3 无监督学习:聚类和降维的可视化套路
第五次作业常要求聚类可视化。高维数据直接画不了,标准做法是先 PCA 降到 2 维再画:
from sklearn.decomposition import PCA from sklearn.cluster import KMeans import matplotlib.pyplot as plt def cluster_visualize(X, n_clusters: int = 3): X_pca = PCA(n_components=2, random_state=42).fit_transform(X) labels = KMeans(n_clusters=n_clusters, random_state=42, n_init=10).fit_predict(X) fig, ax = plt.subplots(figsize=(6, 5)) scatter = ax.scatter(X_pca[:, 0], X_pca[:, 1], c=labels, cmap="viridis", s=20) ax.set_title(f"K-Means clustering (k={n_clusters}) on PCA-reduced data") ax.set_xlabel("PC1") ax.set_ylabel("PC2") fig.colorbar(scatter, ax=ax, label="cluster") return fig逻辑说明:PCA 只用于可视化,聚类仍在原始特征上做,避免降维丢失信息影响结果。参数说明:n_components=2是为了画图;n_init=10让 K-Means 多跑几次取最优,避免陷入局部最优;random_state固定保证图可复现。报告里要写清"PCA 仅用于可视化,聚类基于原始特征"。
5. 避坑与排查:六次作业里最容易翻车的五件事
5.1 数据泄漏:标准化在划分之前做
现象:验证集准确率高得离谱,测试集一跑就崩。原因:先对整个数据集做了标准化或归一化,再划分训练测试集,测试集的统计量泄漏到了训练过程。解决:永远先train_test_split,再在训练集上fit预处理器,测试集只transform。这个坑在第一次作业就要养成习惯,后面五次都靠它。
5.2 随机种子没固定:报告数字对不上
现象:报告里写准确率 0.91,助教跑代码得到 0.88。原因:random_state没设,或者不同库的随机种子没统一。解决:在入口脚本开头统一设种子:
import random import numpy as np import torch def set_seed(seed: int = 42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed)参数说明:seed用 42 或 2024 都行,关键是六次作业统一。报告里写清"所有实验随机种子设为 42"。
5.3 类别不平衡:准确率虚高但 F1 很低
现象:准确率 0.95,但少数类几乎全预测错。原因:数据类别比例悬殊,准确率被多数类主导。解决:看classification_report里的 F1 和召回率,必要时用class_weight="balanced"或过采样。报告里要同时给准确率和 F1,只给准确率会被扣分。
5.4 过拟合:训练集完美,验证集拉胯
现象:训练准确率 0.99,验证准确率 0.72。原因:模型太复杂、数据太少、训练太久。解决:先加正则化(L2、Dropout),再减模型容量,最后考虑数据增强。报告里画训练/验证曲线,标出过拟合开始的 epoch,这本身就是得分点。
5.5 环境依赖:换台机器就跑不起来
现象:本地跑通,助教机器上报ModuleNotFoundError或版本冲突。原因:没写requirements.txt,或者用了本地特有的包。解决:项目根目录放requirements.txt,只写核心依赖和版本范围:
numpy>=1.24 pandas>=2.0 scikit-learn>=1.3 matplotlib>=3.7 torch>=2.0 pyyaml>=6.0提交前在干净虚拟环境里pip install -r requirements.txt跑一遍,确认能复现。
6. 把六次作业压成一套可复用模板的进阶做法
六次作业做完,如果只是交完就扔,那这套代码的价值就浪费了。我一般会做一件事:把六次作业抽象成一套"数据-模型-评估"流水线模板,下次遇到新任务直接套。具体做法是定义一个Experiment类,把配置、数据加载、模型构建、训练、评估、报告生成串起来。
class Experiment: def __init__(self, cfg: dict): self.cfg = cfg self.model = None self.scaler = None def run(self): X_train, X_test, y_train, y_test = self.load_data() self.build_model() self.fit(X_train, y_train) metrics = self.evaluate(X_test, y_test) self.dump_report(metrics) return metrics def load_data(self): # 按 cfg 读取并划分,复用第 4 章的骨架 ... def build_model(self): # 按 cfg["model"]["name"] 分发到不同模型 ... def fit(self, X, y): ... def evaluate(self, X, y): ... def dump_report(self, metrics: dict): # 把指标和图表路径写进 reports/hwX.md ...逻辑说明:Experiment把六次作业的公共流程固定下来,每次作业只需要实现或覆盖build_model和load_data。参数说明:cfg就是第 2 章的 YAML 配置,metrics是评估指标字典。这样第六次作业的深度学习模型和第二次的逻辑回归走同一套流程,报告模板也能复用。
验证这套模板是否可靠,我一般做两个检查:一是换一个随机种子跑,指标波动在合理范围内;二是把训练集缩小到 50%,看流程是否仍然跑通。如果缩小数据后代码报错,说明某处硬编码了数据规模,需要修掉。
最后一个习惯:每次作业提交前,把reports/里的图和src/里的代码对一遍,确认报告里每个数字都能在代码输出里找到。我吃过一次亏,报告里写了一个手算的 F1,结果和代码输出差 0.02,被助教追问了半天。从那以后,报告里的数字一律从日志复制,不手打。希望帮到你。
本文还有配套的精品资源,点击获取