当我使用 Caret 包中的“train”函数创建模型以使用权重进行梯度提升时,在使用“varImp”函数时出现错误,表示它没有检测到树模型。但是当我去掉重量时它就起作用了。
下面的代码会产生错误:
set.seed(123)
model_weights <- ifelse(modelo_df_sseg$FATALIDADES == 1,
yes = (1/table(modelo_df_sseg$FATALIDADES)[2]) * 0.5,
no = (1/table(modelo_df_sseg$FATALIDADES)[1]) * 0.5
)
model <- train(
as.factor(FATALIDADES) ~.,
data = modelo_df_sseg,
method = "xgbTree",
trControl = trainControl("cv", number = 10),
weights = model_weights
)
varImp(model)
但是如果我不施加重量,它就会起作用。
为什么 varImp 无法识别我的树?
编辑 2020 年 9 月 4 日
评论部分的missuse建议使用wts代替权重。现在我收到以下错误:
Error in nominalTrainWorkflow(x = x, y = y, wts = weights, info = trainInfo, : formal argument 'wts' matched by multiple actual arguments
我用 R 内置数据集编写了一个小代码,以便您可以自己测试:
set.seed(123)
basex <- Arrests
model_weights <- ifelse(basex$released == 2,
yes = (1/table(basex$released)[2]) * 0.5,
no = (1/table(basex$released)[1]) * 0.5
)
y = basex$released
x = basex
tc = trainControl("cv", number = 10)
mtd = "xgbTree"
model <- train(
x,
y,
method = mtd,
trControl = tc,
wts = model_weights,
verbose = TRUE
)
也许我创建的权重向量是错误的。但我找不到任何有关“wts”参数的文档。
示例代码有几个问题。
在插入符号中应用权重的正确方法是使用
weights
参数到 train
。
我在评论中错误地建议使用参数
wts
。我的错误是由于 xgbTree 源,特别是行:
if (!is.null(wts))
xgboost::setinfo(x, 'weight', wts)
这表明
wts
可能是正确答案。
让我们看一下示例并解决所有问题
library(caret)
library(car) #for the data set
library(tidyverse) #because I like to use it
data(Arrests)
basex <- Arrests
table(basex$released) #released is the outcome class
No Yes
892 4334
在这里我们看到“是”结果比“否”结果更频繁。这将扭曲预测的概率并有利于倾向于预测“是”的模型。解决这个问题的一种方法是给予“否”观察更高的权重。 “否”观察的有意义的权重将是“是”类的比例,“是”观察的有意义的权重将是“否”类的比例:
model_weights <- ifelse(basex$released == "Yes",
table(basex$released)[1]/nrow(basex),
table(basex$released)[2]/nrow(basex))
权重之和为1
head(data.frame(basex,
weights = model_weights))
released colour year age sex employed citizen checks weights
1 Yes White 2002 21 Male Yes Yes 3 0.170685
2 No Black 1999 17 Male Yes Yes 3 0.829315
3 Yes White 2000 24 Male Yes Yes 3 0.170685
4 No Black 2000 46 Male Yes Yes 1 0.829315
5 Yes Black 1999 27 Female Yes Yes 1 0.170685
6 Yes Black 1998 16 Female Yes Yes 0 0.170685
“是”更频繁,因此我们给予它的权重较小。
从上面可以看出数据框有几个分类预测变量(如颜色、性别......)。
xgbTree
无法处理它们,因此您需要在建模之前将它们转换为数字。将分类预测变量转换为数字的一种方法是虚拟编码。还有其他方法,但这不在本答案的范围内。
使用虚拟编码:
dummies <- dummyVars(released ~ ., data = basex)
x <- predict(dummies, newdata = basex)
head(x)
colour.Black colour.White year age sex.Female sex.Male employed.No employed.Yes citizen.No citizen.Yes checks
1 0 1 2002 21 0 1 0 1 0 1 3
2 1 0 1999 17 0 1 0 1 0 1 3
3 0 1 2000 24 0 1 0 1 0 1 3
4 1 0 2000 46 0 1 0 1 0 1 1
5 1 0 1999 27 1 0 0 1 0 1 1
6 1 0 1998 16 1 0 0 1 0 1 0
y <- basex$released
现在我们有了权重 x 和 y
由于我将适合下面的几个模型,因此我将首先创建重采样折叠并在每次调用中使用它们来训练,因此它们没有不同。
folds <- createFolds(basex$released, 10)
由于类别频率存在不平衡,我将使用
twoClassSummary
,这样我们就可以看到训练模型的敏感性和特异性
tc <- trainControl(method = "cv",
number = 10,
summaryFunction = twoClassSummary,
index = folds, #predefined folds
classProbs = TRUE) #needed for twoClassSummary
mtd <- "xgbTree"
model <- train(x = x,
y = y,
method = mtd,
trControl = tc,
weights = model_weights,
verbose = TRUE,
metric = "ROC")
#没有错误
model$results %>%
filter(ROC == max(ROC))
eta max_depth gamma colsample_bytree min_child_weight subsample nrounds ROC Sens Spec ROCSD SensSD SpecSD
1 0.3 1 0 0.8 1 1 50 0.7031076 0.6185944 0.693945 0.009074758 0.03516597 0.01536701
在这里我们看到,如果我们使用模型权重,则具有最高 AUC 的模型的敏感性为 0.6185944,特异性为 0.693945。
没有配重
model2 <- train(x = x,
y = y,
method = mtd,
trControl = tc,
verbose = TRUE,
metric = "ROC")
#没有错误
model2$results %>%
filter(ROC == max(ROC))
eta max_depth gamma colsample_bytree min_child_weight subsample nrounds ROC Sens Spec ROCSD SensSD SpecSD
1 0.3 1 0 0.8 1 0.75 50 0.701109 0.1000325 0.9713885 0.0101395 0.03343579 0.01236701
没有权重的模型的灵敏度为 0.1000325,特异性为 0.9713885。
因此,有意义的权重参数固定了模型始终预测“是”的趋势。