一、模型解釋性的意義
機(jī)器學(xué)習(xí)業(yè)務(wù)應(yīng)用以輸出決策判斷為目標(biāo)??山忉屝允侵溉祟惸軌蚶斫鉀Q策原因的程度。機(jī)器學(xué)習(xí)模型的可解釋性越高,人們就越容易理解為什么做出某些決定或預(yù)測(cè)。模型可解釋性指對(duì)模型內(nèi)部機(jī)制的理解以及對(duì)模型結(jié)果的理解。其重要性體現(xiàn)在:建模階段,輔助開發(fā)人員理解模型,進(jìn)行模型的對(duì)比選擇,必要時(shí)優(yōu)化調(diào)整模型;在投入運(yùn)行階段,向業(yè)務(wù)方解釋模型的內(nèi)部機(jī)制,對(duì)模型結(jié)果進(jìn)行解釋。比如基金推薦模型,需要解釋:為何為這個(gè)用戶推薦某支基金。
在機(jī)器學(xué)習(xí)應(yīng)用中,有些領(lǐng)域(如金融風(fēng)控)的模型決策很看重業(yè)務(wù)的解釋性,通過(guò)業(yè)務(wù)先驗(yàn)的知識(shí)加以調(diào)整并監(jiān)控模型、以創(chuàng)造更值得信任的、安全可靠的模型。

追求業(yè)務(wù)解釋性,可以減少一些歧視、違規(guī)、不合理的特征決策,對(duì)模型帶來(lái)類似正則化效果,可以減少統(tǒng)計(jì)噪音的影響(減少過(guò)擬合),有更好的泛化效果。
但是,追求業(yè)務(wù)解釋性是個(gè)繁瑣的事情,首先你得有足夠的業(yè)務(wù)應(yīng)用知識(shí)的理解,其次還要手動(dòng)不停地調(diào)整一版又一版的模型。業(yè)界上對(duì)合理的業(yè)務(wù)解釋性可以提升模型的效果這是肯定的,特別是在小數(shù)據(jù)、數(shù)據(jù)不穩(wěn)定的情況,
一個(gè)金融領(lǐng)域簡(jiǎn)單的例子,如現(xiàn)有的1000條樣本顯示,有條數(shù)據(jù)規(guī)律:申請(qǐng)貸款的次數(shù)低于10,用戶的貸款逾期概率就越大。但是結(jié)合業(yè)務(wù)來(lái)看,一個(gè)人頻繁申請(qǐng)貸款,其負(fù)債、還款能力肯定是有問(wèn)題的,這時(shí)僅憑這條現(xiàn)有數(shù)據(jù)規(guī)律去決策風(fēng)險(xiǎn)有點(diǎn)大,很大概率這條決策在更多樣本的情況下就是失效的。
我們通過(guò)解釋性的工具剖析模型決策,當(dāng)模型決策不符合合理的業(yè)務(wù)邏輯或法規(guī)什么的 ,這時(shí),就很有必要做一些特征選擇,調(diào)整模型,以符合業(yè)務(wù)解釋性:
如經(jīng)典的邏輯回歸-lr ,需要不斷憑借業(yè)務(wù)含義調(diào)整特征分箱決策的單調(diào)性:
一文梳理金融風(fēng)控建模全流程(Python)
二、引入業(yè)務(wù)先驗(yàn)約束的樹模型(GBDT)
但上面兩種方法都比較依賴于手動(dòng)微調(diào)模型,以符合業(yè)務(wù)解釋性。為什么不直接在訓(xùn)練過(guò)程中,直接依據(jù)業(yè)務(wù)先驗(yàn)知識(shí)輔助模型訓(xùn)練?
在此,本文另提出一個(gè)思路,通過(guò)在樹模型學(xué)習(xí)訓(xùn)練過(guò)程(樹節(jié)點(diǎn)的分裂過(guò)程),簡(jiǎn)單引入個(gè)業(yè)務(wù)先驗(yàn)約束,以符合決策過(guò)程符合業(yè)務(wù)解釋性。

