第一次調整Boosting算法的參數可能是一個非常艱難的任務。
有很多參數可供選擇,調整不同的參數會有不同的結果產生。
最好的調參可能是取決於數據。
每當我得到一個新的數據集,我都會學到一些新的東西。
對分類和回歸樹(CART)有很好的理解有助於我們理解boosting
我最喜歡的Boosting包是xgboost,它將在下面的所有示例中使用。
在討論數據之前,我們先談談一些我認為最重要的參數。
這些參數大多用於控制模型適合數據的程度。
我們希望能夠捕捉數據的結構,但僅限於真實的結構。
換句話說,我們不希望模型適合噪音(過擬合)
eta: 學習(或收縮)參數。
它控制Boosting中將使用來自新樹的多少信息。
該參數必須大於0並且被限制為1.
如果它接近零,我們將僅使用來自每個新樹的一小部分信息。
如果我們將eta設置為1,我們將使用新樹中的所有信息。
eta的大值導致更快的收斂和更多的過度擬合問題。
小數值可能需要許多樹來聚合。colsample_bylevel:就像隨機森林一樣,
有時候只需要看一些變量就可以增長樹中的每個新節點。
如果我們查看所有變量,算法需要更少的樹來收斂。
但例如,查看2/3的變量可能會導致模型更具魯棒性以適應過度擬合。
有一個類似的參數叫做colsample_bytree,它重新采樣每個新樹中的變量,
而不是每個新節點。
max_depth : 控制樹木的最大深度。 更深的樹有更多的終端節點並且適合更多的數據。 如果我們深入發展,融合也需要更少的樹木。 但是,如果樹要深一些,我們將使用來自第一棵樹的大量信息,算法的最終樹對丟失函數的重要性將會降低。 Boosting從使用許多樹木的信息中受益。 因此,巨大的樹木是不可取的。 較小的樹木也會增長得更快,並且因為Boosting在偽剩余中生長新的樹木,我們不需要為單個樹木進行任何驚人的調整。
sub_sample : 這個參數決定我們是估計一個Boosting還是一個隨機Boosting。 如果我們使用1,我們會獲得常規的Boosting。 0和1之間的值是隨機的情況。 隨機Boosting只使用一小部分數據來增長每棵樹。 例如,如果我們使用0.5,每棵樹將采樣50%的數據增長。 隨機增強是非常有用的,如果我們有異常值,因為它限制了它們對最終模型的影響,因為它們被放在幾個子樣本上。 而且,對於較小的實例,可能會有顯着的改進,但它們更易於過度擬合。
gamma:控制在樹中增長新節點所需的損失函數的最小減少量。 此參數對損失函數的規模很敏感,它將與響應變量的規模相關聯。 使用不同於0的gamma的主要結果是停止生成無用的樹的算法,這些樹幾乎不會減少樣本內誤差,並且可能導致過度擬合。 這個參數以后再說。
min_child_weigth :控制終端節點中觀察值(實例)的最小數量。 此參數的最小值為1,這使得樹只有一個觀測值的終端節點。 如果我們使用更大的值,我們將限制可能的完美擬合。 這個參數也將留給第二部分。
example:
數據服從一下等式:
這里:
,
。變量數量K將被設置為10,實例數量將被設置為1000。
實驗將更改每個Boosting參數,使所有其他參數保持不變以嘗試隔離其效果。 標准模型將具有以下參數:
eta:0.1
colsample_bylevel:2/3
sub_sample:0.5
我會將這些參數中的每一個更改為代碼中的值。 我們將分析測試樣本中的收斂性和均方根誤差(RMSE)。 下面的代碼將准備一切運行模型。
library(xgboost) library(ggplot2) library(reshape2) library(Ecdat) set.seed(1) N = 1000 k = 10 x = matrix(rnorm(N*k),N,k) b = (-1)^(1:k) yaux=(x%*%b)^2 e = rnorm(N) y=yaux+e # = select train and test indexes = # train=sample(1:N,800) test=setdiff(1:N,train) # = parameters = # # = eta candidates = # eta=c(0.05,0.1,0.2,0.5,1) # = colsample_bylevel candidates = # cs=c(1/3,2/3,1) # = max_depth candidates = # md=c(2,4,6,10) # = sub_sample candidates = # ss=c(0.25,0.5,0.75,1) # = standard model is the second value of each vector above = # standard=c(2,2,3,2) # = train and test data = # xtrain = x[train,] ytrain = y[train] xtest = x[test,] ytest = y[test]
eta:我們將開始分析eta參數。 下面的代碼估計每個候選eta的Boosting模型。 首先我們得到了收斂圖,這表明eta的更大值收斂得更快。 然而,圖下方的列車RMSE表明,更快的收斂並不能轉化為良好的樣本外表現。 較小的eta值如0.05和0.1是產生較小誤差的值。 我的觀點是,在這種情況下,0.1給我們一個良好的樣本外性能和可接受的收斂速度。 請注意,eta = 0.5和1的結果與其他結果相比非常糟糕。
set.seed(1) conv_eta = matrix(NA,500,length(eta)) pred_eta = matrix(NA,length(test), length(eta)) colnames(conv_eta) = colnames(pred_eta) = eta for(i in 1:length(eta)){ params=list(eta = eta[i], colsample_bylevel=cs[standard[2]], subsample = ss[standard[4]], max_depth = md[standard[3]], min_child_weigth = 1) xgb=xgboost(xtrain, label = ytrain, nrounds = 500, params = params) conv_eta[,i] = xgb$evaluation_log$train_rmse pred_eta[,i] = predict(xgb, xtest) }
conv_eta = data.frame(iter=1:500, conv_eta) conv_eta = melt(conv_eta, id.vars = "iter") ggplot(data = conv_eta) + geom_line(aes(x = iter, y = value, color = variable))
(RMSE_eta = sqrt(colMeans((ytest-pred_eta)^2)))
## 0.05 0.1 0.2 0.5 1 ## 9.964462 10.052367 10.223738 13.691344 20.929690
colsample_bylevel:下一個參數控制每個新節點中測試的變量(特征)的比例。 回想一下,如果我們使用1,所有變量都經過測試。 小於1的值只測試相應的變量部分。 收斂性表明該模型對colsample_bylevel不太敏感。 具有較小值的曲線略高於具有較大值的曲線。 最准確的模型似乎是每棵樹中使用25%樣本的模型。 這個結果可能會隨着不同類型的數據而改變。 例如,我們生成的數據使用相同的分布來創建所有響應變量,並且測試向變量賦予相似的權重,這使得采樣不那么重要。
set.seed(1) conv_cs = matrix(NA,500,length(cs)) pred_cs = matrix(NA,length(test), length(cs)) colnames(conv_cs) = colnames(pred_cs) = cs for(i in 1:length(cs)){ params = list(eta = eta[standard[1]], colsample_bylevel = cs[i], subsample = ss[standard[4]], max_depth = md[standard[3]], min_child_weigth = 1) xgb=xgboost(xtrain, label = ytrain,nrounds = 500, params = params) conv_cs[,i] = xgb$evaluation_log$train_rmse pred_cs[,i] = predict(xgb, xtest) }
conv_cs = data.frame(iter=1:500, conv_cs) conv_cs = melt(conv_cs, id.vars = "iter") ggplot(data = conv_cs) + geom_line(aes(x = iter, y = value, color = variable))
(RMSE_cs = sqrt(colMeans((ytest-pred_cs)^2))) ## 0.333333333333333 0.666666666666667 1 ## 10.29836 10.05237 10.20938
max_depth:第三個參數是每棵樹中允許的最大深度。 當然,如果我們種植更大的樹木,模型會更快地收斂(見下圖)。 但是,最好的示例外性能是max_depth = 4。 請記住,更大的樹木更可能導致過度貼合。 根據我的經驗,不需要使用大於4到6的值,但可能有例外。
set.seed(1) conv_md=matrix(NA,500,length(md)) pred_md=matrix(NA,length(test),length(md)) colnames(conv_md)=colnames(pred_md)=md for(i in 1:length(md)){ params=list(eta=eta[standard[1]],colsample_bylevel=cs[standard[2]], subsample=ss[standard[4]],max_depth=md[i], min_child_weigth=1) xgb=xgboost(xtrain, label = ytrain,nrounds = 500,params=params) conv_md[,i] = xgb$evaluation_log$train_rmse pred_md[,i] = predict(xgb, xtest) }
conv_md=data.frame(iter=1:500,conv_md) conv_md=melt(conv_md,id.vars = "iter") ggplot(data=conv_md)+geom_line(aes(x=iter,y=value,color=variable))
(RMSE_md=sqrt(colMeans((ytest-pred_md)^2))) ## 2 4 6 10 ## 12.502733 9.374257 10.134965 10.100691
sub_sample:下一個參數決定我們是否估計Boosting或Stochastic Boosting。 較小的值會導致樣本中的誤差更大,但它可能會產生更強大的樣本外估計。 但是,如前所述,對於具有許多特征的樣本,與觀察次數和數據非常嘈雜時相比,您將獲得更大的改進。 這里不是這種情況。 盡管如此,與確定性案例相比有一些改進,我相信這主要是由響應變量中的異常值引起的(boxplot變量y可以看到)。
set.seed(1) conv_ss=matrix(NA,500,length(ss)) pred_ss=matrix(NA,length(test),length(ss)) colnames(conv_ss)=colnames(pred_ss)=ss for(i in 1:length(ss)){ params=list(eta=eta[standard[1]],colsample_bylevel=cs[standard[2]], subsample=ss[i],max_depth=md[standard[3]], min_child_weigth=1) xgb=xgboost(xtrain, label = ytrain,nrounds = 500,params=params) conv_ss[,i] = xgb$evaluation_log$train_rmse pred_ss[,i] = predict(xgb, xtest) }
conv_ss=data.frame(iter=1:500,conv_ss) conv_ss=melt(conv_ss,id.vars = "iter") ggplot(data=conv_ss)+geom_line(aes(x=iter,y=value,color=variable))
(RMSE_ss=sqrt(colMeans((ytest-pred_ss)^2))) ## 0.25 0.5 0.75 1 ## 9.731273 10.052367 11.119535 11.233855
這里的主要結論是,調整Boosting模型沒有獨特的規則。 最好的方法是測試幾種配置。
請繼續關注,如果你喜歡這篇文章,我們會盡快討論Boosting。