在 scikit-learn 中使用交叉验证时绘制 Precision-Recall 曲线

Posted

技术标签:

【中文标题】在 scikit-learn 中使用交叉验证时绘制 Precision-Recall 曲线【英文标题】:Plotting Precision-Recall curve when using cross-validation in scikit-learn 【发布时间】:2014-12-22 15:26:19 【问题描述】:

我正在使用交叉验证来评估具有 scikit-learn 的分类器的性能,并且我想绘制 Precision-Recall 曲线。我在 scikit-learn 的网站上找到了an example 来绘制 PR 曲线,但它没有使用交叉验证进行评估。

使用交叉验证时如何在 scikit learn 中绘制 Precision-Recall 曲线?

我做了以下,但我不确定这是否是正确的方法(伪代码):

for each k-fold:

   precision, recall, _ =  precision_recall_curve(y_test, probs)
   mean_precision += precision
   mean_recall += recall

mean_precision /= num_folds
mean_recall /= num_folds

plt.plot(recall, precision)

你怎么看?

编辑:

它不起作用,因为precisionrecall 数组的大小在每次折叠后都不同。

有人吗?

【问题讨论】:

【参考方案1】:

不是在每次折叠后记录精度和召回值,而是在每次折叠后存储测试样本的预测。接下来,收集所有测试(即袋外)预测并计算精度和召回率。

 ## let test_samples[k] = test samples for the kth fold (list of list)
 ## let train_samples[k] = test samples for the kth fold (list of list)

 for k in range(0, k):
      model = train(parameters, train_samples[k])
      predictions_fold[k] = predict(model, test_samples[k])

 # collect predictions
 predictions_combined = [p for preds in predictions_fold for p in preds]

 ## let predictions = rearranged predictions s.t. they are in the original order

 ## use predictions and labels to compute lists of TP, FP, FN
 ## use TP, FP, FN to compute precisions and recalls for one run of k-fold cross-validation

在一次完整的 k 折交叉验证运行下,预测器对每个样本进行一个且仅一个预测。给定 n 个样本,您应该有 n 个测试预测。

(注意:这些预测与训练预测不同,因为预测器对每个样本进行预测,而之前从未见过它。)

除非您使用 leave-one-out 交叉验证,否则 k 折交叉验证通常需要对数据进行随机分区。理想情况下,您会进行重复(和分层)k-fold 交叉验证。然而,组合来自不同轮次的精确召回曲线并不简单,因为您不能在精确召回点之间使用简单的线性插值,这与 ROC 不同(请参阅 Davis and Goadrich 2006)。

我个人使用 Davis-Goadrich 方法在 PR 空间中插值计算了 AUC-PR(随后进行数值积分),并使用来自重复分层 10 折交叉的 AUC-PR 估计值比较了分类器验证。

为了绘制一个漂亮的图,我展示了其中一个交叉验证轮次的代表性 PR 曲线。

当然,根据数据集的性质,还有许多其他评估分类器性能的方法。

例如,如果您的数据集中(二进制)标签的比例没有偏差(即大约为 50-50),您可以使用更简单的 ROC 分析和交叉验证:

从每个折叠中收集预测并构建 ROC 曲线(如前所述),收集所有 TPR-FPR 点(即取所有 TPR-FPR 元组的并集),然后绘制可能平滑的组合点集。可选地,使用简单的线性插值和复合梯形法进行数值积分计算AUC-ROC。

【讨论】:

对不平衡数据使用 PR 而不是 ROC 有什么解释吗?在不平衡的情况下,ROC 是无用的还是缺乏对模型的有意义的洞察力,为什么?感谢您的任何回复。 我找到了相关论文,需要时间阅读:autonlab.org/icml_documents/camera-ready/… ROC AUC 当然可以用于不平衡数据,事实上,即使在极端情况下,它通常也是不平衡的优选指标之一。它具有许多优于 PR 的统计特性。可以在此处查看 David Powers 的回答并参考 stats.stackexchange.com/questions/7207/…。然而,在大海捞针类型的问题中,我们非常关心在阳性分数中不会出现误报,PR 比 ROC 更敏感,尽管在 ROC 中,当 N>>P 时特异性会略有下降,这仍然会被拾起.【参考方案2】:

这是目前使用交叉验证为 sklearn 分类器绘制 Precision Recall 曲线的最佳方法。最好的部分是,它绘制了所有类的 PR 曲线,因此您也可以获得多条外观整洁的曲线

from scikitplot.classifiers import plot_precision_recall_curve
import matplotlib.pyplot as plt

clf = LogisticRegression()
plot_precision_recall_curve(clf, X, y)
plt.show()

该函数自动负责交叉验证给定的数据集,连接所有不折叠的预测,并计算每个类的 PR 曲线 + 平均 PR 曲线。这是一个为您处理一切的单行函数。

Precision Recall Curves

免责声明:请注意,这使用了我构建的 scikit-plot 库。

【讨论】:

我们如何知道在 plot_precision_recall_curve() 中使用了多少折交叉验证?

以上是关于在 scikit-learn 中使用交叉验证时绘制 Precision-Recall 曲线的主要内容,如果未能解决你的问题,请参考以下文章

Scikit-Learn:在交叉验证期间避免数据泄漏

在 scikit-learn 中跨多个模型进行交叉验证时如何保持相同的折叠?

如何在 scikit-learn 中使用交叉验证获得预测概率

在 Scikit-Learn 中获得线性回归的大交叉验证分数

在 SciKit-Learn 中使用 XGBoost 交叉验证进行网格搜索和提前停止

如何在 scikit-learn 中正确执行交叉验证?