前言
過去幾個月,一直在學習機器學習模型,輸入只是學習的一部分,輸出可以幫助自己更熟練地掌握概念和知識。把一個復雜的事物簡單的講述出來,才能表示真正弄懂了這個知識。所以我將在博客中盡量簡單地把這些模型講述出來,以加深自己的掌握,也為他人提供一點點參考。感謝大神劉建平Pinard的博客,如有任何疑惑可參考該神博客,此作僅為狗尾續貂之作。
每個模型介紹都將用基本思想,輸入,輸出,損失函數,優化方法,偽代碼來進行介紹
正文
1.決策樹
基本思想
決策樹是一個經典的分類算法,用if,else構成,可以分類,回歸,也可以拿來做集成模型的弱學習器,這里介紹sklearn中的決策樹方法,cart樹。

這就是決策樹模型,每個節點2分類,這里會產生一個問題,算法怎么知道先用哪個節點來分類最合適呢?CART分類樹算法使用基尼系數來決定用哪個特征進行分類,基尼系數代表了模型的不純度,基尼系數越小,則不純度越低,選用這個特征越好。
輸入
樣本X,屬於的分類標簽y
輸出
我們希望生成一棵樹,這棵樹由很多個節點組成,我們希望得到對於分類最合適的節點。
損失函數
這里我們的損失函數是基尼系數,我們希望每次選節點時,選取可以讓基尼系數最小的節點。假設有k個類別,每個類別有Ck個,共D個樣本。那么基尼系數的表達式是:

對於某一個特征把樣本化為兩個群體時,基尼系數的表達式為:
![]()
對於離散型特征來說,把所有離散特征用來分類,並比較一下,選用最小的,然后接下來的節點繼續這樣做
對於連續特征,具體的思路如下,比如m個樣本的連續特征A有m個,從小到大排列為a1,a2,...,am,CART算法取相鄰兩樣本值的平均數,一共取得m-1個划分點,其中第i個划分點Ti表示為:Ti=ai+ai+1。對於這m-1個點,分別計算以該點作為二元分類點時的基尼系數。選擇基尼系數最小的點作為分類點。對於多分類也是一樣,反正都是度量基尼系數。
對於缺失值的處理,主要是改變一下基尼系數的算法,把缺失值和非缺失值的樣本提出來,計算(非缺失的部分的基尼系數)*(非缺失/總樣本數),以此作為基尼系數計算依據,然后分類。然后可以將缺失特征的樣本同時划分入所有的子節點,不過將該樣本的權重按各個子節點樣本的數量比例來分配。
優化方法
決策樹沒有什么梯度下降等優化方法,就是計算然后比較,所以這里就介紹一下它的剪枝方法。
由於決策樹容易過擬合,為了增加泛化性能,我們對決策樹某些太細分的節點進行剪枝,那么怎么判斷是否是太過細分了呢?CART采用的辦法是后剪枝法,即先生成決策樹,然后產生所有可能的剪枝后的CART樹,然后使用交叉驗證來檢驗各種剪枝的效果,選擇泛化能力最好的剪枝策略
也就是說,CART樹的剪枝算法可以概括為兩步,
第一步是從原始決策樹生成各種剪枝效果的決策樹
第二步是用交叉驗證來檢驗剪枝后的預測能力,選擇泛化預測能力最好的剪枝后的樹作為最終的CART樹
首先我們看看剪枝的損失函數度量,在剪枝的過程中,對於任意的一刻子樹T,其損失函數為:
![]()
其中,α為正則化參數,這和線性回歸的正則化一樣。C(Tt)為訓練數據的預測誤差,分類樹是用基尼系數度量,回歸樹是均方差度量。|Tt|是子樹T的葉子節點的數量。
對於任意節點,剪枝前和剪枝后的損失函數為:


當這兩個相等時,
代表可以剪枝
上面我們講到,可以計算出每個子樹是否剪枝的閾值α,如果我們把所有的節點是否剪枝的值α都計算出來,然后分別針對不同的αα所對應的剪枝后的最優子樹做交叉驗證。這樣就可以選擇一個最好的α,有了這個α,我們就可以用對應的最優子樹作為最終結果
具體的算法實現過程可以看這里
偽代碼
輸入:訓練集X,基尼系數閾值,樣本個數閾值
輸出:一顆決策樹T
1) 對於當前節點的數據集為X,如果樣本個數小於閾值或者沒有特征,則返回決策子樹,當前節點停止遞歸。
2) 計算樣本集X的基尼系數,如果基尼系數小於閾值,則返回決策樹子樹,當前節點停止遞歸。
3) 計算當前節點現有的各個特征的各個特征值對數據集X的基尼系數。對於缺失值的處理按之前所說。
4) 在計算出來的各個特征的各個特征值對數據集X的基尼系數中,選擇基尼系數最小的特征A和對應的特征值a。根據這個最優特征和最優特征值,把數據集划分成兩部分X1和X2,同時建立當前節點的左右節點,左節點的數據集X為X1,右節點的數據集X為X2.
5) 對左右的子節點遞歸的調用1-4步,生成決策樹。
如何解決回歸問題
回歸問題,用和方差度量損失,選擇分出的兩個集合的和方差最小的來進行節點分組:

