机器学习系列(三十)——F1 Score与Precision-R
本篇主要内容:F1 Score,Precision-Recall的平衡,P-R曲线
F1 Score
上篇我们提到,精准率和召回率这两个指标有时精准率低一些有时召回率低一些,有时可能都低。那么实际中用哪个指标比较好呢?这一般和应用场景有关,对于有些场景,我们更注重精准率,比如股票预测,假设预测的是一个二分类问题:股票会升还是降,显然为了利润我们关注的是升(即上升为类1),为什么这种情况下精准率指标更好呢?因为精准率是所有分类为1的预测中有多少是正确的,对本例也就是预测未来股票上升有多少是对的,这更复合我们的利润最大决策。而召回率是实际上升的股票中我们预测对了多少,基于风险投资理念,有很多股票会上升的时刻,我们就算落掉一些也是没有关系的,没有投资进去也就没有损失,更重要的是我们的决策中有多少能赚钱,所以在这种场景下,精准率更好。
而如果在医疗领域,则是召回率更加重要,也就是要能在实际得病的人中尽量预测的更加准确,我们不想漏掉任何真正患病的人,这样才更有可能挽回一些人的生命,而精准率低些(没病的被预测为有病)并不会导致特别严重的后果,只是进行了一些过度医疗。
不过并非所有场景都如上面两个例子般极端,只关注精准率或只关注召回率。更多的我们希望得到它们之间的一种平衡,即同时关注精准率和召回率。这种情况下我们有一个新的指标:F1 Score,它的计算公式为:
如果两个都为0,则定义F1=0。本质上F1是精准率和召回率的调和平均,调和平均一个很重要的特性是如果两个数极度不平衡(一个很大一个很小),最终的的结果会很小,只有两个数都比较高时,调和平均才会比较高,这样便达到了平衡精准率和召回率的目的。下面编程实现一下F1 Score:
import numpy as np
def f1_score(precision,recall):
try:
return 2*precision*recall/(precision+recall)
except:
return 0.0
输入几组值进行测试:
调和平均测试下面在真实数据集上来使用F1 Score,分类算法使用逻辑回归,数据集和上篇文章相同,是人工处理为2类的手写数字数据集:
import numpy as np
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()
'''人工加入偏斜'''
y[digits.target==9]=1
y[digits.target!=9]=0
'''10分类变为2分类,用Logistic分类'''
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=666)
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X_train,y_train)
log_reg.score(X_test,y_test)
准确率:
准确率精准率和召回率:
精准率和召回率from sklearn.metrics import f1_score
f1_score(y_test,y_predict)
F1 Score:
F1_Score可以看到F1的值是综合了精准率和召回率的,用它来衡量模型性能是比准确率要好的。
Precision-Recall的平衡
精准率和召回率是相互制约的,如果想要精准率提高,召回率则会下降,如果要召回率提高,精准率则会下降,我们需要找到二者之间的一个平衡。
下面通过调整决策边界导致的分类结果变化来观察一下这个现象,不过Logistic回归中并没有直接能调整决策边界的函数,可以通过decision_score来间接调节:
log_reg.decision_function(X_test)[:10]
decision_score的前10个值展示:
d_c其值就是样本特征带入决策边界函数得到的结果,对于其中小于0的就被判别为类别0了,大于0的则是类别1。默认的决策边界函数是,此时如果需要调节边界比如要调节为,只需在计算时让再与0比较即可:
'''如果阀值为5'''
y_predict_2 = np.array(decision_scores >= 5,dtype=int)
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,y_predict_2)
此时的混淆矩阵为:
混淆矩阵精准率和召回率:
精准率和召回率F1 Score:
F1 Score再调节决策边界为:
'''如果阀值为-5'''
y_predict_3 = np.array(decision_scores >= -5,dtype=int)
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test,y_predict_3)
精准率、召回率和F1 Score:
精准率召回率和F1从上面的结果可以观察到当精准率升高时召回率相应下降,召回率升高时精准率相应下降,我们希望模型尽量有比较平横的精准率和召回率,为了更好地观察它们之间的关系,可以绘制精准率召回率曲线(P-R曲线):
import matplotlib.pyplot as plt
precisions = []
recalls = []
thresholds = np.arange(np.min(decision_scores),np.max(decision_scores))
for threshold in thresholds:
y_predict = np.array(decision_scores >= threshold,dtype=int)
precisions.append(precision_score(y_test,y_predict))
recalls.append(recall_score(y_test,y_predict))
plt.plot(thresholds,precisions)
plt.plot(thresholds,recalls)
plt.show()
P、R随阀值变化曲线
P-R曲线
从P-R曲线看出精准率和召回率是相互制约的,召回率的升高会带来精准率的下降。同样可以用sklearn中自带的P-R曲线绘制函数来绘制:
from sklearn.metrics import precision_recall_curve
precisions, recalls, thresholds = precision_recall_curve(y_test,decision_scores)
plt.plot(thresholds,precisions[:-1])
plt.plot(thresholds,recalls[:-1])
plt.show()
'''sklearn自动寻找最优部分的数据'''
P、R随阀值变化曲线
P-R曲线
在P-R曲线中,突然下降的位置很可能就是二者平衡的一个位置。
整体的,如果将两个模型的P-R曲线绘制到一个图中,则靠外的那个模型显然更优,也就是与两个轴围成的面积大的那个模型更好。