学生任务单:把观察变成有边界的证据

本任务单同时适用于 Python 与 R。Python Notebook 提供逐步可执行单元;R 可按相同研究问题运行对应脚本。所有记录均为合成数据,540 行训练、180 行验证,没有最终测试数据。

每个实验使用五步:先写研究问题 → 先写预测 → 只改指定条件 → 记录可观察量 → 写支持与不支持的结论。不要在看见结果后把解释改写成事先预测。

学习路线与练习记录

时间为学习安排建议,实际训练速度取决于设备。不要为了完成全部任务而省略控制条件。

实验 0|我真的没有用验证集拟合预处理吗?

研究问题: 如果训练集和验证集分别标准化,是否仍是同一条预测管线?

  1. 运行计算检查脚本(selfcheck_python.py 或 selfcheck_R.R)。记录训练与验证行数,确认员工标识不重叠。
  2. 运行完整实验,打开 scaling.csv。
  3. 从原始训练行重新计算一个特征的均值和总体标准差。与 CSV 对照。
  4. Notebook 中观察训练标准化均值接近 0、标准差接近 1。验证均值不必为 0。
  5. 用一句话说明验证集只能应用训练参数的原因。不要为了“整齐”而把验证均值调成 0。

记录: 特征名、训练均值、训练总体标准差、验证变换公式、核查差值。

思考提示: scale 是总体标准差,不是样本标准差。Python 使用 ddof=0;R 使用平均平方偏差的平方根。

实验 1|神经网络必须先超过什么基线?

研究问题: 一个复杂模型的分数,是否真的超过了不使用特征的简单策略?

  1. 运行 experiments_python.py 或 experiments_R.R,先看 constant、logistic、nn_reference 三行。
  2. 常数模型对所有记录返回训练集离职比例;不要用验证标签估计该比例。
  3. 比较验证交叉熵、AUC、召回率与准确率。阈值均固定为 0.5。
  4. 解释为什么常数分数的 AUC 为 0.5(前提是验证集同时有两类)。
  5. 如果某个模型准确率较高,却漏掉更多正例,说明准确率遗漏了什么。

控制条件: 相同记录、预处理、标签、阈值;逻辑回归与默认网络共享学习率和 L2,但结构不同。常数模型不训练,没有保留轮次。

记录: comparison.csv 的三行、选定的主指标、不同指标是否支持相同排序。

思考提示: “高于常数基线”不等于“可以用于组织决策”。这些是合成开发数据上的相对观察。

实验 2|增加隐藏单元一定更好吗?

研究问题: 4、8、16 个隐藏单元如何改变拟合能力与验证损失?

  1. 入门入口先运行 HIDDEN=8、LEARNING_RATE=0.05、L2=0.001,保存目录名。
  2. 只把 HIDDEN 改为 4,再运行;然后改为 16。
  3. 在完整比较中找到 hidden_4、nn_reference、hidden_16,核对两种运行方式。
  4. 比较保留模型的训练交叉熵、验证交叉熵、二者差值、保留/停止轮次。
  5. 从逐轮曲线中指出一段具体区间。不要只写“看起来过拟合”。

可观察量: train_log_loss、val_log_loss、gap_log_loss、best_epoch、stop_epoch。

控制条件: 数据、学习率、L2、停止规则固定。不同宽度需要不同形状的固定初始化;不能声称严格隔离了所有初始化影响。

思考提示: 差值为正本身不能单独证明过拟合。需要观察训练持续下降而验证趋平或上升等证据。曲线若没有出现此模式,就报告“未观察到”。

实验 3|学习率改变了什么?

研究问题: 同样的最大轮次,学习率如何影响优化速度与保留结果?

  1. 恢复隐藏单元 8、L2 0.001。
  2. 分别比较 0.01、0.05、0.15 的学习率。对应 lr_001、nn_reference、lr_015。
  3. 比较第 0、50、100 轮及最后共同存在的轮次。曲线结束后不要补造数据。
  4. 再比较各自保留轮次的损失。区分“相同更新预算”和“各自早停”的比较。
  5. 写出低学习率的结果是否可能反映尚未收敛。若要延长训练,先固定新的预算并给实验另命名。

