轉自:https://blog.csdn.net/anshuai_aw1/article/details/83275299
本篇文章主要參考柯國霖大神在知乎上的回答,以及自己閱讀LGBM的部分源碼整理而來。
1、one-hot編碼弊端
one-hot編碼是處理類別特征的一個通用方法,然而在樹模型中,這可能並不一定是一個好的方法,尤其當類別特征中類別個數很多的情況下。主要的問題是:
①可能無法在這個類別特征上進行切分(即浪費了這個特征)。使用one-hot編碼的話,意味着在每一個決策節點上只能使用one vs rest(例如是不是狗,是不是貓等)的切分方式。當類別值很多時,每個類別上的數據可能會比較少,這時候切分會產生不平衡,這意味着切分增益也會很小(比較直觀的理解是,不平衡的切分和不切分沒有區別)。
②會影響決策樹的學習。因為就算可以在這個類別特征進行切分,也會把數據切分到很多零碎的小空間上,如圖1左邊所示。而決策樹學習時利用的是統計信息,在這些數據量小的空間上,統計信息不准確,學習會變差。但如果使用如圖1右邊的分裂方式,數據會被切分到兩個比較大的空間,進一步的學習也會更好。
圖1右邊葉子節點的含義是X=A或者X=C放到左孩子,其余放到右孩子。
圖1
2、LGBM處理分類特征
2.1 大致流程
為了解決one-hot編碼處理類別特征的不足。LGBM采用了Many vs many的切分方式,實現了類別特征的最優切分。用Lightgbm可以直接輸入類別特征,並產生如圖1右邊的效果。在1個k維的類別特征中尋找最優切分,朴素的枚舉算法的復雜度是,而LGBM采用了如參考文獻【1】的方法實現了的算法。
算法流程如圖2所示:在枚舉分割點之前,先把直方圖按每個類別的均值進行排序;然后按照均值的結果依次枚舉最優分割點。從圖2可以看到,Sum(y)/Count(y)為類別的均值。當然,這個方法很容易過擬合,所以在LGBM中加入了很多對這個方法的約束和正則化。圖3是一個簡單的對比實驗,可以看到該最優方法在AUC上提升了1.5個點,並且時間只多了20%。
圖2
圖3
2.2 詳細流程
下面具體來講下在代碼中如何求解類別特征的最優切分的流程:
(feature_histogram.hpp文件中FindBestThresholdCategorical函數)
A. 離散特征建立直方圖的過程:
統計該特征下每一種離散值出現的次數,並從高到低排序,並過濾掉出現次數較少的特征值, 然后為每一個特征值,建立一個bin容器, 對於在bin容器內出現次數較少的特征值直接過濾掉,不建立bin容器。
B. 計算分裂閾值的過程:
B.1
先看該特征下划分出的bin容器的個數,如果bin容器的數量小於4,直接使用one vs other方式, 逐個掃描每一個bin容器,找出最佳分裂點;
B.2
對於bin容器較多的情況, 先進行過濾,只讓子集合較大的bin容器參加划分閾值計算, 對每一個符合條件的bin容器進行公式計算(公式如下: 該bin容器下所有樣本的一階梯度之和 / 該bin容器下所有樣本的二階梯度之和 + 正則項(參數cat_smooth),這里為什么不是label的均值呢?其實上例中只是為了便於理解,只針對了學習一棵樹且是回歸問題的情況, 這時候一階導數是Y, 二階導數是1),得到一個值,根據該值對bin容器從小到大進行排序,然后分從左到右、從右到左進行搜索,得到最優分裂閾值。但是有一點,沒有搜索所有的bin容器,而是設定了一個搜索bin容器數量的上限值,程序中設定是32,即參數max_num_cat。
LightGBM中對離散特征實行的是many vs many 策略,這32個bin中最優划分的閾值的左邊或者右邊所有的bin容器就是一個many集合,而其他的bin容器就是另一個many集合。
B.3
對於連續特征,划分閾值只有一個,對於離散值可能會有多個划分閾值,每一個划分閾值對應着一個bin容器編號,當使用離散特征進行分裂時,只要數據樣本對應的bin容器編號在這些閾值對應的bin集合之中,這條數據就加入分裂后的左子樹,否則加入分裂后的右子樹。
參考文獻:
【1】On grouping For maximum homogeneity
【2】https://www.zhihu.com/question/266195966
---------------------
作者:anshuai_aw1
來源:CSDN
原文:https://blog.csdn.net/anshuai_aw1/article/details/83275299
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!