机器学习实验报告
用结构化报告记录任务、环境、数据、协议、基线、候选、搜索、测试、错误、交付与限制。
学习前需要掌握
背景与问题
实验报告要让别人判断改进是否可信、结果能否复现,以及还有哪些限制。只列模型名与最高分,会遗漏划分、数据处理和反复选择带来的影响。
报告应围绕明确问题展开:与哪个基线比较,预先关心哪个指标,哪些数据参与了训练和选择,最终结果支持什么范围的结论。
概念定义
报告不是结果截图集合,而是让读者能够复现并审查每个决策的实验档案。
直观理解
把项目当作一条可复现、可审计的实验链,而不是追求一次最高分。
核心原理
数据部分记录来源版本、样本与标签口径、排除规则和拆分单位,保留实际索引或可重建方式。文件或内容哈希有助于确认同一份数据,但不能替代来源、授权与质量说明。
方法部分记录整个 Pipeline、参数、搜索范围、随机性与软件环境。选择过程与最终模型配置要区分,不能只写获胜参数却隐去尝试过多少方案和怎样选中。
结果应同时包括基线、每折或留出分数、关键切片、成本和错误分析,并明确哪些是构造演示、哪些是真实实测。负结果与失败运行也是证据,有助于避免重复工作和选择性报告。
测试使用次数应由运行记录支撑,而不是仅在字典中写 test_used_once=True。若测试结果引发后续改动,就应说明它已进入开发;结论还需注明适用人群、数据时期和没有验证的条件。
数学表达
项目主线
预先写主要指标和协议;结果部分同时记录训练、验证、测试与限制,不隐藏未达预期或错误样本。
变量含义
变量定义与本页概念定义一致,代码中的同名变量保持相同语义。
计算步骤
- 1摘要与最终结果
- 2环境版本和命令
- 3数据规模与分布
- 4划分/CV/泄漏边界
代码对应位置
示例 1把真实运行的配置、索引与指标写入报告:在明确数据与固定划分上执行一轮拟合和测试,记录来源与边界,不宣称模型优于其他方案。
案例:一份可回查的小型实验记录
下方以固定 Iris 数据、固定训练测试索引与完整 Pipeline 做一次演示,保存环境、数据哈希、参数和实际计算的准确率到临时 JSON。读取后核对索引覆盖与样本数,展示报告字段如何关联真实执行。
示例代码只有一次测试评分调用,但一般项目不能仅靠报告中的次数声明证明没有反复测试,还要有运行历史。这个数据上的分数只属于该演示划分,不代表真实业务效果;没有和其他方案比较,也不能声称算法改进。
计算与实现步骤
- 摘要与最终结果
- 环境版本和命令
- 数据规模与分布
- 划分/CV/泄漏边界
- 基线和候选
- 搜索空间
- 最终测试
- 错误分析
- 保存/输入检查
- 限制和结论
代码实现
示例 1
把真实运行的配置、索引与指标写入报告
example_01.py用途:在明确数据与固定划分上执行一轮拟合和测试,记录来源与边界,不宣称模型优于其他方案。
from pathlib import Path
from tempfile import TemporaryDirectory
import hashlib
import json
import numpy as np
import sklearn
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X, y = load_iris(return_X_y=True)
train, test = train_test_split(np.arange(len(y)), test_size=0.2, stratify=y, random_state=42)
model = make_pipeline(StandardScaler(), LogisticRegression(C=1.0, max_iter=1000))
model.fit(X[train], y[train])
prediction = model.predict(X[test])
report = {
"dataset": "sklearn built-in iris",
"data_sha256": hashlib.sha256(X.tobytes() + y.tobytes()).hexdigest(),
"sklearn_version": sklearn.__version__,
"random_state": 42,
"train_indices": train.tolist(), "test_indices": test.tolist(),
"pipeline": ["StandardScaler", "LogisticRegression"],
"parameters": {"C": 1.0, "max_iter": 1000},
"primary_metric": "accuracy",
"test_accuracy": float(accuracy_score(y[test], prediction)),
}
with TemporaryDirectory() as temporary:
path = Path(temporary) / "report.json"
path.write_text(json.dumps(report, indent=2), encoding="utf-8")
loaded = json.loads(path.read_text(encoding="utf-8"))
assert set(loaded["train_indices"]).isdisjoint(loaded["test_indices"])
print("train_test:", (len(loaded["train_indices"]), len(loaded["test_indices"])))
print(f"test_accuracy={loaded['test_accuracy']:.3f}")
print("hash_length:", len(loaded["data_sha256"]))代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
在明确数据与固定划分上执行一轮拟合和测试,记录来源与边界,不宣称模型优于其他方案。
X- 完整特征矩阵,每行一个样本、每列一个特征。
y- 目标标签或连续目标值。
model- 组合预处理和估计器的模型对象。
Step 1 · 1–12 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
from pathlib import Path
from tempfile import TemporaryDirectory
import hashlib
import json
import numpy as np
import sklearn
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScalerStep 2 · 14–37 行
按固定协议切分训练与测试数据;此处的数据边界决定后续哪些样本可以参与 fit。
X, y = load_iris(return_X_y=True)
train, test = train_test_split(np.arange(len(y)), test_size=0.2, stratify=y, random_state=42)
model = make_pipeline(StandardScaler(), LogisticRegression(C=1.0, max_iter=1000))
model.fit(X[train], y[train])
prediction = model.predict(X[test])
report = {
"dataset": "sklearn built-in iris",
"data_sha256": hashlib.sha256(X.tobytes() + y.tobytes()).hexdigest(),
"sklearn_version": sklearn.__version__,
"random_state": 42,
"train_indices": train.tolist(), "test_indices": test.tolist(),
"pipeline": ["StandardScaler", "LogisticRegression"],
"parameters": {"C": 1.0, "max_iter": 1000},
"primary_metric": "accuracy",
"test_accuracy": float(accuracy_score(y[test], prediction)),
}
with TemporaryDirectory() as temporary:
path = Path(temporary) / "report.json"
path.write_text(json.dumps(report, indent=2), encoding="utf-8")
loaded = json.loads(path.read_text(encoding="utf-8"))
assert set(loaded["train_indices"]).isdisjoint(loaded["test_indices"])
print("train_test:", (len(loaded["train_indices"]), len(loaded["test_indices"])))
print(f"test_accuracy={loaded['test_accuracy']:.3f}")
print("hash_length:", len(loaded["data_sha256"]))代码与数学原理
减去训练均值并除以训练标准差,对应代码中的 mean/std 或 StandardScaler。
预期输出或运行结果
本地 scikit-learn 1.8.0 的核对输出: train_test: (120, 30) test_accuracy=0.933 hash_length: 64
常见错误 · 4 条
- 不要在测试集上调用 fit 或 fit_transform;测试集只能复用训练参数。
- 只保留最好分数和最终参数,隐去搜索预算、失败方案与数据排除。
- 用随机种子代替数据版本和实际索引,或把自填“测试一次”当成审计证据。
- 将构造案例、开发分数和独立测试混写,给出超出数据与协议的结论。
实际应用
- 课程报告
- 模型审查
- 复现
常见错误
- 只保留最好分数和最终参数,隐去搜索预算、失败方案与数据排除。
- 用随机种子代替数据版本和实际索引,或把自填“测试一次”当成审计证据。
- 将构造案例、开发分数和独立测试混写,给出超出数据与协议的结论。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。