xgboost包和随机森林回归

时间:2016-01-19 10:30:01

标签: r random-forest xgboost

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实现相比,结果都令人惊讶地糟糕。这也适用于其他数据集。

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

嗯,所有的树都长大了,所有树都用来做预测。您可以使用参数' ntreelimit'来检查为了预测'功能。

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

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

您可以指定'目标'选项如下:

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

这允许您在为拆分选择变量时使用MSE。即使在那之后,与randomForest相比,结果也是令人惊讶的糟糕。

也许,问题在于学术性质,并且涉及如何选择进行分割的随机特征子集的方式。经典实现选择一个特征子集(大小用随机森林包的' mtry'指定)分别进行拆分,xgboost实现为树选择一个子集(用' colsample_bytree&#指定) 39)。

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

1 个答案:

答案 0 :(得分:4)

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

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

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

真实型号:$ y = x_1 * x_2 $ +噪音

如果训练单个树或多个树,使用下面的代码示例,您会发现学习的模型结构确实包含更多树。你不能单独从预测准确性中争论有多少树被训练。

可能预测不同,因为实现方式不同。我所知道的~5个RF实现中没有一个是完全相同的,而这个xgboost(rf风格)与最接近的“堂兄”一样。

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

我看到你的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