1. 程式人生 > 其它 >正則化貪心森林(RGF)的入門簡介,含案例研究

正則化貪心森林(RGF)的入門簡介,含案例研究

作為曾參與機器學習競賽的資料科學家,我一直在尋找“非主流”的演算法。使用這些演算法可能不會成為競爭的贏家。但是他們有獨特的預測方式。這些演算法可以在整合模型中使用,以獲得其他流行的梯度下降演算法(XGBoost,LightGBM等)所沒有的額外優勢。

本文討論一種稱為正則化貪心森林(Regularized Greedy Forests,RGF)的演算法。它的效能與執行在較大資料集的梯度下降演算法類似。它們產生較少的相關性預測,並且能很好地與其他梯度下降決策樹模型整合。

為了充分理解本文,應該瞭解梯度下降和決策樹的基礎知識。

RGF與梯度下降

在梯度下降演算法中,每個分類器/迴歸器都接受了資料的訓練,繼承了以前的分類器/迴歸器的成果。在每次訓練後,重新分配權重。為錯誤分類的資料增加權重,以強調最困難的情況。這樣,後續的學習器(learner)會在他們的訓練中關注他們。

但是,這種方法把基於學習器的決策樹視為一個黑盒子,沒有利用樹結構本身。從某種意義上說,梯度下降對模型執行部分校正步驟。

而RGF執行兩個步驟:

1. 找到當前森林某一步的結構變化,以獲得最小化損失函式的新森林(例如最小二乘法或logloss)

2. 調整整個森林的“葉子”的權重,使損失函式最小化

尋找最佳的結構變化:

1. 為了計算效率,在搜尋策略中僅執行兩種型別的操作:

  • ·分割現有的葉節點
  • ·啟動一個新的樹(即向森林新增新的樹根)

2. 通過反覆評估所有可能的結構變化的最大損失率,對所有現有葉節點的權重進行搜尋。

3. 想要搜尋整個森林非常困難(實際應用時通常如此)。因此,搜尋僅限於最近建立的“t”樹,預設選項為t = 1。

在這裡,我來舉個例子來說明一下。

圖型3顯示了在與圖型2相同的階段,我們可以考慮拆分標記為X的一個葉節點或者生成一個新的樹T4。

權重優化

每個節點的權重也被優化,以進一步最小化損失函式:

1. 損失函式和權重優化的區間可以由引數指定。每次增加100(k = 100)個新的葉節點,校正權重就能很好地工作,所以當RGF模型被訓練時,這被作為預設引數。

2. 如果“k”非常大,那麼類似於在重點做單一權重的更新; 如果“k”’非常小(例如k = 1),那麼它會大大減慢訓練速度。

正則化

在這裡為損失函式正則化對於這個演算法來說是非常重要的,因為它會很快過擬合。森林生長過程和權重校正過程可能有不同的L2正則化引數。

有三種正則化的方法:

1.一個是單葉(leaf-only)模型的L2正則化,其中正則化懲罰項G(F)為::

2.另外兩個被稱為最小懲罰正則化(min-penalty regularizers)。他們對每棵樹的正則化懲罰項的定義是:

更大的γ> 1懲罰更深的節點(對應更復雜的函式)也更嚴格。正則化的程度可以通過λ或γ超引數來調整。

3.森林生長過程和權重校正過程可能有不同的L2正則化引數,在這裡視情況而定。

樹尺寸

RGF不需要在梯度下降決策樹設定所需的樹尺寸(tree size)引數(例如,樹的數量,最大深度)。使用RGF時,每棵樹的尺寸是由最小正則化損失自動確定的。我們所宣告的是森林中葉子的最大數量和正則化引數(L1和L2)。

模型尺寸

由於RGF在模型/森林上執行完全糾正步驟,因此與需要較小學習率和大量估計量來產生較好結果的梯度下降演算法不同,它可以訓練相對簡單的模型。

在Python中的實現

原始RGF的二元分類和迴歸的實現是由論文的作者Rie Johnson和Tong Zhang使用C ++完成的。由fukatani開發的使用Python做相同實現的最流行的封裝甚至支援多分類。大部分實現基於MLWave的RGF包裝。

超引數

