5

xgboost 包允许构建一个随机森林(事实上,它选择列的随机子集来选择一个变量用于整个树的拆分,而不是像在算法的经典版本中那样用于点头,但它可以忍受)。但似乎只使用了森林中的一棵树(也许是最后一棵树)进行回归。

为确保这一点,请仅考虑一个标准玩具示例。

library(xgboost)
library(randomForest)
data(agaricus.train, package = 'xgboost')
    dtrain = xgb.DMatrix(agaricus.train$data,
 label = agaricus.train$label)
 bst = xgb.train(data = dtrain, 
                 nround = 1, 
                 subsample = 0.8, 
                 colsample_bytree = 0.5, 
                 num_parallel_tree = 100, 
                 verbose = 2, 
                 max_depth = 12)

answer1 = predict(bst, dtrain); 
(answer1 - agaricus.train$label) %*% (answer1 -  agaricus.train$label)

forest = randomForest(x = as.matrix(agaricus.train$data), y = agaricus.train$label, ntree = 50)

answer2 = predict(forest, as.matrix(agaricus.train$data))
(answer2 - agaricus.train$label) %*% (answer2 -  agaricus.train$label)

是的,当然,xgboost 随机森林的默认版本不使用 Gini 评分函数,而仅使用 MSE;它可以很容易地改变。做这样的验证等等也是不正确的。它不会影响主要问题。与 randomForest 实现相比,无论尝试哪组参数,结果都非常糟糕。这也适用于其他数据集。

有人可以就这种奇怪的行为提供提示吗?当涉及到分类任务时,算法确实按预期工作。

#

嗯,所有的树都长出来了,都用来做预测。您可以使用“predict”函数的参数“ntreelimit”来检查。

主要问题仍然存在:xgbbost 包生成的随机森林算法的具体形式是否有效?

交叉验证、参数调整和其他废话与此无关——每个人都可以对代码添加必要的更正,看看会发生什么。

您可以像这样指定“目标”选项:

mse = function(predict, dtrain)
{
  real = getinfo(dtrain, 'label')
  return(list(grad = 2 * (predict - real),
              hess = rep(2, length(real))))
}

这使您在为拆分选择变量时可以使用 MSE。即使在那之后,与 randomForest 的结果相比,结果也差得惊人。

也许,这个问题是学术性质的,并且涉及如何选择随机特征子集进行拆分的方式。经典实现为每个拆分单独选择特征子集(大小由 randomForest 包的“mtry”指定),xgboost 实现为树选择一个子集(用“colsample_bytree”指定)。

因此,至少对于某些类型的数据集,这种细微的差异似乎非常重要。确实很有趣。

4

1 回答 1

6

xgboost(随机森林风格)确实使用不止一棵树来预测。但还有许多其他差异需要探索。

我自己是 xgboost 的新手,但很好奇。所以我写了下面的代码来可视化这些树。您可以自己运行代码来验证或探索其他差异。

您选择的数据集是一个分类问题,因为标签不是 0 就是 1。我喜欢切换到一个简单的回归问题来可视化 xgboost 的作用。

真实模型:$y = x_1 * x_2$ + 噪声

如果您训练一棵树或多棵树,通过下面的代码示例,您会观察到学习的模型结构确实包含更多树。你不能单独从预测准确度来争论训练了多少棵树。

也许预测不同,因为实现不同。我所知道的~5 个 RF 实现中没有一个是完全相同的,而且这个 xgboost(rf style) 是最接近遥远的“表亲”。

我观察到colsample_bytree不等于mtry,因为前者对整个树使用相同的变量/列子集。我的回归问题只是一个大的交互,如果树只使用x1x2则无法学习。因此在这种情况下colsample_bytree必须设置为 1 才能在所有树中使用这两个变量。常规 RF 可以用 mtry=1 来模拟这个问题,因为每个节点都使用X1X2

我看到您的 randomForest 预测没有经过袋外交叉验证。如果对预测得出任何结论,您必须进行交叉验证,特别是对于完全生长的树木。

注意您需要修复函数 vec.plot 因为不支持 xgboost 开箱即用,因为 xgboost 开箱即用不将 data.frame 作为有效输入。 代码中的指令应该清楚

library(xgboost)
library(rgl)
library(forestFloor)
Data = data.frame(replicate(2,rnorm(5000)))
Data$y = Data$X1*Data$X2 + rnorm(5000)*.5
gradientByTarget =fcol(Data,3)
plot3d(Data,col=gradientByTarget) #true data structure

fix(vec.plot) #change these two line in the function, as xgboost do not support data.frame
#16# yhat.vec = predict(model, as.matrix(Xtest.vec))
#21# yhat.obs = predict(model, as.matrix(Xtest.obs))

#1 single deep tree
xgb.model =  xgboost(data = as.matrix(Data[,1:2]),label=Data$y,
                     nrounds=1,params = list(max.depth=250))
vec.plot(xgb.model,as.matrix(Data[,1:2]),1:2,col=gradientByTarget,grid=200)
plot(Data$y,predict(xgb.model,as.matrix(Data[,1:2])),col=gradientByTarget)
#clearly just one tree

#100 trees (gbm boosting)
xgb.model =  xgboost(data = as.matrix(Data[,1:2]),label=Data$y,
                     nrounds=100,params = list(max.depth=16,eta=.5,subsample=.6))
vec.plot(xgb.model,as.matrix(Data[,1:2]),1:2,col=gradientByTarget) 
plot(Data$y,predict(xgb.model,as.matrix(Data[,1:2])),col=gradientByTarget) ##predictions are not OOB cross-validated!


#20 shallow trees (bagging)
xgb.model =  xgboost(data = as.matrix(Data[,1:2]),label=Data$y,
                     nrounds=1,params = list(max.depth=250,
                     num_parallel_tree=20,colsample_bytree = .5, subsample = .5))
vec.plot(xgb.model,as.matrix(Data[,1:2]),1:2,col=gradientByTarget) #bagged mix of trees
plot(Data$y,predict(xgb.model,as.matrix(Data[,1:2]))) #terrible fit!!
#problem, colsample_bytree is NOT mtry as columns are only sampled once
# (this could be raised as an issue on their github page, that this does not mimic RF)


#20 deep tree (bagging), no column limitation
xgb.model =  xgboost(data = as.matrix(Data[,1:2]),label=Data$y,
                     nrounds=1,params = list(max.depth=500,
                     num_parallel_tree=200,colsample_bytree = 1, subsample = .5))
vec.plot(xgb.model,as.matrix(Data[,1:2]),1:2,col=gradientByTarget) #boosted mix of trees
plot(Data$y,predict(xgb.model,as.matrix(Data[,1:2])))
#voila model can fit data
于 2016-01-20T16:54:14.770 回答