乐趣区

关于人工智能:使用阈值调优改进分类模型性能

阈值调优是数据迷信中一个重要且必要的步骤。它与应用程序畛域密切相关,并且须要一些畛域内的常识作为参考。在本文中将演示如何通过阈值调优来进步模型的性能。

用于分类的罕用指标

个别状况下咱们都会应用准确率 accuracy 来评估分类的性能,然而有很多状况下 accuracy 不足以报告分类模型的性能,所以就呈现了很多其余的指标:精确度 Precision、召回率 Recall、F1 分数 F1 score 和特异性 Specificity。除此以外,还有 ROC 曲线、ROC AUC 和 Precision-Recall 曲线等等。

让咱们首先简略解释这些指标和曲线的含意:

精确度 Precision:所有正例中真正正例的数量。P=TP/(TP+FP)

召回率 Recall:正例数超过真正例数加上假负例数。R=TP/(TP+FN)

F1 分数 F1 score:Precision 和 Recall 之间的和谐平均值。

特异性 Specificity:真负例的数量超过真负例的数量加上假正例的数量。Spec=TN(TN+FP)

(ROC) 曲线:该曲线显示了真正例率和假正例率之间的衡量。代表模型的性能。

ROC 曲线下面积(AUC):ROC 曲线下面积。如果这个面积等于 1,咱们就有了一个完满的分类器。如果它等于 0.5,那么就是一个随机的分类器。

Precision-Recall 曲线:这条曲线显示了不同阈值下的精度和召回值。它用于可视化 Precision 和 Recall 之间的衡量。

一般来说,咱们必须思考所有这些指标和曲线。为了将这些内容显示在一起查看,这里定义了一个办法:

 def make_classification_score(y_test, predictions, modelName):
     tn, fp, fn, tp = confusion_matrix(y_test, predictions).ravel() # ravel() used to convert to a 1-D array
     prec=precision_score(y_test, predictions)
     rec=recall_score(y_test, predictions)
     f1=f1_score(y_test, predictions)
     acc=accuracy_score(y_test, predictions)
     # specificity
     spec=tn/(tn+fp)
 
     score = {'Model': [modelName], 'Accuracy': [acc], 'f1': [f1], 'Recall': [rec], 'Precision': [prec], \
         'Specificity': [spec], 'TP': [tp], 'TN': [tn], 'FP': [fp], 'FN': [fn], 'y_test size': [len(y_test)]}
     df_score = pd.DataFrame(data=score)
     return df_score

“预测概率”技巧

当咱们测试和评估模型时,将预测的 Y 与测试集中的 Y 进行比拟。然而这里不倡议应用 model.predict(X_test) 办法,间接返回每个实例的标签,而是间接返回每个分类的概率。例如 sklearn 提供的 model.predict_proba(X_test) 的办法来预测类概率。而后咱们就能够编写一个办法,依据决策阈值参数返回每个实例的最终标签。

 def probs_to_prediction(probs, threshold):
     pred=[]
     for x in probs[:,1]:
         if x>threshold:
             pred.append(1)
         else:
             pred.append(0)
     return pred

如果设置 thresh = 0.5 那么则和调用 model.predict(X_test) 办法失去的后果是雷同的,然而应用概率咱们能够测试不同的阈值的性能体现。

如果扭转阈值则会扭转模型的性能。这里能够依据应用程序畛域抉择一个阈值来最大化重要的度量 (通常是精度或召回率),比方在 kaggle 的较量中常常会呈现 thresh = 0.4xx 的状况。

抉择重要的度量

最大化的重要指标是什么呢? 如何确定?

在二元分类工作中,咱们的模型会呈现两种类型的谬误:

第一类谬误: 预测 Y 为 True,但它实际上是 False。也称为假正例谬误。

第二类谬误: 预测 Y 为 False,但它实际上是 True。也称为假负例谬误。

谬误分类实例的数量决定了模型的好坏。但这些谬误并不同等重要,对于不必的畛域有着不同的要求,比方医学的检测和金融的风控中,须要尽量减小假负例也就是防止第二类谬误,须要最小化假负例的数量,那么最大化的重要指标是召回率。

