R語言自學日記(21)-機器學習(二):極限梯度提升(XGBoost)

Edward Tung
Sep 9, 2018 · 13 min read

Introduction of Gradient Boosting Model of Machine Learning

前言:機器學習是甚麼

上一篇把近期迴歸模型的進展拓展了一遍,但實際上並沒有談到機器學習的精華所在,因此這邊重新帶大家順過一遍。

近幾年AI相關的技術又重新受到關注,從16年Alpha Go事件以來,大家開始爆炸性地關注這個技術未來的發展性與應用面,而的確我們現在看到這些技術越來越多的可能性,比方說科大迅飛開發出來的語音辨識機器,NYC研究生開發出來的YOLO物件偵測系統(可以用在自駕車、圖像辨別等),NVIDIA近來研究出基於深度學習框架與光影辨識技術的GPU等等。

實際上,機器學習是AI產業裡面最主要的技術之一。顧名思義,機器學習是旨在教會機器如何 “學習’’ ,而要讓機器知道如何學習,某種程度上我們必須先理解人類是如何學習的,人類有一套自己的學習標準,用來模仿是我們目前想到最快的方式。舉例來說,你有沒有想過人是怎麼樣知道眼前的物體是一輛車或是一棵樹?其實道理很簡單,我們從小開始看到各式各樣的物體,每次都有人告訴我們,這是車、這是樹,久而久之我們就知道長相類似的物體會被歸類為車子或樹,而機器也是一樣的,也就是說,在讓機器開始學習之前,你必須餵給他學習資源,也就是數據,讓機器從已知的樣本中去得到一組泛用的規律,並且運用這個規律去預測或分類未知的資料。因此,這整個科目就成了龐大的交叉學科,因為要產生這個規律,你必須用機率論、數理統計、計算機理論、資料結構與演算法等等的學科去組合出來。

機器學習跨學科領域以及發展方向,Source:Udacity

再舉個例子,假設我們有一組量化數據,去解釋人長得好不好看,比方說老王是5分,小王是8分,我們在下這些判斷前實質上是經過好多的變數去組合出來的,比方說鼻子挺不挺、眼睛大不大等等,當然對人類來說這些變數非常多,很可能是複雜又模糊的,我們不會描述一個人說他的眼睛長度大概6.32公分,鼻子傾斜角度75度,所以他長得好看。我們會說這是一種 “感覺”,比方我覺得這個人五官很深邃,或是臉部很有古典美的氣質,透過這些來判斷一個人好不好看。但是對於機器來說可不是如此,機器可以很快速地處理大量且複雜的數據集,因此只要我餵給他足夠的樣本,下次他就可以根據一個人臉部大量的變數去說,這個人長得好不好看,有多好看。

聰明的你很快就發現,咦?這不就是迴歸模型嗎? 是的,迴歸模型是機器學習中一個重要的演算法,能夠協助機器去預測連續型數值,當然我們還有其他演算法去處理分類問題、聚類問題或降噪問題等等,但我們既然在談時間序列,那本篇就會以機器學習中的各種迴歸模型為主,來介紹我們是如何架構資料分析的Pipeline。

機器學習中的迴歸模型

迴歸問題經過兩百多年,絕對有更多元且更精準的模型發展出來,我簡單列出目前比較常見的迴歸模型:Linear Model 一般線性模型、Ridge Regression 嶺迴歸、Lasso迴歸、Elastic Net彈性網絡、SVM 支持向量機等,還有比較違反以往對迴歸模型印象的樹狀演算法,譬如Decision Tree的迴歸樹、SGD Regressor 隨機梯度下降、Ranfom Forest Regression隨機森林回歸、....等等,整個目不暇給。

對於資料分析師或是工程師來說,深入了解這些演算法就有一定的必要,目前的Open Sources 或 Packages非常方便,使得用機器學習來做分析的門檻不斷下降,然而,當我們希望找到一組最佳的模型來擬和資料的時候,往往要做到參數調整甚至模型調整,更厲害的科學家甚至開創出新的模型,這些就都需要堅強的數學實力與電腦科學實力。

我們今天仍然不會介紹所有的模型(實際上也講不完),但我們會來提到近幾年在Kaggle(世界知名資料科學平台,雖然在去年被Google收購了而引起一陣哀號)競賽上非常流行的XGBoost,是當時幾乎囊括了大部分競賽獲勝隊伍所使用的演算法,但在此之前我們需要先來點準備知識預熱一下:

