1、常用的模型分类评价指标#
准确率 Accuracy#
准确率:预测正确的结果占总样本的百分比
code
from sklearn.metrics import accuracy_score
y_pred = [0, 2, 1, 3]
y_true = [0, 1, 2, 3]
accuracy_score(y_true, y_pred)
缺点
样本不平衡时准确率会失效,比如判断浏览购物网站是否会购买,100 个浏览用户也许只有 1 个会购买,那么模型无脑拍不会购买,准确率有 99%
1️⃣ 处理样本不平衡 :重采样、欠采样、过采样 等
2️⃣ 更换合适指标: F1-Score ,它不仅考虑模型预测的错误数量,还考虑错误类型
混淆矩阵#
看对角线
code
import matplotlib.pyplot as plt
import scikitplot as skplt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits
X, y = load_digits(return_X_y=True)
clf = RandomForestClassifier(n_estimators=5, max_depth=5, random_state=1)
clf.fit(X, y)
clf.score(X, y)
pred = clf.predict(X)
skplt.metrics.plot_confusion_matrix(y, pred, normalize=True)
plt.show()
二分类对角线衍生指标#
-
真正例 (True Positive, TP):被模型预测为正的正样本;
-
假正例 (False Positive, FP):被模型预测为正的负样本;
-
假负例 (False Negative, FN):被模型预测为负的正样本;
-
真负例 (True Negative, TN):被模型预测为负的负样本;
-
精确率 Precision= TP/(TP+FP)
-
召回率 Recall=TP/(TP+FN)
-
F1 score=2*(P * R)/(P+R)
精确率 Precision#
模型预测为 1,真正是 1 所占的百分比
案例:
-
在预测股票的时候,我们更关心精准率,即我们预测升的那些股票里,真的升了有多少,因为那些我们预测升的股票都是我们投钱的。
-
比如对于罪犯的预测,我们希望预测结果是非常准确的,即使放过了一些真正的罪犯,也不能错怪一个好人
code
from sklearn.metrics import precision_score
from sklearn.metrics import accuracy_score
y_true = [0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
y_pred = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1]
# None 每个类各自精确率(不平均)
precision_score(y_true, y_pred, average=None)
# [0.375 1. ]
# 'macro' 每类精确率的平均(不加权)
precision_score(y_true, y_pred, average='macro')
# (0.375 + 1.)/2 = 0.6875
# 'weighted' 按每类样本数加权的平均精确率
precision_score(y_true, y_pred, average='weighted')
# 0.375*0.3+1*0.7 = 0.8125
# 'micro' 全部样本总体精确率
precision_score(y_true, y_pred, average='micro')
# 等于Accuracy 0.5
accuracy_score(y_true, y_pred)
# 0.5
召回率 Recall#
真是 1 的样本,再次被模型召回的概率,也叫查全率
案例:
-
假如一共发生了 10 次地震,我们情愿发出 1000 次警报,这样能把这 10 次地震都涵盖进去(此时 recall 是 100%,precision 是 1%),也不要发出 100 次警报,其中有 8 次地震给预测到了,但漏了 2 次(此时 recall 是 80%,precision 是 8%)
-
而在预测病患的场景下,我们更关注召回率,即真的患病的那些人里我们预测错了情况应该越少越好,因为真的患病如果没有检测出来,结果其实是很严重的,之前那个无脑的算法,召回率就是 0。
code
from sklearn.metrics import recall_score
from sklearn.metrics import accuracy_score
y_true = [0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
y_pred = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1]
recall_score(y_true, y_pred, average=None)
# 3个0都被召回了,7个1只有2个被召回 [1. 0.28571429]
recall_score(y_true, y_pred, average='macro')
# (1. + 0.28571429)/2 = 0.6428571428571428
recall_score(y_true, y_pred, average='weighted')
# 1*0.3+0.28571429*0.7 = 0.5
recall_score(y_true, y_pred, average='micro')
# 等于Accuracy =0.5
accuracy_score(y_true, y_pred)
# 0.5
为什么 precision 和 recall 矛盾#
1️⃣ 如果想要更高的 recall,那么就要让模型的预测能覆盖到更多的样本,但是这样模型就更有可能犯错,也就是说 precision 会比较低。
2️⃣ 如果模型很保守,只能检测出它很确定的样本,那么其 precision 会很高,但是 recall 会相对低。
F1 score#
调和平均数#
- 什么是调和平均数?
🔴 由于它是根据变量的倒数计算的,所以又称倒数平均数
-
一段路程 2 公里,前 1 公里速度 20km/h,后 1 公里速度 10km/h,求平均速度?
简单平均:
(20+10)/2 = 15按时间加权:
总时间 = (1/20 + 1/10)= 0.15
第一公里时间:1/20=0.05 权重 33%
第二公里时间:1/10=0.1 权重 66%
平均时间 = 20 * 33% + 10 * 66% = 13.33
调和平均
为什么 F1 要用调和平均数?#
- 如果简单平均,P=0.8,R=0.8 与 P=0.7,R=0.9 的算术平均一样都是 0.8,类似预测与召回是可替代的。
- 调和平均相当于添加了惩罚机制:越高的数值给越低的权重(比如上面例子中,20 速度的权重只有 33%)
从而避免在使用算术平均时,出现由于其中一个很高,另一个较低,造成的均值虚高的现象。(假设 p 和 r 一个是 1.0 一个是 0.1, 算术平均会接近 0.5 而调和平均接近 0.2)
F1 值背后的思想就是,precision 和 recall 二者都平平的算法比一个指标巨好另一个指标巨差的算法靠谱
总结:两个好才是真的好
code
from sklearn.metrics import f1_score
from sklearn.metrics import accuracy_score
y_true = [0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
y_pred = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1]
f1_score(y_true, y_pred, average=None)
# [0.54545455 0.44444444]
f1_score(y_true, y_pred, average='macro')
# (0.54545455+0.44444444)/2 = 0.4949494949494949
f1_score(y_true, y_pred, average='weighted')
# 0.54545455*0.3+0.44444444*0.7 = 0.47474747474747475
f1_score(y_true, y_pred, average='micro')
# 等于Accuracy 0.5
accuracy_score(y_true, y_pred)
# 0.5