結合論文《Revisiting Deep Learning Models for Tabular Data》的觀點,集成樹模型通常擅長于表格數據這種異構數據集,是實打實的表格數據王者。集成樹模型中的LightGBM是增強版的GBDT,支持了分類變量,在工程層面大大提高了訓練效率。關于樹模型的介紹,可見之前文章:一文講透樹模型
DNN深度神經網絡擅長于同構的高維數據,從高維稀疏的表示中學習到低維致密的分布式表示,所以在自然語言、圖像識別等領域基本上是稱霸武林(神經網絡的介紹及實踐可見系列文章:一文搞定深度學習建模全流程)。對于異構致密的表格數據,個人實踐來看,DNN模型的非線性能力沒樹模型來得高效。
所以一個很樸素的想法是,結合這樹模型+神經網絡模型的優勢。比如通過NN學習文本的嵌入特征后,輸入樹模型繼續學習(如word2vec+LGB做文本分類,可見文章:NLP建模全流程)。 或者是,樹模型學習表格數據后,輸出樣本的高維個葉子節點的特征表示,輸入DNN模型。
接下來,我們使用LightGBM+DNN模型強強聯手,驗證其在信貸違約的表格數據預測分類效果。
數據處理及樹模型訓練
lightgbm樹模型,自帶缺失、類別變量的處理,還有很強的非線性擬合能力,特征工程上面不用做很多處理,建模非常方便。
##完整代碼及數據請見 算法進階github:https://github.com/aialgorithm/Blog
# 劃分數據集:訓練集和測試集
train_x, test_x, train_y, test_y = train_test_split(train_bank[num_feas + cate_feas], train_bank.isDefault,test_size=0.3, random_state=0)
# 訓練模型
lgb=lightgbm.LGBMClassifier(n_estimators=5, num_leaves=5,class_weight= 'balanced',metric = 'AUC')
lgb.fit(train_x, train_y)
print('train ',model_metrics(lgb,train_x, train_y))
print('test ',model_metrics(lgb,test_x,test_y))
簡單處理建模后test的AUC可以達到0.8656
樹+神經網絡
接下來我們將提取樹模型的葉子節點的路徑作為特征,并簡單做下特征選擇處理
import numpy as np
y_pred = lgb.predict(train_bank[num_feas + cate_feas],pred_leaf=True)
# 提取葉子節點
train_matrix = np.zeros([len(y_pred), len(y_pred[0])*lgb.get_params()['num_leaves']],dtype=np.int64)
print(train_matrix.shape)
for i in range(len(y_pred)):
temp = np.arange(len(y_pred[0]))*lgb.get_params()['num_leaves'] + np.array(y_pred[i])
train_matrix[i][temp] += 1
# drop zero-features
df2 = pd.DataFrame(train_matrix)
droplist2 = []
for k in df2.columns:
if not df2[k].any():
droplist2.append(k)
print(len(droplist2))
df2= df2.drop(droplist2,axis=1).add_suffix('_lgb')
# 拼接原特征和樹節點特征
df_final2 = pd.concat([train_bank[num_feas],df2],axis=1)
df_final2.head()
將拼接好原特征及樹節點路徑特征輸入神經網絡模型,并使用網格搜索調優神經網絡模型。
# 劃分數據集:訓練集和測試集
train_x, test_x, train_y, test_y = train_test_split(df_final2, train_bank.isDefault,test_size=0.3, random_state=0)
# 神經網絡模型評估
def model_metrics2(nnmodel, x, y):
yprob = nnmodel.predict(x.replace([np.inf, -np.inf], np.nan).fillna(0))[:,0]
fpr,tpr,_ = roc_curve(y, yprob,pos_label=1)
return auc(fpr, tpr),max(tpr-fpr)
import keras
from keras import regularizers
from keras.layers import Dense,Dropout,BatchNormalization,GaussianNoise
from keras.models import Sequential, Model
from keras.callbacks import EarlyStopping
from sklearn.metrics import mean_squared_error
np.random.seed(1) # 固定隨機種子,使每次運行結果固定
bestval = 0
# 創建神經模型并暴力搜索較優網絡結構超參: 輸入層; n層k個神經元的relu隱藏層; 輸出層
for layer_nums in range(2): #隱藏層的層數
for k in list(range(1,100,5)): # 網格神經元數
for norm in [0.01,0.05,0.1,0.2,0.4,0.6,0.8]:#正則化懲罰系數
print("************隱藏層vs神經元數vs norm**************",layer_nums,k,norm)
model = Sequential()
model.add(BatchNormalization()) # 輸入層 批標準化 input_dim=train_x.shape
for _ in range(layer_nums):
model.add(Dense(k,
kernel_initializer='random_uniform', # 均勻初始化
activation='relu', # relu激活函數
kernel_regularizer=regularizers.l1_l2(l1=norm, l2=norm), # L1及L2 正則項
use_bias=True)) # 隱藏層1
model.add(Dropout(norm)) # dropout正則
model.add(Dense(1,use_bias=True,activation='sigmoid')) # 輸出層
# 編譯模型:優化目標為回歸預測損失mse,優化算法為adam
model.compile(optimizer='adam', loss=keras.losses.binary_crossentropy)
# 訓練模型
history = model.fit(train_x.replace([np.inf, -np.inf], np.nan).fillna(0),
train_y,
epochs=1000, # 訓練迭代次數
batch_size=1000, # 每epoch采樣的batch大小
validation_data=(test_x.replace([np.inf, -np.inf], np.nan).fillna(0),test_y), # 從訓練集再拆分驗證集,作為早停的衡量指標
callbacks=[EarlyStopping(monitor='val_loss', patience=10)], #早停法
verbose=False) # 不輸出過程
print("驗證集最優結果:",min(history.history['loss']),min(history.history['val_loss']))
print('------------train------------\n',model_metrics2(model, train_x,train_y))
print('------------test------------\n',model_metrics2(model, test_x,test_y))
test_auc = model_metrics2(model, test_x,test_y)[0]
if test_auc > bestval:
bestval = test_auc
bestparas = ['bestval, layer_nums, k, norm',bestval, layer_nums, k, norm]
# 模型評估:擬合效果
plt.plot(history.history['loss'],c='blue') # 藍色線訓練集損失
plt.plot(history.history['val_loss'],c='red') # 紅色線驗證集損失
plt.show()
model.summary() #模型概述信息
print(bestparas)
可見,在我們這個實驗中,使用樹模型+神經網絡模型在test的auc得到一些不錯的提升,樹模型的AUC 0.8656,而樹模型+神經網絡的AUC 0.8776,提升了1.2%
其他試驗結果
結合微軟的試驗,樹+神經網絡(DeepGBM),在不同的任務上也是可以帶來一些的效果提升的。有興趣可以閱讀下文末參考文獻。
LGB+DNN(或者單層的LR)是一個很不錯的想法,有提升模型的一些效果。但需要注意的是,這也會加重模型的落地及迭代的復雜度。總之,樹+神經網絡是一個好的故事,但是結局沒有太驚艷。
參考論文:https://www.microsoft.com/en-us/research/uploads/prod/2019/08/deepgbm_kdd2019__CR_.pdf
https://github.com/motefly/DeepGBM