梯度下降(Gradient Descent)

記得我們說過,要找到一個最佳的模型我們應該要盡可能的最小化損失函數(Loss Function),而在這個前提下我們有一個最暴力但也最精確的做法叫做梯度下降法(Gradient Descent):

假設我們有一個損失函數,我們並不知道在哪一個點它會出現最小值,但我們知道的是,只要一個函數在隨機一點 a 可微分且有定義,則該函數在 a 點與梯度相反的方向下降的最快。梯度是甚麼,我們可以把梯度函數考慮成一個三維空間的一座山,沿著山坡往山頂最陡的方向就是所謂的梯度,因此,只要我們沿著最陡的地方反方向一路往前走,我們就能夠用最快的速度達到最小值(也就是谷底),圖示來說就會像這樣:

Source:researchgate.net

接下來有一個問題產生了,我們如何用最快的步數去達到最小值呢(你總不希望程式執行個三天三夜)?這裡要注意的是,我們一開始並不知道這座山長甚麼樣,我們只能去判斷A點朝哪個方向走最陡,但往那個方向走如果一次走太小步,我們有機率會花費非常多的時間才能夠達到谷底,但如果一次走太大步,我們有可能會錯過谷底導致估計變得非常不准,這時候我們就引進一個參數的概念,叫做 Learning Rate(學習速率)。

在一個標準梯度下降的情況,我們可以將公式寫成:

其中的符號 η 就代表Learning Rate,範圍在0到1之間。另外,有時候我們不是只想對單一函數做梯度下降,而是對函數空間作優化,那麼我們的 a 點就變成了函數 f(x),要找到一個最佳的 F*(x)。

Source:https://blog.csdn.net/google19890102/article/details/51746402

梯度提升算法(Gradient Boosting Algorithms)

在了解XGBoost以前,我們要先看一個概念叫做梯度提升(Gradient Boosting),這東西其實是兩個部分所組成的,也就是我們剛剛提到的梯度下降法(Gradient Descent)以及提升算法(Boosting Algorithms):

提升算法是機器整體學習中一個重要的環節(另一個是Bagging),Boosting是甚麼呢?想像我們剛才說的函數空間裏頭包含很多函數,這些函數實際上是指我們的基底學習器(Base Learning Models)所產生的損失函數,比方說我建立了一個線性迴歸與一個多項式回歸,它們都有各自的損失函數,而我們要找到一個最佳的函數F(X),在這邊就是模型的組合,來最小化總體損失,因此Boosting的算法實際上就是訓練出多個模型再去做加權彙總,圖示如下:

Source:https://blog.csdn.net/google19890102/article/details/51746402

那,如果把這兩者結合到一起,就變成梯度提升算法(Gradient Boosting),也就是Boosting模型組合的方式是使用梯度下降的方法去算出來的,具體流程如下:

Source:researchgate.net

由上圖我們可以發現,因為每一個函數實際上跟係數a以及相關係數有關,我們也要同時對這些數值做梯度下降之後去做加總得到下一個我們要計算的函數對象。唯一要注意的是,我們在建置這類模型時,會希望基底學習器彼此之間的表現(Performance)不要差異太大,否則建構Boosting算法就會用處不大,程式只要極大偏重於表現好的學習模型即可。

極限梯度提升(Extreme Gradient Boosting, XGBoost)

終於進入正題啦!甚麼是XGBoost呢?如果你認為前面那種程度不夠暴力,那我們就來得更暴力一點,考慮一個二階信息的梯度提升模型,也就是對函數做泰勒展開到二階態,就會變成:

Source:https://blog.csdn.net/sinat_22594309/article/details/60957594

Omega我們可以先不用管他,只是一個懲罰項而已,另外,我們剛才一直沒有提到說使用的f(x)函數是甚麼,這裡揭開神秘面紗,叫做決策樹模型(Decision Tree Model),XGBoost在其上引入了Tree Pruning的概念,不過這邊我就不再多說了不然篇幅會變得落落長,對於該演算法想了解的,推薦兩篇延伸閱讀(上面沒有數學下面有):

總而言之,透過極限梯度提升,我們能夠大幅度提升模型表現,這是拜更精準的模型損失評估所賜,同時,我們也並不用擔心這些運算會導致訓練速度過慢,這個演算法的設計准許電腦CPU能夠多線並行(詳情要研究電腦硬體結構才會比較了解),另外,XGBoost也可以傳入稀疏矩陣(Sparse Matrix)的輸入,某種程度上也節省了前期資料處理的時間。

