有谁知道如何gbm
处理R
缺失值?我似乎无法使用谷歌找到任何解释。
5 回答
为了解释 gbm 对缺失预测变量的作用,让我们首先可视化 gbm 对象的单个树。
假设您有一个 gbm 对象mygbm
。使用pretty.gbm.tree(mygbm, i.tree=1)
您可以可视化 mygbm 上的第一棵树,例如:
SplitVar SplitCodePred LeftNode RightNode MissingNode ErrorReduction Weight Prediction
0 46 1.629728e+01 1 5 9 26.462908 1585 -4.396393e-06
1 45 1.850000e+01 2 3 4 11.363868 939 -4.370936e-04
2 -1 2.602236e-04 -1 -1 -1 0.000000 271 2.602236e-04
3 -1 -7.199873e-04 -1 -1 -1 0.000000 668 -7.199873e-04
4 -1 -4.370936e-04 -1 -1 -1 0.000000 939 -4.370936e-04
5 20 0.000000e+00 6 7 8 8.638042 646 6.245552e-04
6 -1 3.533436e-04 -1 -1 -1 0.000000 483 3.533436e-04
7 -1 1.428207e-03 -1 -1 -1 0.000000 163 1.428207e-03
8 -1 6.245552e-04 -1 -1 -1 0.000000 646 6.245552e-04
9 -1 -4.396393e-06 -1 -1 -1 0.000000 1585 -4.396393e-06
有关详细信息,请参阅 gbm 文档。每行对应一个节点,第一列(未命名)是节点号。我们看到每个节点都有一个左右节点(如果节点是叶子,则设置为 -1)。我们还看到每个节点都关联了一个MissingNode
.
为了在树上运行观察,我们从节点 0 开始。如果观察在SplitVar
= 46 上有缺失值,那么它将沿着树向下发送到节点MissingNode
= 9。对于这种观察的树的预测将是SplitCodePred
= -4.396393e-06,这与在对节点零进行任何拆分之前树的预测相同(节点零Prediction
= -4.396393e-06)。
该过程与其他节点和拆分变量类似。
它似乎将缺失值发送到每棵树中的单独节点。如果您有一个名为“mygbm”的 gbm 对象,那么您将通过键入“pretty.gbm.tree(mygbm, i.tree = 1)”看到树中的每个拆分都有一个 LeftNode、一个 RightNode 和一个 MissingNode。这意味着(假设您有interaction.depth=1)每棵树将有3个终端节点(分裂的每一侧1个,预测器缺失的地方一个)。
gbms的官方指南在测试数据中引入了缺失值,所以我假设它们被编码为处理缺失值。
gbm 包特别处理 NA(缺失值),如下所示。该算法通过构建和连续组合分类或回归树来工作。所谓的基础学习树是通过将观察结果分成左右两部分来构建的(@user2332165 是正确的)。gbm 中还有一个单独的节点类型 Missing。如果行或观察没有该变量的值,则算法将应用代理拆分方法。
如果您想更好地理解代理拆分,我建议您阅读包 rpart vignette。
然后从源代码开始。只需gbm
在控制台输入即可显示源代码:
function (formula = formula(data), distribution = "bernoulli",
data = list(), weights, var.monotone = NULL, n.trees = 100,
interaction.depth = 1, n.minobsinnode = 10, shrinkage = 0.001,
bag.fraction = 0.5, train.fraction = 1, cv.folds = 0, keep.data = TRUE,
verbose = TRUE)
{
mf <- match.call(expand.dots = FALSE)
m <- match(c("formula", "data", "weights", "offset"), names(mf),
0)
mf <- mf[c(1, m)]
mf$drop.unused.levels <- TRUE
mf$na.action <- na.pass
mf[[1]] <- as.name("model.frame")
mf <- eval(mf, parent.frame())
Terms <- attr(mf, "terms")
y <- model.response(mf, "numeric")
w <- model.weights(mf)
offset <- model.offset(mf)
var.names <- attributes(Terms)$term.labels
x <- model.frame(terms(reformulate(var.names)), data, na.action = na.pass)
response.name <- as.character(formula[[2]])
if (is.character(distribution))
distribution <- list(name = distribution)
cv.error <- NULL
if (cv.folds > 1) {
if (distribution$name == "coxph")
i.train <- 1:floor(train.fraction * nrow(y))
else i.train <- 1:floor(train.fraction * length(y))
cv.group <- sample(rep(1:cv.folds, length = length(i.train)))
cv.error <- rep(0, n.trees)
for (i.cv in 1:cv.folds) {
if (verbose)
cat("CV:", i.cv, "\n")
i <- order(cv.group == i.cv)
gbm.obj <- gbm.fit(x[i.train, , drop = FALSE][i,
, drop = FALSE], y[i.train][i], offset = offset[i.train][i],
distribution = distribution, w = ifelse(w ==
NULL, NULL, w[i.train][i]), var.monotone = var.monotone,
n.trees = n.trees, interaction.depth = interaction.depth,
n.minobsinnode = n.minobsinnode, shrinkage = shrinkage,
bag.fraction = bag.fraction, train.fraction = mean(cv.group !=
i.cv), keep.data = FALSE, verbose = verbose,
var.names = var.names, response.name = response.name)
cv.error <- cv.error + gbm.obj$valid.error * sum(cv.group ==
i.cv)
}
cv.error <- cv.error/length(i.train)
}
gbm.obj <- gbm.fit(x, y, offset = offset, distribution = distribution,
w = w, var.monotone = var.monotone, n.trees = n.trees,
interaction.depth = interaction.depth, n.minobsinnode = n.minobsinnode,
shrinkage = shrinkage, bag.fraction = bag.fraction, train.fraction = train.fraction,
keep.data = keep.data, verbose = verbose, var.names = var.names,
response.name = response.name)
gbm.obj$Terms <- Terms
gbm.obj$cv.error <- cv.error
gbm.obj$cv.folds <- cv.folds
return(gbm.obj)
}
<environment: namespace:gbm>
快速阅读表明数据被放入模型框架中,NAna.pass
依次?na.pass
处理从长远来看这意味着什么。看起来您可能还需要查看代码gbm.fit
等。