同理, 如果要防止第一类谬误,咱们须要最小化假正例的数量,所以最大化的重要指标是精度。

为了最大化指标,咱们能够挪动阈值,直到咱们在所有指标之间达成良好的均衡,这时就能够应用 Precision-Recall 曲线,当然也能够应用 ROC 曲线。

然而要阐明的是,咱们不能最大化所有指标,因为通过指标的定义就能看到这是不可能的。

阈值优化

假如咱们正在解决一个二元分类工作的逻辑回归模型。咱们曾经进行了训练、超参数调优和测试阶段。该模型曾经过穿插验证。也就是说,基本上能做的事件咱们都曾经做了,然而还是心愿可能有一些其余的形式来优化模型,那么则能够试试调整模型的阈值。

对于 sklearn 来说应用 model.predict_proba(X_test) 办法来取得类概率,如果应用神经网络的化个别都会输入的是每个类的概率,所以咱们这里以 sklearn 为例,应用这个概率值:

  • 计算 ROC AUC,它等于 0.9794
  • 计算并绘制 ROC 曲线
  • 计算并绘制精度 - 召回率曲线

上面的代码块示意这些步骤:

 def probs_to_prediction(probs, threshold):
     pred=[]
     for x in probs[:,1]:
         if x>threshold:
             pred.append(1)
         else:
             pred.append(0)
     return pred
 
 # getting predicted probability values
 probability = model.predict_proba(X_test)
 
 # calculate ROC AUC score. AUC = 0.9794
 print("Logit: ROC AUC = %.4f" % roc_auc_score(y_test, probability[:, 1]))
 
 # calculate and plot the ROC curve
 model_fpr, model_tpr, _ = roc_curve(y_test, probability[:, 1])
 plt.plot(model_fpr, model_tpr, marker='.', label='Logit')
 plt.xlabel('False Positive Rate')
 plt.ylabel('True Positive Rate (recall)')
 plt.legend()
 plt.title("ROC Curve")
 plt.show()
 
 # calculate and plot the Precision-Recall curve
 model_precision, model_recall, thresholds = precision_recall_curve(y_test, probability[:, 1])
 plt.plot(model_recall, model_precision, marker='.', label='Logit')
 plt.xlabel('Recall')
 plt.ylabel('Precision')
 plt.legend()
 plt.title('Precision-Recall Curve')
 plt.show()

下图的曲线。能够看到模型的性能很好。

在本例中,假如在咱们的理论利用中 FP 的老本 > FN 的老本,所以抉择一个阈值在不升高召回率的状况下最大化精度。应用 Precision-Recall 曲线来对一个可能的阈值进行初始抉择。在上面的代码中,绘制了带有候选阈值的 Precision-Recall 曲线。

 plt.plot(model_recall, model_precision, marker='.', label='Logit')
 plt.plot(model_recall[43000], model_precision[43000], "ro", label="threshold")
 plt.xlabel('Recall')
 plt.ylabel('Precision')
 plt.legend()
 plt.title('Precision and Recall values for a chosen Threshold')
 plt.show()

这样就能够应用选定的阈值来取得最终的分类标签并计算性能指标。并且能够屡次进行抉择不同阈值进行比照。

 print("Threshold value = %.4f" % thresholds[43000])
 
 # results with the chosen threshold
 predictions = probs_to_prediction(probability, thresholds[43000])
 make_classification_score(y_test, predictions, "logit, custom t")

下图中能够看到,所选的阈值以召回率为代价来最大化精度。依据咱们利用的决策阈值,雷同的模型能够体现出一些不同的性能。

通过调整阈值并进行后果的比照,一旦对后果称心,模型就能够投入到生产中了。

总结

为分类模型抉择最重要的评估指标并不容易。这种抉择通常与应用程序畛域无关,必须思考谬误分类的代价。在某些状况下,可能有必要征询领域专家确定哪些谬误代表最大的危险。

模型的行为很大水平上受到阈值抉择的影响,咱们能够利用不同的技术来评估模型并调优阈值以取得预期的后果。

https://avoid.overfit.cn/post/81f1646e48c341358391a9a1d3a2dcfd

作者:Edoardo Bianchi

退出移动版