xgboost 包和随机森林回归

Posted

技术标签:

【中文标题】xgboost 包和随机森林回归【英文标题】:The xgboost package and the random forests regression 【发布时间】:2016-04-24 18:50:22 【问题描述】:

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”指定)。

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

【问题讨论】:

你的问题是什么? 正如我已经说过的,我想知道为什么会得到这样的结果。包裹里有错误吗?还是我只是对如何使用包的功能有错误? 【参考方案1】:

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 预测未经过袋外交叉验证。如果对预测得出任何结论,您必须进行交叉验证,尤其是对于完全生长的树木。

NB 你需要修复函数 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

【讨论】:

可视化的伟大之处! 1. 我有点懒得在这里放一个合适的代码,需要所有的验证和其他东西。这对于正在考虑的问题并不重要。事实上,即使是交叉验证过程也必须重复几次(嗯,远远超过几次)才能完全确定该方法有效,这经常被遗忘。2。关于其他内容——我对主帖进行了更改。 即使有修复,我也无法让 vec.plot 工作:UseMethod("predict") 中的错误:没有适用于“预测”的方法应用于“xgb.Booster”类的对象。编辑:当我在 vec.plot 中将 predict 更改为 xgboost::predict 时工作 我运行代码并没有发现错误。我猜你有一些命名空间错误,因为你的搜索路径不同,尝试运行 search() 。 predict() 方法不需要指定包。也许错误会通过重新启动 R 并按照建议的顺序加载包而消失。但是,嘿,如果它有效,那么很好:)

以上是关于xgboost 包和随机森林回归的主要内容,如果未能解决你的问题,请参考以下文章

数据挖掘算法(logistic回归,随机森林,GBDT和xgboost)

用 XGBoost 开发随机森林集成

xgboost原理,怎么防止过拟合。随机森林,GBDT,Xgoost的区别,bagging和boosting

决策树随机森林GBDTXGBoost

如何从 xgboost 或随机森林中区分重要特征的方向?

随机森林中的“方差解释”和 XGBoost 中的“merror”有啥区别