前身(ID3和C4.5)
ID3通過信息論中的信息增益來尋找最優的節點,信息增益最大,就選哪個特征。無法處理缺失值,無法處理連續特征,且如果一個特征分類多,天然占優勢。還有過擬合的問題,另外ID3的分裂不是2分裂的方式。
C4.5為了解決上述問題,不能處理連續特征:把連續特征離散化,選出每個連續特征的中間節點。對於特征分類多天然占優的情況:改進一下用信息增益比來度量(連續特征還是信息增益)。過擬合與CART樹采用相同的剪枝處理。對缺失值處理:用CART樹相同的方法。C4.5也有缺點,計算用的熵模型,費時間。只能用於分類,分裂方式還是多叉樹。
2.隨機森林RF
基本思想
隨機森林是集成模型中的bagging模型,其基本思想是訓練多棵樹對同一數據進行預測,然后把這些樹預測結果做一個投票,投票加總進行分類。抄一張現成的圖:

隨機采樣:這里每棵樹的訓練在樣本中有放回隨機采樣,一般采m個。
訓練過程:隨機森林的每棵樹訓練過程與cart有一點不同,他不會選最優節點來划分,而是先隨機選一個特征子集,再在子集中選最優,增強泛化能力。
如何處理缺失值呢?和CART樹一樣,把缺失的特征的基尼系數*權重(意思就是你缺失了,你就乘以0.x,相比不缺失的特征,你就往后稍一稍),實在要用你分類了,缺失特征值的樣本同時划入你分的兩類中,同時這些樣本要分別乘以權重(這里權重就是分開的比例)
其實這里就已經把隨機森林介紹完了,輸入輸出,優化方法都是決策樹那一套了。
偽代碼
1.for i in n(n顆子樹)
1.1 for i in m:隨機采樣數據集
1.2 隨機選擇特征子集,形成新的數據集
1.3 用數據集訓練一顆決策樹
2.統計n顆決策樹的分類結果
3.梯度提升樹GBDT
基本思想
GBDT是屬於集成學習中的Boosting方法,bagging是多個訓練器單獨訓練然后投票,而boosting方法是前面的學習結果要影響后面的一種方法(比如:這個弱學習器預測出來的一個樣本的結果不如意,下一個弱學習器訓練時,這個樣本的權重就會增加,這樣算損失函數的時候就會偏向這個樣本多一些)

以下介紹基於GBDT回歸樹:GBDT基於boosting思想,用殘差來擬合下一棵樹,最終形成強學習器。什么叫擬合殘差,舉個例子是這樣:如果你要吃一塊餅,你先吃完一半(0.5),再吃剩下一半的一半(0.25),如此往復,最終擬合整個1。GBDT就是第一顆樹盡量擬合,第二棵樹擬合這個殘差,第三棵樹再擬合剩下的殘差,f(最終) = f(初) + f(殘1) + f(殘2) +...第一輪的損失就是第二輪的殘差,第二輪的損失就是第三輪殘差。但是這個損失如何度量呢?
損失函數
前面說過,我們要知道每一輪的殘差,就得知道損失是什么。如何度量損失,Freidman提出用“損失函數的負梯度”來擬合本輪損失近似值。這是借鑒了泰勒展開的思想。這也是為什么叫梯度提升樹的原因。
下面具體來看一下,怎么度量殘差:
第t輪,第i個樣本的殘差為:

這個是什么意思呢,其實就是損失函數(標量)對變量(標量)求導,很簡單,如果損失函數度量是(y-x)2,那么就求它對x的導數。有了rti,我們就可以用
(xi,rti)(i=1,2,..m)來作為數據集,擬合下一輪的樹了!
知道殘差和損失函數的關系了,那么損失函數怎么定義呢?對於回歸,一般可用
均方差

絕對損失

huber損失:是均方差和絕對損失的折合,超過了一定距離的異常點就用絕對損失。

分位數損失(暫時沒看)
對於分類,一般可用指數損失函數,和對數損失函數
優化方法
我們擬合出一顆cart回歸樹之后還有一個步驟是確定回歸的輸出值,
以前的cart回歸樹是用葉子結點的均值,來作為回歸的輸出值(舉個例子:特征a大於1的樣本有3個,y值分別是5,4,3。於是就輸出5,4,3的均值4作為回歸結果)
但是在GBDT里不再是這樣,GBDT的回歸值c要取得讓總體損失函數最小:
![]()
(舉個例子,特征a大於1的樣本有2個,y值是5,4,上一輪中擬合出來的數值是3,這一輪擬合出的值就是c使得(5-3-c)2+(4-3-c)2最小)
(Rtj,j=1,2,...,J代表其對應的葉子節點區域)
於是本輪的決策樹的擬合函數如下:
![]()
(I就代表,屬於這個區域就是1,不屬於就是0)
於是最終的強學習器就是:
![]()
偽代碼
GBDT回歸算法:
輸入是訓練集樣本X,最大迭代次數T, 損失函數L
輸出強學習器,多棵樹(注意:這里每棵樹的輸入由上一棵樹決定了,不再是隨機森林那樣從樣本里抽)
1.初始化弱學習器,