好了,說了半天我們還是直接上實作吧!

*題外話:相比於LightGBM與CatBoost這兩個新興的算法(2017年)而言,基本上XGBoost就要顯得慢了許多,但三者在特徵切分的方式上略有不同,因此我們也難以僅根據模型訓練速度去評估哪個模型較佳。

建構XGBoost模型

首先,我們引入forecastxgb套件(在Python之中就叫做xgboost),並且這邊我們對於趨勢以及季節性簡單做出一些調整,我們在這邊透過decompose方法來處理季節性,代碼如下:

跟上面提到的方法一樣,我們用XGBoost建構出迴歸模型以後,就可以去對之後的資料做出預測,這個預測是基於自迴歸模型,也因此我們的函數叫做xgbar(),就是XGB+AR模型的意思。

我們也可以用上一篇提到的Lagged Regression的方式來建立模型,線性迴歸的RMSE在1.7左右,而XGBoost落在1.475,等於減少了13.3%的誤差。

參數調整(Parameter Tuning)

一個模型基本上我們會再透過參數調整去想辦法得到更好的表現,對於梯度提升模型來說,有一些參數會顯得比較重要,通常這也是資料科學家的重頭戲之一,透過對於演算法以及資料本身的深刻理解,去調整參數以追求更好的精確度,因而達到所謂的“產品研發”等級。當然,現在說機器學習門檻下獎的其中一個原因在於,即便對於模型或資料本身不夠了解,我們還是可以用網格搜索的方式去暴力得到最佳解(也就是所有參數都跑一遍),然而,如果希望給予實際價值,也就是知道怎麼樣解釋模型參數並給出商業上的建議,實際上還是要求分析師對於模型有一定的理解程度。

在這邊先把XGBoost完整參數的說明連結附上:

直覺上我會去調整的參數包括各種懲罰項,這一來與資料分布的狀況有關,二來與模型用來測試的分數基準有關,評估函數方式以及學習速率等,而其他的參數就視情況調整或是透過網格搜索,也就是暴力調整(只要不會train太久當然就隨便你,但大部分時候都不太可能讓你稱心如意)

介紹一下自己調參的幾個目標:

  1. 學習速率與迭代次數:這個非常好理解,學習速率越小則越有可能找到最優點,但相對地訓練次數就必須提高,而相反學習速率越大可以更快地訓練模型,但有可能出現震盪而找不到最佳值。因此這兩個參數是最優先要調整的,通常我都是用逼近的方式(否則暴力搜索真的太久了)。
  2. 樹狀演算法參數:這邊的說明可以在上面決策樹的延伸閱讀找到,不過這必須要是在你的演算法是tree才能使用。我自己的原則是,把參數分成非限制跟限制參數來看,非限制參數在避免Overfit的前提下調大,限制參數則根據樣本情況去調整,比方說樣本數量很大,我會調高每個節點的最小樣本數以避免機器無法取樣到足夠有用的特徵等。
  3. 懲罰項以及損失函數:通常如果競賽或是公司專案有很明確的評斷標準,那就讓這個參數與該標準一致即可,如果沒有則放心地都嘗試看看。

基本上以上三個是我一定會去調整的,其他一些比較Minor的參數就見仁見智,通常這些調整完之後模型的績效就已經到了一個臨界值了,再能透過調整其他參數大幅改善績效的情況相對很少。

最後要謹記的是,Gradient Boosting基本上可以無限深度無限迭代地去降低誤差,因此我們必須經過Train-Test-Split的步驟來避免所謂的Overfitting,也就是說雖然訓練資料的表現很好,但在測試資料的表現就很差的情況。

總結

講完了XGBoost,我們接下來走進深度學習的範圍試試看,下一篇會講解所謂的神經網絡(Neural Networks)到底是怎麼一回事,以及如何建構一個人工神經網絡(Artificial Neural Networks)來協助時間序列資料的預測。如果你喜歡我的文章,還請下方按個Clap唷!

R 語言自學系列

About a self-taught diary on R Language programming and practical Time Series Analysis, made by a python user and BBA student. Hope you like it:)

Edward Tung

Written by

NTU Undergrad || Data Science Enthusiast || Business Consultant

R 語言自學系列

About a self-taught diary on R Language programming and practical Time Series Analysis, made by a python user and BBA student. Hope you like it:)

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade