我正在处理一个非常不平衡的分类问题,我正在使用AUPRC作为插入符号的度量标准。对于来自插入符号的AUPRC和来自PRROC包的AUPRC中的测试集,我得到了非常不同的结果。
为了方便起见,可重复的示例使用来自包mlbench的PimaIndiansDiabetes数据集:
rm(list=ls())
library(caret)
library(mlbench)
library(PRROC)
#load data, renaming it to 'datos'
data(PimaIndiansDiabetes)
datos=PimaIndiansDiabetes[,1:9]
# training and test
set.seed(998)
inTraining <- createDataPartition(datos[,9], p = .8, list = FALSE)
training <-datos[ inTraining,]
testing <- datos[ -inTraining,]
#training
control=trainControl(method = "cv",summaryFunction = prSummary,
classProbs = TRUE)
set.seed(998)
rf.tune <-train(training[,1:8],training[,9],method ="rf",
trControl=control,metric="AUC")
#evaluating AUPRC in test set
matriz=cbind(testing[,9],predict(rf.tune,testing[,1:8],type="prob"),
predict(rf.tune,testing[,1:8]))
names(matriz)=c("obs",levels(testing[,9]),"pred")
prSummary(matriz,levels(testing[,9]))
#calculating AUPRC through pr.curve
#checking positive class
confusionMatrix(predict(rf.tune,testing[,1:8]),testing[,9],
mode = "prec_recall")#'Positive' Class : neg
#preparing data for pr.curve
indice_POS=which(testing[,9]=="neg")
indice_NEG=which(testing[,9]=="pos")
#the classification scores of only the data points belonging to the
#positive class
clas_score_POS=predict(rf.tune,testing[,1:8],type="prob")[indice_POS,1]
#the classification scores of only the data points belonging to the
#negative class
clas_score_NEG=predict(rf.tune,testing[,1:8],type="prob")[indice_NEG,2]
pr.curve(clas_score_POS,clas_score_NEG)
PRROC的值为0.9053432,来自caret prSummary的值为0.8714607。在我的不平衡情况下,差异更大(AUPRC = 0.1688446,SMOTE重新采样 - 通过control$sampling <- "smote"
-和0.01429与PRROC。)
这是因为在这些包中计算AUPRC的方法不同,或者我做错了什么?
更新:我在代码中找不到错误。在回答错误后,我想发表一些看法:
当你做prSummary(matriz,levels(testing[,9]))
时,你得到了
AUC Precision Recall F
0.8714607 0.7894737 0.9000000 0.8411215
这符合
confusionMatrix(predict(rf.tune,testing[,1:8]),testing[,9],mode = "prec_recall")
Confusion Matrix and Statistics
Reference
Prediction neg pos
neg 90 23
pos 10 30
Accuracy : 0.7843
95% CI : (0.7106, 0.8466)
No Information Rate : 0.6536
P-Value [Acc > NIR] : 0.0003018
Kappa : 0.4945
Mcnemar's Test P-Value : 0.0367139
Precision : 0.7965
Recall : 0.9000
F1 : 0.8451
Prevalence : 0.6536
Detection Rate : 0.5882
Detection Prevalence : 0.7386
Balanced Accuracy : 0.7330
'Positive' Class : neg
与:
> MLmetrics::PRAUC(y_pred = matriz$neg, y_true = ifelse(matriz$obs == "neg", 1, 0))
[1] 0.8714607
正如您在最后一行中所看到的,“正面”类是“否定”,我认为错误将正类视为“pos”,因此我们有不同的指标。此外,当您打印经过训练的射频时,结果也与预期的AUC~0.87一致:
> rf.tune
Random Forest
615 samples
8 predictor
2 classes: 'neg', 'pos'
No pre-processing
Resampling: Cross-Validated (10 fold)
Summary of sample sizes: 554, 553, 553, 554, 554, 554, ...
Resampling results across tuning parameters:
mtry AUC Precision Recall F
2 0.8794965 0.7958683 0.8525 0.8214760
5 0.8786427 0.8048463 0.8325 0.8163032
8 0.8528028 0.8110820 0.8325 0.8192225
在这种情况下,我并不担心0.87caret-0.9PRROC的差异,但在非平衡情况下我非常担心0.1688446插入/ 0.01429 PRROC。这可能是因为在不平衡的情况下,不同实施下的数字差异会加强吗?如果实现中存在数字差异,那么它们在测试集中是如何相同的0.8714607
?
我相信你在代码中犯了几个错误。
首先,caret::prSummary
使用MLmetrics::PRAUC
来计算AUPRC。它应该像这样定义:
MLmetrics::PRAUC(y_pred = matriz$pos, y_true = ifelse(matriz$obs == "pos", 1, 0))
#output
0.7066323
使用正类概率和真正类的数字0/1向量(1表示正数)
使用以下方法获得相同的结果:
caret::prSummary(matriz, levels(testing[,9])[2])
MLmetrics::PRAUC
使用ROCR::prediction
构建曲线:
pred_obj <- ROCR::prediction(matriz$pos, ifelse(matriz$obs == "pos", 1, 0))
perf_obj <- ROCR::performance(pred_obj, measure = "prec",
x.measure = "rec")
并且曲线看起来像:
ROCR::plot(perf_obj, ylim = c(0,1))
当使用PRROC::pr.curve
时,有几种方法可以定义输入。一种是为阳性观察提供正类的概率向量,为阴性观察提供正类的概率向量:
preds <- predict(rf.tune,
testing[,1:8],
type="prob")[,2] #prob of positive class
preds_pos <- preds[testing[,9]=="pos"] #preds for true positive class
preds_neg <- preds[testing[,9]=="neg"] #preds for true negative class
PRROC::pr.curve(preds_pos, preds_neg)
#truncated output
0.7254904
这两个数字(由PRROC::pr.curve
和MLmetrics::PRAUC
获得)不匹配
然而曲线
plot(PRROC::pr.curve(preds_pos, preds_neg, curve = TRUE))
看起来就像上面使用ROCR::plot
获得的那个。
去检查:
res <- PRROC::pr.curve(preds_pos, preds_neg, curve = TRUE)
ROCR::plot(perf_obj, ylim = c(0,1), lty = 2, lwd = 2)
lines(res$curve[,1], res$curve[,2], col = "red", lty = 5)
他们是一样的。因此,所获得的区域的差异是由于所提到的包中的不同实现。
可以通过查看以下内容来检查这些实现:
MLmetrics:::Area_Under_Curve #this one looks pretty straight forward
PRROC:::compute.pr #haven't the time to study this one but if I had to bet I'd say this one is more accurate for step like curves.