2.for t in T(樹的數量,開始訓練第二顆,第三顆樹)
a.for i in m 計算樣本的負梯度:

b.利用負梯度,組成新的數據集(xi,rti)(i=1,2,..m),擬合一顆新的cart樹,得到第t顆回歸樹,其對應的葉子節點區域為Rtj,j=1,2,...,J。其中J為回歸樹t的葉子節點的個數。
c.for j in J,對新樹的葉子區域進行最佳c值擬合

d.更新強學習器

3.循環完T輪,得到了強學習器

分類樹
基本思想是和邏輯回歸相似,用概率來表示分類,用極大似然概率來測量損失
對二分類來說,損失函數是:
(這里用的負的對數似然函數做損失函數,負號和sigmoid的函數形式抵消了)
根據損失函數形式,則有最佳c值為

此式子難以優化,近似一下為:
![]()
有了每一棵樹的ctj於是強學習器得解,最后結果通過判斷加總結果接近1或者-1來二分類。
對於多分類的公式,我不是很熟悉,但是基本思想是訓練多個強學習器,用one vs more的思想進行分類,即通過一個強學習器先分成1類和剩下類,再通過一個強學習器把剩下類又分為1類和剩下類。
4.XGBOOST
基本思想
對GBDT的改進:
1.用二階泰勒展開來做損失,更精密一些
2.樹最后的回歸值選擇(ctj)選擇跟GBDT不同,分類節點選擇跟cart樹也不同,對單顆樹的分裂過程做了並行優化
3.缺失值的處理:對於缺失值的特征,通過比較所有缺失值在當前節點是進入左子樹還是右子樹來決定缺失值的處理方式。
損失函數
XGB的損失函數如下,加入了正則化:

(wtj是第j個葉子節點的最優值。這里的wtj和我們GBDT里使用的ctj是一個意思,J是葉子結點個數)
對前面的項進行二階泰勒展開(不展開正則化項),最后殘差為:
![]()
注意,這里殘差不再是(xi,rti) i=1,2,3...m這樣的數據集,而就是這樣一個函數,但它其實是表達了類似的意思,就是把這一輪所有殘差求和嘛。
上面的符號解釋:


回顧GBDT,我們先分裂樹,再通過逼近損失函數,來求ctj。但是XGB說:我要一次把兩個都求了。見下面優化方法
優化方法
關於如何一次求解出決策樹最優的所有J個葉子節點區域和每個葉子節點區域的最優解wtj,我們可以把它拆分成2個問題:
1) 如果我們已經求出了第t個決策樹的J個最優的葉子節點區域,如何求出每個葉子節點區域的最優解wtj?
2) 對當前決策樹做子樹分裂決策時,應該如何選擇哪個特征和特征值進行分裂,使最終我們的損失函數Lt最小?
對於第一個問題,我們直接用損失函數對wtj求偏導等於0就好了。

把式子帶入原損失函數式,wtj取最優解時,損失函數為

對於第二個問題,XGBoost這里不使用GBDT中的均方誤差,而是使用貪心法,即每次分裂都期望向着最小化損失函數的地方前進。於是這里就涉及到分裂的時候,損失函數如何變化的:
![]()
(這就是變化過程,這個式子代表第一層的損失函數減去第二層的損失函數,還是舉個例子:假設損失函數是一百萬元,轉運到銀行,途中要換乘幾輛車,我們的任務是盡快把錢都掉在運輸途中,給銀行送去的錢越少越好,我們當然就希望每次轉運的時候損失最多的錢。同理,我們就希望最大化上式子)

左右子樹的一階二階導數和為GL,HL,GR,HL,生動的解釋如下:

我們對每個分割點都試一試,看看哪個的最大,我們就用它分裂。由此我們一並解決了用哪個特征分類的問題,也解決了wtj等於什么的問題
偽代碼
5.LightGBM
基本思想
對XGB的改進,
1.把特征值弄成直方圖,減小節點數量,通過直方圖來做節點判斷,這樣計算量小了許多。
2.樹的分裂過程,不是所有節點同時二分(按層生長),而是一次只選擇一個節點二分(leaf-wise)。
3.可直接使用category特征,對分類特征不用再進行one-hot編碼了(one-hot對於類別很多的特征來說沒有價值)

