xgboost: 速度快效果好的boosting模型
Python R
本文作者:何通,SupStat Inc(總部在紐約,中國(guó)分部為北京數(shù)博思達(dá)信息科技有限公司)數(shù)據(jù)科學(xué)家,加拿大Simon Fraser University計(jì)算機(jī)學(xué)院研究生,研究興趣為數(shù)據(jù)挖掘和生物信息學(xué)。
主頁:https://github.com/hetong007
引言
在數(shù)據(jù)分析的過程中,我們經(jīng)常需要對(duì)數(shù)據(jù)建模并做預(yù)測(cè)。在眾多的選擇中,randomForest,gbm和glmnet是三個(gè)尤其流行的R包,它們?cè)贙aggle的各大數(shù)據(jù)挖掘競(jìng)賽中的出現(xiàn)頻率獨(dú)占鰲頭,被坊間人稱為R數(shù)據(jù)挖掘包中的三駕馬車。根據(jù)我的個(gè)人經(jīng)驗(yàn),gbm包比同樣是使用樹模型的randomForest包占用的內(nèi)存更少,同時(shí)訓(xùn)練速度較快,尤其受到大家的喜愛。在python的機(jī)器學(xué)習(xí)庫sklearn里也有GradientBoostingClassifier的存在。
Boosting分類器屬于集成學(xué)習(xí)模型,它基本思想是把成百上千個(gè)分類準(zhǔn)確率較低的樹模型組合起來,成為一個(gè)準(zhǔn)確率很高的模型。這個(gè)模型會(huì)不斷地迭代,每次迭代就生成一顆新的樹。對(duì)于如何在每一步生成合理的樹,大家提出了很多的方法,我們這里簡(jiǎn)要介紹由Friedman提出的Gradient Boosting Machine。它在生成每一棵樹的時(shí)候采用梯度下降的思想,以之前生成的所有樹為基礎(chǔ),向著最小化給定目標(biāo)函數(shù)的方向多走一步。在合理的參數(shù)設(shè)置下,我們往往要生成一定數(shù)量的樹才能達(dá)到令人滿意的準(zhǔn)確率。在數(shù)據(jù)集較大較復(fù)雜的時(shí)候,我們可能需要幾千次迭代運(yùn)算,如果生成一個(gè)樹模型需要幾秒鐘,那么這么多迭代的運(yùn)算耗時(shí),應(yīng)該能讓你專心地想靜靜……
現(xiàn)在,我們希望能通過xgboost工具更好地解決這個(gè)問題。xgboost的全稱是eXtreme Gradient Boosting。正如其名,它是Gradient Boosting Machine的一個(gè)c++實(shí)現(xiàn),作者為正在華盛頓大學(xué)研究機(jī)器學(xué)習(xí)的大牛陳天奇。他在研究中深感自己受制于現(xiàn)有庫的計(jì)算速度和精度,因此在一年前開始著手搭建xgboost項(xiàng)目,并在去年夏天逐漸成型。xgboost最大的特點(diǎn)在于,它能夠自動(dòng)利用CPU的多線程進(jìn)行并行,同時(shí)在算法上加以改進(jìn)提高了精度。它的處女秀是Kaggle的希格斯子信號(hào)識(shí)別競(jìng)賽,因?yàn)槌霰姷男逝c較高的預(yù)測(cè)準(zhǔn)確度在比賽論壇中引起了參賽選手的廣泛關(guān)注,在1700多支隊(duì)伍的激烈競(jìng)爭(zhēng)中占有一席之地。隨著它在Kaggle社區(qū)知名度的提高,最近也有隊(duì)伍借助xgboost在比賽中奪得第一。
為了方便大家使用,陳天奇將xgboost封裝成了python庫。我有幸和他合作,制作了xgboost工具的R語言接口,并將其提交到了CRAN上。也有用戶將其封裝成了julia庫。python和R接口的功能一直在不斷更新,大家可以通過下文了解大致的功能,然后選擇自己最熟悉的語言進(jìn)行學(xué)習(xí)。
功能介紹
一、基礎(chǔ)功能
首先,我們從github上安裝這個(gè)包:
devtools::install_github('dmlc/xgboost',subdir='R-package')
動(dòng)手時(shí)間到!第一步,運(yùn)行下面的代碼載入樣例數(shù)據(jù):
require(xgboost)data(agaricus.train,package='xgboost')data(agaricus.test,package='xgboost')train <- agaricus.traintest <- agaricus.test
這份數(shù)據(jù)需要我們通過一些蘑菇的若干屬性判斷這個(gè)品種是否有毒。數(shù)據(jù)以1或0來標(biāo)記某個(gè)屬性存在與否,所以樣例數(shù)據(jù)為稀疏矩陣類型:
>class(train$data)[1]"dgCMatrix"attr(,"package")[1]"Matrix"
不用擔(dān)心,xgboost支持稀疏矩陣作為輸入。下面就是訓(xùn)練模型的命令
> bst <- xgboost(data = train$data, label = train$label, max.depth =2, eta =1,+? ? ? ? ? ? ? ? nround =2, objective ="binary:logistic")[0]train-error:0.046522[1]train-error:0.022263
我們迭代了兩次,可以看到函數(shù)輸出了每一次迭代模型的誤差信息。這里的數(shù)據(jù)是稀疏矩陣,當(dāng)然也支持普通的稠密矩陣。如果數(shù)據(jù)文件太大不希望讀進(jìn)R中,我們也可以通過設(shè)置參數(shù)data = 'path_to_file'使其直接從硬盤讀取數(shù)據(jù)并分析。目前支持直接從硬盤讀取libsvm格式的文件。
做預(yù)測(cè)只需要一句話:
pred <- predict(bst,test$data)
做交叉驗(yàn)證的函數(shù)參數(shù)與訓(xùn)練函數(shù)基本一致,只需要在原有參數(shù)的基礎(chǔ)上設(shè)置nfold:
> cv.res <- xgb.cv(data = train$data, label = train$label, max.depth =2, +? ? ? ? ? ? ? ? ? eta =1, nround =2, objective ="binary:logistic", +? ? ? ? ? ? ? ? ? nfold =5)[0]train-error:0.046522+0.001102test-error:0.046523+0.004410[1]train-error:0.022264+0.000864test-error:0.022266+0.003450> cv.res? train.error.mean train.error.std test.error.mean test.error.std1:0.0465220.0011020.0465230.0044102:0.0222640.0008640.0222660.003450
交叉驗(yàn)證的函數(shù)會(huì)返回一個(gè)data.table類型的結(jié)果,方便我們監(jiān)控訓(xùn)練集和測(cè)試集上的表現(xiàn),從而確定最優(yōu)的迭代步數(shù)。
二、高速準(zhǔn)確
上面的幾行代碼只是一個(gè)入門,使用的樣例數(shù)據(jù)沒法表現(xiàn)出xgboost高效準(zhǔn)確的能力。xgboost通過如下的優(yōu)化使得效率大幅提高:
xgboost借助OpenMP,能自動(dòng)利用單機(jī)CPU的多核進(jìn)行并行計(jì)算。需要注意的是,Mac上的Clang對(duì)OpenMP的支持較差,所以默認(rèn)情況下只能單核運(yùn)行。
xgboost自定義了一個(gè)數(shù)據(jù)矩陣類DMatrix,會(huì)在訓(xùn)練開始時(shí)進(jìn)行一遍預(yù)處理,從而提高之后每次迭代的效率。
在盡量保證所有參數(shù)都一致的情況下,我們使用希格斯子競(jìng)賽的數(shù)據(jù)做了對(duì)照實(shí)驗(yàn)。
Model and Parametergbmxgboost
1 thread2 threads4 threads8 threads
Time (in secs)761.48450.22102.4144.1834.04
以上實(shí)驗(yàn)使用的CPU是i7-4700MQ。python的sklearn速度與gbm相仿。如果想要自己對(duì)這個(gè)結(jié)果進(jìn)行測(cè)試,可以在比賽的官方網(wǎng)站下載數(shù)據(jù),并參考這份demo中的代碼。
除了明顯的速度提升外,xgboost在比賽中的效果也非常好。在這個(gè)競(jìng)賽初期,大家驚訝地發(fā)現(xiàn)R和python中的gbm竟然難以突破組織者預(yù)設(shè)的benchmark。而xgboost橫空出世,用不到一分鐘的訓(xùn)練時(shí)間便打入當(dāng)時(shí)的top 10,引起了大家的興趣與關(guān)注。準(zhǔn)確度提升的主要原因在于,xgboost的模型和傳統(tǒng)的GBDT相比加入了對(duì)于模型復(fù)雜度的控制以及后期的剪枝處理,使得學(xué)習(xí)出來的模型更加不容易過擬合。更多算法上的細(xì)節(jié)可以參考這份陳天奇給出的介紹性講義。
三、進(jìn)階特征
除了速度快精度高,xgboost還有一些很有用的進(jìn)階特性。下面的“demo”鏈接對(duì)應(yīng)著相應(yīng)功能的簡(jiǎn)單樣例代碼。
只要能夠求出目標(biāo)函數(shù)的梯度和Hessian矩陣,用戶就可以自定義訓(xùn)練模型時(shí)的目標(biāo)函數(shù)。demo
允許用戶在交叉驗(yàn)證時(shí)自定義誤差衡量方法,例如回歸中使用RMSE還是RMSLE,分類中使用AUC,分類錯(cuò)誤率或是F1-score。甚至是在希格斯子比賽中的“奇葩”衡量標(biāo)準(zhǔn)AMS。demo
交叉驗(yàn)證時(shí)可以返回模型在每一折作為預(yù)測(cè)集時(shí)的預(yù)測(cè)結(jié)果,方便構(gòu)建ensemble模型。demo
允許用戶先迭代1000次,查看此時(shí)模型的預(yù)測(cè)效果,然后繼續(xù)迭代1000次,最后模型等價(jià)于一次性迭代2000次。demo
可以知道每棵樹將樣本分類到哪片葉子上,facebook介紹過如何利用這個(gè)信息提高模型的表現(xiàn)。demo
可以計(jì)算變量重要性并畫出樹狀圖。demo
可以選擇使用線性模型替代樹模型,從而得到帶L1+L2懲罰的線性回歸或者logistic回歸。demo
這些豐富的功能來源于對(duì)日常使用場(chǎng)景的總結(jié),數(shù)據(jù)挖掘比賽需求以及許多用戶給出的精彩建議。
四、未來計(jì)劃
現(xiàn)在,機(jī)器學(xué)習(xí)工具在實(shí)用中會(huì)不可避免地遇到“單機(jī)性能不夠”的問題。目前,xgboost的多機(jī)分布式版本正在開發(fā)當(dāng)中。基礎(chǔ)設(shè)施搭建完成之日,便是新一輪R包開始設(shè)計(jì)與升級(jí)之時(shí)。
結(jié)語
我為xgboost制作R接口的目的就是希望引進(jìn)好的工具,讓大家使用R的時(shí)候心情更愉悅。總結(jié)下來,xgboost的特點(diǎn)有三個(gè):速度快,效果好,功能多,希望它能受到大家的喜愛,成為一駕新的馬車。
xgboost功能較多,參數(shù)設(shè)置比較繁雜,希望在上手之后有更全面了解的讀者可以參考項(xiàng)目wiki。歡迎大家多多交流,在項(xiàng)目issue區(qū)提出疑問與建議。我們也邀請(qǐng)有興趣的讀者提交代碼完善功能,讓xgboost成為更好用的工具。
另外,在使用github開發(fā)的過程中,我深切地感受到了協(xié)作寫代碼帶來的變化。一群人在一起的時(shí)候,可以寫出更有效率的代碼,在豐富的使用場(chǎng)景中發(fā)現(xiàn)新的需求,在極端情況發(fā)現(xiàn)隱藏很深的bug,甚至在主代碼手拖延癥較為忙碌的時(shí)候有人挺身而出拿下一片issue。這樣的氛圍,能讓一個(gè)語言社區(qū)的交流豐富起來,從而充滿生命力地活躍下去。