分类模型
混淆矩阵 Confusion Matrix
评价的基础:混淆矩阵 Confusion Matrix
所有分类模型的评估指标,都源于一个简单的表格,叫做混淆矩阵,它用于告诉开发者模型在哪些地方做得好,哪些地方是错误的
假设:现在训练好了一个模型,用于检测邮件是否是垃圾邮件 Spam
那么有两个术语,用来描称呼 Spam和 Ham:
- 正类 Positive: 是垃圾邮件
- 负类 Negative: 不是垃圾邮件
现在,我们使用模型预测了100封邮件,混淆矩阵看起来是这样的:
| 预测为:垃圾 Positive | 预测为:正常 Negative | |
|---|---|---|
| 实际:垃圾 Positive | TP = 10 | FN = 5 |
| 实际:正常 Negative | FP = 2 | TN = 83 |
这四个格子是所有计算的核心:
-
TP True Positive - 真阳性:
✅️ 模型正确地将垃圾邮件预测为了垃圾邮件(10封)
-
TN True Negative - 真阴性:
✅️ 模型正确地将正常邮件预测为了正常邮件(83封)
-
FP False Positive - 假阳性 / Type I Error:
❌️ 模型错误地将正常邮件预测为了垃圾邮件。这是 误报,把重要的邮件错杀进了垃圾箱(2封)
-
FN False Negative - 假阴性 / Type II Error:
❌️ 模型错误地将垃圾邮件预测为了正常邮件。这是 漏报,让垃圾邮件溜进了你的收件箱(5封)
拥有了以上四个数据,就能够用来计算分类算法里的各种评价指标:
准确率 Accuracy
-
作用:在所有的邮件里,模型预测正确的比例。
-
计算公式
-
例子:以上面为例,
所以模型的准确率为 。
-
使用范围
十分通用,但当数据类别分布十分不均衡时,准确率容易产生误导。例如,一个罕见病预测, 的人是健康的,那么一个最 FW 的模型的准确率也高达 。但它没有任何用处,因为一个病人都找不出来(TP=0)
因此在使用此指标判断模型优劣时,在训练模型前要平衡好数据类别,即患病与健康的样本比例
精确率 Precision
-
作用:在所有预测为 Spam 的邮件中,有多少真的是 Spam
-
它关注预测结果的质量,“宁愿漏报,也不要误报”
-
计算公式
-
例子:以上面为例, 模型一共预测12封 mail 为 Spam
所以模型的准确率为 。
-
使用范围
当误报 FP的代价很高时:
- 垃圾邮件检测:你也不希望你的重要邮件例如奖金领取通知被过滤掉吧
- 股票预测:你也不希望你预测的某只会涨股的股票结果没涨,而你投了几个 W吧
召回率 Recall/ Sensitivity/ True Positive Rate
-
作用:在所有真正是垃圾邮件的邮件中,模型成功找出了多少
-
十分关注模型找到所有正类的能力,“宁愿误报,也不要漏报”
-
计算公式
-
例子:以上面为例, 实际上有 15 封 Spam
所以模型的准确率为
-
使用范围
当漏报 FN的代价非常高时:
- 疾病诊断: 漏诊一个病人(例如鼠疫)的后果十分严重,所以应尽可能找出所有病人,哪怕导致一些健康人被误判为病人(高Recall)
- 金融欺诈检测: 你也不想漏掉一笔欺诈交易忘记报警,导致自己损失了几个 W吧
F1分数 F1-Score
-
作用:查看精确率和召回率的定义,你就会发现这两是对立事件。F1分数就是为了在精确率和召回率之间取得平衡
-
当 Precision 和 Recall 都很重要时,F1分数是它们的调和平均数,它同时惩罚过低的 Precision 和过低的 Recall。
-
计算公式
-
例子:以上面为例, 实际上有 15 封 Spam
所以模型的 为
-
使用范围
同时关注 Precision 和 Recall 时:在类别不均衡的情况下,F1-Score 是比 Accuracy 更可靠的指标
总结
| 指标 | 回答的问题 | 计算公式 | 关键场景 |
|---|---|---|---|
| Accuracy | 整体预测对了多少 | 类别均衡时使用 | |
| Precision | 预测为“是”的结果中,有多少是真的“是” | 误报代价高时 (e.g., 垃圾邮件过滤) | |
| Recall | 所有真的“是”的样本中,找出了多少 | 漏报代价高时 (e.g., 疾病诊断) | |
| F1-Score | Precision和Recall的综合表现如何 | 两者都重要,或类别不均衡时 |
快速计算
Scikit-learn 提供了非常方便的工具
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
# 假设 y_true 是真实标签, y_pred 是模型预测的标签
y_true = [...]
y_pred = [...]
# 1. 直接打印所有核心指标
print(classification_report(y_true, y_pred, target_names=['Not Diabetic', 'Diabetic']))
# 2. 生成并可视化混淆矩阵
cm = confusion_matrix(y_true, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['Not Diabetic', 'Diabetic'], yticklabels=['Not Diabetic', 'Diabetic'])
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.show()
classification_report 会一次性计算好 Precision, Recall, F1-Score 和 Accuracy
回归模型
核心
回归模型得评价指标核心都是在衡量模型预测值与真实值之间的误差或距离,也就是残差 Residual 或者称为 误差 Error。评价指标为的就是衡量残差的大小,并尽可能调整参数,使得残差的总体大小尽可能地小
常用的指标有:
- 平均绝对误差 MAE
- 均方误差 MSE
- 均方根误差 RMSE
- R平方 R-Squared
使用一个例子比较好解释常用的四个指标。
假设:
假设我们要完成一个经典的回归任务:房价预测
- 真实值 ( ): 第 i 套房子的真实成交价
- 预测值 ( ): 模型对第 i 套房子的预测价格
- 误差 (Error): 对于单套房子,误差为
示例数据(单位:万美元):
| 房子 | 真实价格 | 模型预测价 | 误差 | 绝对误差 | 误差的平方 | | :—: | :-----------: | :-------------: | :-------: | :-------------: | :--------------: | | A | 30 | 28 | 2 | 2 | 4 | | B | 50 | 55 | -5 | 5 | 25 | | C | 100 | 90 | 10 | 10 | 100 | | D | 22 | 25 | -3 | 3 | 9 |
计算核心评估指标:
-
平均绝对误差 MAE
- 作用:计算模型预测结果 与 真实值的绝对误差的均值,使用平均的角度看待误差值
- 核心思想:计算每个样本误差的绝对值,再求均值
- 计算公式 其中 n 为样本数量
- 示例 以上文例子的数据计算: 因此模型预测房价的平均误差是 5万刀
- 优点: 对异常值不敏感,因为它不对误差进行平方
- 缺点: 由于不取平方, 因此它对大误差和小误差的惩罚是线性的,可能无法充分体现出大误差的严重性
-
均方误差 MSE
-
作用:本身没啥作用,指标不够直观,但是是其他技术(像优化)的基础
-
核心思想:就像名字,计算每个样本误差的平方,然后求平均
-
计算公式
-
示例
模型均方误差是34.5(万美元的平方),不好解释这个单位的意义
-
优点
- 对大误差给予更大的惩罚:在例子中,10万美元的误差贡献了100,而5万美元的误差只贡献了25。这会让模型更努力地修正那些离谱的预测。
- 数学上处理方便(函数光滑可导),是大多数线性回归模型默认的损失函数
-
缺点
-
单位是原始单位的平方,不直观
-
对异常值非常敏感:一个巨大的误差会被平方,可能主导整个MSE的值
-
-
-
均方根误差 RMSE
-
作用:在考虑了较大误差的情况下,模型预测结果误差的均值
-
核心思想:就是对 MSE 做了开方,将单位变回美元
-
计算公式
-
示例
说明它受 10万美元这个大误差数据的影响更大
-
优点
- 单位和原始数据相同,直观
- 保留了对大误差的惩罚特性
-
缺点
- 对异常值非常敏感:因为使用的仍然是 MSE,没办法
-
最常用的回归指标,因为保留了 MSE 和 MAE 的特性
-
-
R平方 R-Squared / 决定系数
-
作用:模型解释了目标变量多大比例的变化,在示例中是房价
-
核心思想:用于衡量,训练的模型相较于一个只预测平均值,不干其他事情的基准模型(最蠢的模型),要好多少 这个基准模型只会输出一个均值:即历来所有房价真实值的均值
-
计算公式
- R²的取值范围通常在0到1之间
- R² = 1: 完美模型,预测值和真实值完全一样
- R² = 0: 模型和 “预测平均值” 一样烂
- R² = 0.75: 模型解释了房价75%的变化
- R² < 0: 模型还不如直接预测平均值,说明模型非常差
-
优点:提供了一个相对性能度量(0%到100%),不受目标变量尺度的影响
-
缺点:如果不断地向模型中添加新的特征(哪怕是无用的特征),R²的值也可能会 “虚假地” 升高。调整后 (Adjusted R-squared) 可以修正这个问题
-
使用场景:想要衡量模型的拟合优度时,或者向他人解释模型在多大程度上捕捉了数据的内在规律时
-
总结
| 指标 | 回答的问题 | 单位 | 对异常值敏感度 | 核心特点 |
|---|---|---|---|---|
| MAE | 平均误差多少 | 原始单位 | 低 | 直观,鲁棒 |
| MSE | 误差的平方平均是多少 | 原始单位的平方 | 高 | 惩罚大误差,数学方便 |
| RMSE | 考虑大误差后,平均误差多少 | 原始单位 | 高 | 最常用,结合了MSE和MAE的优点 |
| R² | 模型解释了多少变化 | 无单位 (比例) | 中 | 相对性能度量,判断模型拟合优度 |
快速计算
Scikit-learn 提供了所有这些工具
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
# 假设 y_true 是真实值, y_pred 是模型预测的值
y_true = [30, 50, 100, 22]
y_pred = [28, 55, 90, 25]
# 计算 MAE
mae = mean_absolute_error(y_true, y_pred)
# 计算 MSE
mse = mean_squared_error(y_true, y_pred)
# 计算 RMSE
rmse = np.sqrt(mse) # 或者 mean_squared_error(..., squared=False)
# 计算 R-Squared
r2 = r2_score(y_true, y_pred)
聚类模型
由于聚类学习是无监督学习,因此我们是没有真实的标签来和模型输出的数据做对比的,它的指标比较特殊
两类评价指标
- 外部评价指标
- 使用前提:拥有数据的真实类别标签
- 目的:通常用于学术研究或算法基准测试。你可以把聚类结果和已知的正确答案进行比较,看看算法做得有多好
- 例子:你有一个客户数据集,虽然用聚类算法去发现自然群体,但手头其实已经有一份高价值/低价值客户的标签了
- 内部评价指标
- 使用前提:没有任何真实类别标签
- 目的:最常见、最实用的场景。它不依赖外部信息,而是直接评估聚类结果本身的质量
- 核心思想:一个好的聚类结果应该是簇内紧密,簇间疏远
外部评价指标
- 调整兰德指数 Adjusted Rand Index - ARI
- V-measure V-度量
内部评价指标(核心)
轮廓系数 Silhouette Coefficient
-
作用:每个数据点与其所属的簇的匹配程度、和与其他簇的分离程度,有多好
-
核心思想 对每个数据点计算一个分数:
- a: 该点到其自身簇中所有其他点的平均距离(簇内凝聚度),a越小越好
- b: 该点到最近的邻近簇中所有点的平均距离(簇间分离度),b越大越好
-
计算公式(对单个点)
取值范围: -1 到 1
-
接近 1:说明该点被很好地聚类
-
接近 0:说明该点位于两个簇的边界上
-
接近 -1:说明该点可能被分到了错误的簇
整个数据集的轮廓系数是所有点的分数的平均值
-
-
优点:最流行、最直观的内部评价指标。它提供了一个清晰的数值来判断聚类的整体质量
方差比标准 Calinski-Harabasz 指数
- 作用:簇间的分散程度与簇内的分散程度之比是多少
- 核心思想:它是一个比率
- 分子:簇间方差(各个簇的中心点与数据集总中心点的距离),越大越好(簇间疏远)
- 分母:簇内方差(每个簇内部的点与其簇中心的距离),越小越好(簇内紧密)
- 取值范围: 分数越高越好,没有上限
- 优点: 计算速度快
Davies-Bouldin 指数
-
作用:平均来看,每个簇与其最相似的簇之间的相似度是多少
-
核心思想:计算每个簇与其最相似的那个邻居簇的相似度比率(基于簇内距离和簇间距离) ,然后对所有簇的这个最差情况的相似度求平均。
-
取值范围: 分数越低越好,最小值为 0
-
优点: 比较稳定,不受簇形状的影响
实践中使用
内部评价指标最常见的用途就是帮助我们选择最佳的聚类数量 (k),这通常被称为肘部法则 的扩展应用
- 设定一个 k 的范围,例如从2到10
- 对每个 k 值,运行聚类算法(如K-Means)
- 计算一个内部评价指标(例如轮廓系数)
- 将 k 值与对应的指标分数画成折线图
- 寻找 “拐点”:
- 对于轮廓系数或Calinski-Harabasz指数,寻找分数最高的那个 k 值
- 对于Davies-Bouldin指数,寻找分数最低的那个 k 值
Scikit-learn中的实现
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score
from sklearn.metrics import adjusted_rand_score # 外部指标示例
# 假设 X 是特征数据
# 假设 labels_true 是真实标签 (如果有的话)
# 运行聚类
kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
labels_pred = kmeans.fit_predict(X)
# 轮廓系数 (越高越好)
s_score = silhouette_score(X, labels_pred)
# Calinski-Harabasz 指数 (越高越好)
ch_score = calinski_harabasz_score(X, labels_pred)
# Davies-Bouldin 指数 (越低越好)
db_score = davies_bouldin_score(X, labels_pred)
# 如果有真实标签,计算外部指标
# ari_score = adjusted_rand_score(labels_true, labels_pred)