以逻辑回归为例,介绍分类结果的评价方式。python
对于极度偏斜的数据,使用分类准确度来评判模型的好坏是不恰当的,精确度和召回率是两个更好的指标来帮助咱们断定模型的好快。git
精准率和召回率是存在于混淆矩阵之上的,以二分类为例,分类0是偏斜数据中占优点的一方,将关注的重点放在分类为1上,其混淆矩阵以下:github
真实值预测值 | 0 | 1 |
---|---|---|
0 | 9978(TN) | 12(FP) |
1 | 2(FN) | 8(TP) |
TN、FN、FP、TP 的实现以下(y_true
表示真实分类, y_predict
表示预测结果):app
import numpy as np def TN(y_true, y_predict): return np.sum((y_true == 0) & (y_predict == 0)) def FP(y_true, y_predict): return np.sum((y_true == 0) & (y_predict == 1)) def FN(y_true, y_predict): return np.sum((y_true == 1) & (y_predict == 0)) def TP(y_true, y_predict): return np.sum((y_true == 1) & (y_predict == 1))
混淆矩阵的结果为:dom
def confusion_matrix(y_test, y_predict): return np.array([ [TN(y_test, y_log_predict), FP(y_test, y_log_predict)], [FN(y_test, y_log_predict), TP(y_test, y_log_predict)] ])
Scikit Learn 中封装了混淆矩阵方法 confusion_matrix()
:测试
from sklearn.metrics import confusion_matrix confusion_matrix(y_true, y_predict)
有了混淆矩阵,精准率和召回率久很好表示了。spa
精准率表示预测分类结果中预测正确的数量的占比,即:code
$$ precision=\frac{TP}{TP+FP} $$orm
将其用代码表示为:ip
def precision_score(y_true, y_predict): tp = TP(y_true, y_predict) fp = FP(y_true, y_predict) try: return tp / (tp + fp) except: return 0.0
召回率表示真实分类中被预测正确的数量的占比,即:
$$ recall=\frac{TP}{TP+FN} $$
将其用代码表示为:
def recall_score(y_true, y_predict): tp = TP(y_true, y_predict) fn = FN(y_true, y_predict) try: return tp / (tp + fn) except: return 0.0
Scikit Learn 中也封装了计算精准率的方法 precision_score()
和计算召回率的方法 recall_score()
:
from sklearn.metrics import precision_score precision_score(y_true, y_predict) from sklearn.metrics import recall_score recall_score(y_true, y_predict)
精准率和召回率这两个指标的侧重点不一样,有的时候咱们注重精准率(如股票预测),有的时候咱们注重召回率(病人诊断)。但有时候又须要把二者都考虑进行,此后就可使用 F1 Score 指标。
F1 Score 是精准率和召回率的调和平均值,公式为:
$$ \frac{1}{F1}=\frac{1}{2}(\frac{1}{precision}+\frac{1}{recall}) $$
即:$F1=\frac{2·precision·recall}{precesion+recall}$,而且 F1 Score 的取值是在区间 $[0, 1]$ 之中的。
代码实现为:
def f1_score(y_true, y_predict): precision = precision_score(y_true, y_predict) recall = recall_score(y_true, y_predict) try: return 2 * precision * recall / (precision + recall) except: return 0.0
Scikit Learn 中封装了方法 f1_score()
来计算 F1 Score:
from sklearn.metrics import f1_score f1_score(y_true, y_predict)
Scikit Learn 的逻辑回归中的几率公式为 $\hat p=\sigma(\theta^T·x_b)$ ,其决策边界为 $\theta^T·x_b=0$,可是若是决策边界不为0会如何呢?
假定决策边界为 $\theta^T·x_b=threshold$,当 threshold 的取值不一样(0、大于0的某个值、小于0的某个值),对应的精确度和召回率也不一样。如图:
圆形和星形是不一样的的分类,而且重点放在星形的分类上,能够看出,threshold 的取值越大时,精确率越高,而召回率越低。
若是要更改决策边界,逻辑回归的 decision_function()
返回传入数据的 $\theta^T·x_b$ 计算结果 decision_scores,接着再构建一个新的预测结果;如代码所示,设定 decision_scores >= 5
(默认decision_scores >= 0
) 的预测结果才为1,其他为0:
from sklearn.linear_model import LogisticRegression log_reg = LogisticRegression() # X_train, y_train 为训练数据集 log_reg.fit(X_train, y_train) # X_test,y_test 为测试数据集 decision_scores = log_reg.decision_function(X_test) y_log_predict_threshold = np.array(decision_scores >= 5, dtype='int')
如此能够获得不一样的 y_log_predict_threshold
,进而获得不一样的精准率和召回率。
以手写数字识别数据为例,将标记为9的数据分类为1,其他分类为0:
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 from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=500)
接着训练逻辑回归模型:
from sklearn.linear_model import LogisticRegression log_reg = LogisticRegression() log_reg.fit(X_train, y_train)
获取测试数据集 X_test 对应的 $\theta^T·x_b$ 取值:
decision_scores = log_reg.decision_function(X_test)
在 decision_scores 的取值区间划分为一系列值 thresholds
,并将其中的值依次做为决策边界,进而获得不一样的精确率和召回率
from sklearn.metrics import precision_score from sklearn.metrics import recall_score precisions = [] recalls = [] thresholds = np.arange(np.min(decision_scores), np.max(decision_scores), 0.1) 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))
将精确率、召回率与决策边界的关系绘制如图:
精确度与召回率的关系,即 Precision-Recall 曲线则为:
Scikit Learn 中提供的 precision_recall_curve()
方法传入真实分类结果和 decision_scores,返回 precisions、recalls 和 thresholds:
from sklearn.metrics import precision_recall_curve precisions, recalls, thresholds = precision_recall_curve(y_test, decision_scores)
Precision-Recall 曲线越靠外(即面积越大)则表示模型越好。
在过度类中,Sckit Learn 提供的 confusion_matrix()
能够直接返回多分类的混淆矩阵,而对于精确率和召回率,则要在 Sckit Learn 提供的方法中指定 average
参数值为 micro
,如:
from sklearn.metrics import precision_score precision_score(y_test, y_predict, average='micro')
对于用图形面积判断模型好快,ROC 曲线比 Precision-Recall 曲线要好。
ROC 曲线涉及两个指标,TPR 和 FPR。TPR 就是召回率,即:$TPR=\frac{TP}{TP+FN}$;FPR 表示真实分类(偏斜数据中占优点的分类)中被预测错误的数量的占比,即:$FPR=\frac{FP}{TN+FP}$。实现代码为:
def TPR(y_true, y_predict): tp = TP(y_true, y_predict) fn = FN(y_true, y_predict) try: return tp / (tp + fn) except: return 0.0 def FPR(y_true, y_predict): fp = FP(y_true, y_predict) tn = TN(y_true, y_predict) try: return fp / (fp + tn) except: return 0.0
对于决策边界的不一样,这两个指标的变化趋势是一致的。仍是以上面的手写数字识别数据为例,计算不一样决策边界下的两指标的值为:
fprs = [] tprs = [] for threshold in thresholds: y_predict = np.array(decision_scores >= threshold, dtype='int') fprs.append(FPR(y_test, y_predict)) tprs.append(TPR(y_test, y_predict))
做出的 TPR 和 FPR 的关系图(即 ROC 曲线)为:
Scikit Learn 中提供的 roc_curve()
方法传入真实分类结果和 decision_scores,返回 TPR、FPR 和 thresholds:
from sklearn.metrics import roc_curve fprs, tprs, thresholds = roc_curve(y_test, decision_scores)
roc_auc_score()
方法传入真实分类结果和 decision_scores,返回 ROC 曲线表示的面积。
from sklearn.metrics import roc_auc_score roc_auc_score(y_test, decision_scores)
面积越大,则模型越好。