我试图将AUPRC作为我的gbm模型拟合的自定义指标,因为我有一个不平衡的分类器。然而,当我尝试加入自定义指标时,我得到了代码中提到的错误。不确定我做错了什么。
此外,当我直接运行auprcSummary()时,它可以正常工作。但当我尝试将其纳入train()时,它会报错。
library(dplyr) # 用于数据操作 library(caret) # 用于模型构建 library(pROC) # 用于AUC计算 library(PRROC) # 用于精确度-召回率曲线计算 auprcSummary <- function(data, lev = NULL, model = NULL){ index_class2 <- data$Class == "Class2" index_class1 <- data$Class == "Class1" the_curve <- pr.curve(data$Class[index_class2], data$Class[index_class1], curve = FALSE) out <- the_curve$auc.integral names(out) <- "AUPRC" out } ctrl <- trainControl(method = "repeatedcv", number = 10, repeats = 5, summaryFunction = auprcSummary, classProbs = TRUE) set.seed(5627) orig_fit <- train(Class ~ ., data = toanalyze.train, method = "gbm", verbose = FALSE, metric = "AUPRC", trControl = ctrl)
这是我得到的错误:
Error in order(scores.class0) : argument 1 is not a vector
这是因为pr.curve()只接受数值向量作为输入(分数/概率)吗?
回答:
我认为这种方法可以产生一个合适的自定义摘要函数:
library(caret) library(pROC) library(PRROC)library(mlbench) #用于数据集data(Ionosphere)
在pr.curve
函数中,分类分数可以分别为每个类别的数据点提供,即对于正/前景类的数据点作为scores.class0
,对于负/背景类的数据点作为scores.class1
;或者所有数据点的分类分数作为scores.class0
提供,标签作为数值(正类为1,负类为0)作为weights.class0
提供(我从函数帮助中复制了这段内容,如果不清楚我道歉)。
我选择了后者 – 在scores.class0
中提供所有数据点的概率,并在weights.class0
中提供类别分配。
caret指出,如果trainControl对象的classProbs参数设置为TRUE,data中将包含额外的列,这些列包含类别概率。因此,对于Ionosphere
数据,列good
和bad
应该存在:
levels(Ionosphere$Class)#output[1] "bad" "good"
要转换为0/1标签,可以简单地执行:
as.numeric(Ionosphere$Class) - 1
good
将变为1
bad
将变为0
现在我们有了自定义函数所需的所有数据
auprcSummary <- function(data, lev = NULL, model = NULL){ prob_good <- data$good #获取good类的概率 the_curve <- pr.curve(scores.class0 = prob_good, weights.class0 = as.numeric(data$obs)-1, #提供类别标签为0/1 curve = FALSE) out <- the_curve$auc.integral names(out) <- "AUPRC" out}
与其使用data$good
,这只适用于这个数据集,可以提取类别名称并使用它来获取所需的列:
lvls <- levels(data$obs) prob_good <- data[,lvls[2]]
每次更新summaryFunction时,都需要更新trainControl对象,这一点很重要。
ctrl <- trainControl(method = "repeatedcv", number = 10, repeats = 5, summaryFunction = auprcSummary, classProbs = TRUE)orig_fit <- train(y = Ionosphere$Class, x = Ionosphere[,c(1,3:34)], #省略第2列以避免与数据集相关的许多警告 method = "gbm", verbose = FALSE, metric = "AUPRC", trControl = ctrl)orig_fit$results#output shrinkage interaction.depth n.minobsinnode n.trees AUPRC AUPRCSD1 0.1 1 10 50 0.9722775 0.035248824 0.1 2 10 50 0.9758017 0.031433797 0.1 3 10 50 0.9739880 0.033169232 0.1 1 10 100 0.9786706 0.025021835 0.1 2 10 100 0.9817447 0.022768838 0.1 3 10 100 0.9772322 0.033010643 0.1 1 10 150 0.9809693 0.020786016 0.1 2 10 150 0.9824430 0.022843619 0.1 3 10 150 0.9818318 0.02287886
看起来合理