思考提示: 更快下降不等于更好泛化。学习率并不直接表示模型结构容量。

实验 4|L2 限制的是哪一部分?

研究问题: 增加权重惩罚是否能改善当前候选的开发表现?

  1. 恢复隐藏单元 8、学习率 0.05。
  2. 比较 L2 为 0、0.001、0.01:l2_0、nn_reference、l2_010。
  3. 查看核心代码中的梯度:哪些参数加上了 L2 项?哪些没有?
  4. 同时观察训练损失、验证损失与差值。不要只保留有利指标。
  5. 进阶:在保留参数上计算权重平方和,和未惩罚交叉熵分别报告。不要把训练目标与曲线纵轴混为一谈。

思考提示: learning_curves.csv 不包含 L2 惩罚项。更强的惩罚可能缓解过拟合,也可能导致欠拟合;必须用这次运行的证据判断。

实验 5|相同概率,为什么会有不同决策?

研究问题: 改变阈值时,哪些指标改变,哪些不会改变?

  1. 打开 thresholds.csv。代码只使用 nn_reference 的同一组保留概率,不重新训练。
  2. 比较阈值 0.2、0.35、0.5、0.65、0.8 的 FP、FN、精确率与召回率。
  3. 核对交叉熵和 AUC 在五行中不变。它们在这里由概率计算,不依赖分类阈值。
  4. 用 normalized_cost=(FP+3×FN)/180 复算一行。1 与 3 是课堂假设,不能伪装为真实政策。
  5. 将假阴性成本改为 1 或 5,再做不重新训练的成本比较。Python Notebook 有可编辑成本参数;R 可在调用 threshold_scan 时传入成本。
  6. 记录哪种成本假设支持哪个阈值。如果两个阈值并列,请写出预先规定的选择规则。

思考提示: 阈值升高时,预测为正的数量、TP 与 FP 不会增加;精确率不保证严格单调。根据验证成本选阈值后,最小成本仍是被选择过的开发结果,不是独立性能估计。

实验 6|保留轮次不是停止轮次

研究问题: 训练继续运行一段时间后,返回的参数来自哪里?

  1. 选一条 best_epoch < stop_epoch 的曲线;如果没有,就明确说明所有候选都在边界保留。
  2. 比较初始、保留、停止三行。报告验证损失的变化。
  3. 在代码中找到参数复制、等待计数重置、恢复保留参数的位置。
  4. Python 计算检查脚本用很大的最小改进值触发三轮等待,检查返回第 0 轮参数。R 计算检查脚本检查对应机制。
  5. 进阶:阅读数值差分梯度检查。解释为什么必须把 L2 项也加入待验证目标。

思考提示: 早停使用验证标签参与模型选择,所以验证集已参与开发。不要称其为“完全未参与训练过程的最终测试”。

实验 7|移除一个特征,能说明它的因果作用吗?

研究问题: 在相同初始化下,去掉一个特征的变化信息,会如何影响这个预测模型?

  1. Notebook 中先选择 support_score;将该标准化特征在训练和验证中都设为 0。
  2. 从原始数据副本出发,不改动 CSV,不重新定义划分。
  3. 固定其他条件,重新训练相同网络;与 nn_reference 比较。
  4. 解释 0 对应训练均值,表示不让模型使用这个特征的记录间变化。
  5. 把它称为“特征消融比较”。其他特征仍可能携带相关信息,单次差异也受模型和初始化影响。
  6. 写出至少两个替代解释。不要写成“提高支持程度会减少离职”的因果结论。

记录: 被消融特征、控制条件、验证损失差、AUC 差、替代解释;Notebook 保存 feature_ablation.csv。

比较记录与最终冻结

复制 comparison_notes_template.csv,每个研究问题填写一行:

完成后写一份“开发候选冻结记录”:模型与参数、预处理、主指标、阈值、成本假设、停止规则、初始化来源、已看过多少个候选。解释为了独立最终评估,还需要另行采集和隔离什么数据。本包不提供或模拟这个最终评估阶段。