关于 ml-evaluation
面向机器学习系统开发与部署的评估指南,涵盖数据划分、指标选择、统计比较、错误分析和上线监测,帮助判断性能变化是否可靠且符合实际决策。
主要功能
- 01选择与决策目标相符的指标
- 02设计分组与时间序列划分
- 03用置信区间和配对检验比较
- 04分析错误切片与模型稳健性
- 05规划上线评估和漂移监测
适用场景
- 01避免训练测试数据泄漏
- 02比较同一测试样本上的模型
- 03检查不同用户群体的表现
- 04上线前制定监测与回滚标准
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ josiahsiegel/ claude-plugin-marketplace --skill ml-evaluation安装后在 Claude Code 中输入/ml-evaluation确认已加载。
详细介绍
机器学习评估
概览
在部署前、部署期间和部署后评估机器学习系统时,请使用此技能。有效的评估应回答:哪些决策会使用模型、哪些数据分布很重要、存在哪些失误成本、哪个指标能体现这些成本,以及测得的改进究竟是真实的,还是由数据泄漏、方差或对验证集过拟合造成的。
评估设计检查清单
- 定义预测单位和独立性单位。当样本存在相关性时,按用户、账户、患者、设备、文档、会话或时间进行划分。
- 使用简单的启发式方法、先前模型或线性/树模型基线,确定基线性能。
- 选择与决策相匹配的指标,而不只是方便使用的默认指标。
- 在最终评估之前冻结测试数据;使用验证数据进行调优。
- 评估不同切片:标签、地理区域、设备、语言、适当时的群体特征、数据来源、时间段和已知难例。
- 当样本量有限时,使用置信区间或重复交叉验证报告不确定性。
- 在扩大模型复杂度之前,进行定性错误分析。
数据集划分策略
仅当数据为独立同分布且样本彼此独立时,才使用随机分层划分。多行数据共享同一实体时,使用分组划分。在预测、推荐、欺诈检测、日志分析,以及任何未来数据不同于过去数据的部署场景中,使用基于时间的划分。当需要对超参数和性能估计同时进行无偏评估时,使用嵌套交叉验证。对于小型数据集,重复分层交叉验证可以降低方差;但当风险较高时,应保留一个从未使用过的最终测试集。
全面的数据泄漏预防检查清单
- 先划分再拟合:仅在训练子集上应用
scaler.fit()、imputer.fit()和编码器拟合。切勿在整个数据集上拟合。 - 时间单调性:对于时间序列划分,确保验证集/测试集索引在时间顺序上严格晚于训练集索引。
- 分组隔离:确认共享分组因素(例如患者 ID、公司 ID、会话 ID)的数据点不会同时出现在训练集和测试集中。
- 目标泄漏:检查是否存在表示预测时间之后事件的列(例如流失模型中的“refunded_date”)。
- 划分前不做增强:在划分之后再进行少数类过采样(例如 SMOTE)或数据增强。划分前进行过采样会导致合成的孪生样本跨越数据集边界。
指标选择
| 任务 | 首选指标 | 注意事项 |
|---|---|---|
| 平衡分类 | 准确率、宏 F1、对数损失 | 准确率会掩盖校准问题和少数类错误 |
| 不平衡分类 | PR-AUC、给定精确率下的召回率、F-beta、成本效用 | 即使正类精确率很差,ROC-AUC 也可能看起来很高 |
| 概率分类 | 对数损失、Brier 分数、校准曲线 | 阈值指标会忽略概率质量 |
| 回归 | MAE、RMSE、RMSLE、pinball loss、R2 | RMSE 对异常值的权重过高;MAPE 在接近零时会失效 |
| 排序/检索 | NDCG、MAP、MRR、recall@k、precision@k | 离线负样本可能无法代表生产环境中的候选项 |
| 预测 | sMAPE、MASE、pinball loss、覆盖率 | 随机划分会泄漏未来模式 |
| 生成 | 特定任务的人工/评估模型评分标准,加上自动化检查 | 单独使用 BLEU/ROUGE 往往无法衡量实用性和安全性 |
| Embeddings/RAG | Recall@k、MRR、答案忠实度、依据充分性、延迟 | 必须区分检索失败和生成失败 |
对于高风险决策,应使用混淆矩阵和成本曲线评估运行阈值。在验证集上优化阈值,然后报告在测试集上使用固定阈值的性能。当决策依赖概率时,应校准概率。
统计比较
不要将简单的指标差异视为证据。当模型在相同样本上进行评估时,应使用配对比较。
Bootstrap 置信区间(Python 示例)
import numpy as np
from sklearn.metrics import f1_score
def bootstrap_metric_ci(
y_true: np.ndarray,
y_pred: np.ndarray,
metric_fn = f1_score,
n_bootstrap: int = 1000,
confidence_level: float = 0.95
):
bootstrapped_scores = []
rng = np.random.default_rng(seed=42)
n_samples = len(y_true)
for _ in range(n_bootstrap):
# Sample with replacement
indices = rng.choice(n_samples, size=n_samples, replace=True)
score = metric_fn(y_true[indices], y_pred[indices])
bootstrapped_scores.append(score)
sorted_scores = np.sort(bootstrapped_scores)
alpha = 1.0 - confidence_level
lower_idx = int(np.floor(alpha / 2.0 * n_bootstrap))
upper_idx = int(np.ceil((1.0 - alpha / 2.0) * n_bootstrap))
return sorted_scores[lower_idx], sorted_scores[upper_idx]
用于比较配对分类器的 McNemar 检验
McNemar 检验用于评估两个模型之间的分歧是否显著。
import numpy as np
from scipy.stats import chi2_contingency
def mcnemar_test(y_true: np.ndarray, pred_model_a: np.ndarray, pred_model_b: np.ndarray):
# Contingency Table:
# Model B Correct Model B Incorrect
# Model A Correct n00 n01
# Model A Incorrect n10 n11
correct_a = (pred_model_a == y_true)
correct_b = (pred_model_b == y_true)
n01 = np.sum(correct_a & ~correct_b) # A correct, B incorrect
n10 = np.sum(~correct_a & correct_b) # A incorrect, B correct
# Calculate chi-squared with continuity correction
if n01 + n10 == 0:
return 1.0 # Perfect agreement
statistic = (abs(n01 - n10) - 1)**2 / (n01 + n10)
# 1 degree of freedom
from scipy.stats import chi2
p_value = 1 - chi2.cdf(statistic, df=1)
return p_value
用于 Logits 校准的温度缩放(PyTorch)
import torch
import torch.nn as nn
import torch.optim as optim
class TemperatureScaler(nn.Module):
def __init__(self):
super().__init__()
# Initial temperature parameter of 1.0 (no scaling)
self.temperature = nn.Parameter(torch.ones(1))
def forward(self, logits: torch.Tensor):
return logits / self.temperature
def fit(self, val_logits: torch.Tensor, val_labels: torch.Tensor, max_iter: int = 50):
# Optimizes temperature parameter on validation set
nll_criterion = nn.CrossEntropyLoss()
optimizer = optim.LBFGS([self.temperature], lr=0.01, max_iter=max_iter)
def eval_loss():
optimizer.zero_grad()
loss = nll_criterion(self.forward(val_logits), val_labels)
loss.backward()
return loss
optimizer.step(eval_loss)
return self.temperature.item()
错误分析
创建结构化的错误分类体系,而不是随机检查失败案例。细分假阳性、假阴性、高置信度错误、低置信度正确案例、分布外示例、缺失值、稀有标签、长尾实体、提示词类别以及延迟/超时。
错误分析应转化为具体的改进措施:收集数据、重新标注、更改数据集划分、调整损失函数、添加特征、改进检索、校准阈值、简化模型或调整服务流水线。
负责任的 AI 与鲁棒性
评估模型在相关人口统计、地理、语言、无障碍和运营切片上的行为。选择符合领域要求的公平性指标:人口统计均等、均等化赔率、机会均等、按群体校准或反事实一致性。说明其中的权衡;公平性指标可能相互冲突。当用户需要了解原因时,可使用可解释模型或可解释性工具,但应验证解释的稳定性和合理性。
测试模型对缺失字段、架构变更、对抗性或含噪输入、LLM/RAG 系统的提示词注入、图像损坏、文本拼写错误、分布偏移和低资源切片的鲁棒性。部署前,务必制定监控计划,以监测数据漂移、性能漂移、校准漂移和安全事件。
生产环境评估
离线指标不可或缺,但仅靠它们还不够。发布前,在可行的情况下进行影子评估、回测、批量回放或金丝雀测试。针对相同示例比较训练和服务预处理的输出。明确回滚阈值、告警接收方、重新训练标准和负责人。对于 A/B 测试,应纳入延迟、成本、用户伤害、公平性切片、业务约束和支持负担等护栏指标。
常见评估问题
- 验证结果出色,生产表现不佳:数据泄漏、分布偏移、服务偏差、阈值不匹配或验证集缺乏代表性。
- ROC-AUC 很高,用户价值却很低:类别不平衡或阈值决策导致指标选择不当。
- 平均指标提升,却损害了关键用户:缺少切片评估。
- 测试集反复使用:对基准测试集发生隐性过拟合。
- LLM 评估结果看似良好,但回答仍会产生幻觉:自动词汇指标未衡量依据是否充分、引用质量或拒答行为。
来源
- scikit-learn 模型评估:https://scikit-learn.org/stable/modules/model_evaluation.html
- TensorFlow Model Analysis:https://www.tensorflow.org/tfx/model_analysis
- Google 机器学习速成课程评估指南:https://developers.google.com/machine-learning/crash-course/classification
- Fairlearn 文档:https://fairlearn.org/
- Evidently AI 机器学习监控与评估概念:https://docs.evidentlyai.com/