我們來談談影響模型準確性或者訓練速度的重要引數:

  • max_leaf:當森林中的葉節點數量達到此值時,訓練將終止。所以它應該足夠大,以便在訓練時能夠獲得一個好的模型,而較小的值則能讓訓練時間更短。
  • loss:損失函式
    • LS:平方損失((p-y)^2/2
    • Expo:指數損失 exp(-py)
    • Log:logistic損失日誌 (1+exp(-py))
  • algorithm
    • RGF:RGF和L2正則化的單葉模型
    • RGF Opt:RGF+最小懲罰正則化
    • RGF Sib:RGF+最小懲罰正則化+同層級零和約束(sum-to-zero sibling constraints)
  • reg_depth:必須小於1. 與algorithm =“RGF Opt”或“RGF Sib”一起使用。值越大懲罰較深節點越重
  • l2:用於控制L2正則化的程度。想要取得良好效能的關鍵。依靠資料決定合適的值。通常1,0.1或0.01都會取得好的結果,儘管存在指數損失(loss= Expo)和邏輯損失(loss= Log),但是一些資料需要較小的值,例如1e-10或1e-20。
  • sl2:覆蓋森林生長過程中的L2正則化引數λ。也就是說,如果指定它,權重修正過程使用λ,森林生長過程使用λg。如果省略,則不進行覆蓋,在整個訓練過程中都使用λ。在某些資料中使用λ/100效果不錯。
  • test_interval:RGF進行權重的徹底的校正更新,在指定的間隔和訓練結束時,對所有樹的葉節點的權值進行更新。
    • 因此,如果儲存250棵樹的模型,,那麼這250棵樹只能用於測試250棵樹的附加模型。如果我們在獲得“k”樹的時候停止訓練,分配給“k”樹的節點的權重將與500棵樹中的第一棵“k”樹完全不同。
    • 如果測試間隔為500,則每次新增500個葉節點,模擬結束訓練,對模型進行測試或將其儲存以供後續測試。
  • normalize:如果開啟,訓練目標被歸一化,以使平均值歸零

使用PYTHON包裝進行訓練和評估

讓我們嘗試RGF上的大賣場預測問題。

資料集下載:https://datahack.analyticsvidhya.com/contest/practice-problem-big-mart-sales-iii/

如果想要詳細瞭解預處理的步驟可以訪問下方連結。

預處理:https://www.analyticsvidhya.com/blog/2016/02/bigmart-sales-solution-top-20/

import pandas as pd
import numpy as np

#Read files:
train= pd.read_csv("Train_UWu5bXk.csv")
test= pd.read_csv("Test_u94Q5KV.csv")

train['source']='train'
test['source']='test'
data= pd.concat([train, test],ignore_index=True)

#Filter categorical variables
categorical_columns= [xfor xin data.dtypes.indexif data.dtypes[x]=='object']

#Exclude ID cols and source:
categorical_columns= [xfor xin categorical_columnsif xnot in ['Item_Identifier','Outlet_Identifier','source']]

#Get the first two characters of ID:
data['Item_Type_Combined']= data['Item_Identifier'].apply(lambda x: x[0:2])

#Rename them to more intuitive categories:
data['Item_Type_Combined']= data['Item_Type_Combined'].map({'FD':'Food',
 'NC':'Non-Consumable',
 'DR':'Drinks'})

#Years
data['Outlet_Years']= 2013 - data['Outlet_Establishment_Year']

#Change categories of low fat:
data['Item_Fat_Content']= data['Item_Fat_Content'].replace({'LF':'Low Fat',
 'reg':'Regular',
 'low fat':'Low Fat'})

#Mark non-consumables as separate category in low_fat:
data.loc[data['Item_Type_Combined']=="Non-Consumable",'Item_Fat_Content']= "Non-Edible"

#Fill missing values by a very large negative val
data.fillna(-9999,inplace= True)

#Import library:
from sklearn.preprocessingimport LabelEncoder
le= LabelEncoder()

#New variable for outlet
data['Outlet']= le.fit_transform(data['Outlet_Identifier'])
var_mod= ['Item_Fat_Content','Outlet_Location_Type','Outlet_Size','Item_Type_Combined','Outlet_Type','Outlet']
le= LabelEncoder()
for iin var_mod:
 data[i]= le.fit_transform(data[i].astype(str))

train_new= train.drop(['Item_Identifier','Outlet_Identifier','Item_Outlet_Sales'],axis=1)
test_new= test.drop(['Item_Identifier','Outlet_Identifier'],axis=1)
y_all= train['Item_Outlet_Sales']

一旦我們有了預處理的儲存資料,我們就可以使用下面的命令匯入RGF:

from rgf.sklearnimport RGFRegressor
from sklearn.model_selectionimport GridSearchCV
為此設定的兩個最重要的引數max_leaf和L2正則化。我們可以使用網格搜尋來找出具有最佳交叉驗證MSE的引數。
parameters= {'max_leaf':[1000,1200,1300,1400,1500,1600,1700,1800,1900,2000],
              'l2':[0.1,0.2,0.3],
              'min_samples_leaf':[5,10]}
clf= GridSearchCV(estimator=rgf,
                   param_grid=parameters,
                   scoring='neg_mean_squared_error',
                   n_jobs= -1,
                   cv= 3)

看起來我們試圖匹配有太多葉節點的過於複雜的模型。高的正則化項高,max_leaf進行程度較低。讓我們用更小的max_leaf做一個不同的網格搜尋:

parameters= {'max_leaf':[100,200,300,400,500,800,900,1000],
 'algorithm':("RGF_Sib","RGF"),
 'l2':[0.1,0.2,0.3],
 'min_samples_leaf':[5,10]}

看起來像這些引數是最合適的。它在公共排行榜上RMSE的得分是1146。

總結

RGF是另一種樹整合技術,它類似梯度下降演算法,可用於有效建模非線性關係。