大致步驟是,
在 GBDT訓(xùn)練代碼中,配置特征業(yè)務(wù)邏輯性的約束
如 當(dāng)前二分類數(shù)據(jù)集有age,weight兩個(gè)特征。假設(shè)我們從業(yè)務(wù)理解上,認(rèn)為年齡age應(yīng)該和標(biāo)簽是呈現(xiàn)負(fù)相關(guān)的,年齡數(shù)值越大,標(biāo)簽值應(yīng)該要越小。那我們就可以配置特征約束的字典feas_logit, 配置特征age業(yè)務(wù)邏輯性的約束, 新增{'age': -1}, 其中-1代表該特征與標(biāo)簽的業(yè)務(wù)規(guī)律約束為負(fù)相關(guān),+1代表正相關(guān)。暫不支持非單調(diào)關(guān)系的業(yè)務(wù)約束配置。
# 配置特征業(yè)務(wù)邏輯性的約束
feas_logit = {'age': -1}
特征節(jié)點(diǎn)分裂時(shí)加入業(yè)務(wù)邏輯判斷(約束)
GBDT是cart二叉決策樹集成實(shí)現(xiàn)的,對(duì)于每一棵cart樹,我們會(huì)遍歷所有特征,嘗試以每一特征值作為決策的分裂點(diǎn)。我們可以在這里加入約束限制,如年齡age特征,我們認(rèn)為它和標(biāo)簽值是負(fù)相關(guān)的,那么對(duì)于每次分類age<特征閾值的左邊分支的樣本群體的標(biāo)簽均值應(yīng)該大于右邊分支的(反之亦然)。如果樹生長(zhǎng)的特征分裂不符合業(yè)務(wù)邏輯的,則會(huì)略過(guò),繼續(xù)其他特征值的搜索。
# 完整代碼:[aialgorithm](https://github.com/aialgorithm/Blog)
for feature in self.features:
self.logger.info(('----劃分特征:', feature))
feature_values = now_data[feature].unique()
for fea_val in feature_values:
# 嘗試劃分
left_index = list(now_data[feature] < fea_val)
right_index = list(now_data[feature] >= fea_val)
left_labelvalue = now_data[left_index][self.target_name]
right_labelvalue = now_data[right_index][self.target_name]
# 該特征劃分 加入判斷業(yè)務(wù)邏輯合理性約束##
if feature in self.feas_logit: # 如果該劃分不符合業(yè)務(wù)合理性約束則繼續(xù)搜索其他劃分
if not self.feas_logit[feature]*right_labelvalue.mean() > self.feas_logit[feature]*left_labelvalue.mean():
continue
# 計(jì)算劃分后的損失
left_se = calculate_se(left_labelvalue)
right_se = calculate_se(right_labelvalue)
sum_se = left_se + right_se
self.logger.info(('------劃分值:%.3f,左節(jié)點(diǎn)損失:%.3f,右節(jié)點(diǎn)損失:%.3f,總損失:%.3f' %
(fea_val, left_se, right_se, sum_se)))
if se is None or sum_se < se:
split_feature = feature
split_value = fea_val
se = sum_se
left_index_of_now_data = left_index
right_index_of_now_data = right_index
代碼運(yùn)行
- 依賴環(huán)境:
- 操作系統(tǒng):Windows/Linux
- 編程語(yǔ)言:Python3
- Python庫(kù):pandas、PIL、pydotplus,
其中pydotplus庫(kù)會(huì)自動(dòng)調(diào)用Graphviz,所以需要去Graphviz官網(wǎng)下載graphviz的-2.38.msi
,先安裝,再將安裝目錄下的bin添加到系統(tǒng)環(huán)境變量,此時(shí)如果再報(bào)錯(cuò)可以重啟計(jì)算機(jī)。詳細(xì)過(guò)程不再描述,網(wǎng)上很多解答。
文件結(jié)構(gòu)(修改前GBDT手寫代碼如參考文末鏈接):
- | - GBDT 主模塊文件夾
- | --- gbdt.py 梯度提升算法主框架
- | --- decision_tree.py 單顆樹生成,包括節(jié)點(diǎn)劃分和葉子結(jié)點(diǎn)生成
- | --- loss_function.py 損失函數(shù)
- | --- tree_plot.py 樹的可視化
- | - example.py 回歸/二分類/多分類測(cè)試文件
-
二分類GBDT測(cè)試,運(yùn)行如下命令:
python example.py --model binary_cf -
還未增加約束的GBDT
可見在原來(lái)的數(shù)據(jù)規(guī)律里面,age和標(biāo)簽是呈現(xiàn)正相關(guān)的,也就是age越高,標(biāo)簽越高。
當(dāng)我們?cè)趀xample.py中新增配置業(yè)務(wù)先驗(yàn)約束(令age需要和標(biāo)簽呈負(fù)相關(guān))的GBDT。此時(shí),在本實(shí)驗(yàn)數(shù)據(jù)集age特征的各分裂點(diǎn)可能都是不符合業(yè)務(wù)邏輯,都沒有選用,如下運(yùn)行結(jié)果:
def run(args):
### 配置特征業(yè)務(wù)邏輯性得約束###
feas_logit = {'age': -1}
### 配置end###

個(gè)人實(shí)踐經(jīng)驗(yàn),當(dāng)加入的業(yè)務(wù)先驗(yàn)比較合理的情況,模型泛化(測(cè)試集)誤差可能會(huì)更低(訓(xùn)練集的誤差通常會(huì)增加),或者訓(xùn)練-測(cè)試兩者差異更小了。模型有更好的泛化能力。有興趣的童鞋可以在更大數(shù)據(jù)集里面試驗(yàn)下,以便更客觀地評(píng)估下加入業(yè)務(wù)約束的模型效果差異。
參考鏈接
GBDT算法原理以及實(shí)例理解(含代碼):https://blog.csdn.net/zpalyq110/article/details/79527653
