Machine learning is changing the world!
在之前的章節(jié)中(見個人微信公眾號連載),我們學(xué)習(xí)了如何訓(xùn)練多種不同形式的高級機(jī)器學(xué)習(xí)模型。由于機(jī)器學(xué)習(xí)算法模型的內(nèi)部結(jié)構(gòu)的負(fù)責(zé)性,它們通常被認(rèn)為是“黑箱”模型。然而,正是由于它們的復(fù)雜性,它們通常可以更準(zhǔn)確地預(yù)測非線性、微弱或一些罕見的現(xiàn)象。不幸的是,以上過程通常以喪失可解釋性為代價。幸運的是,近年來在機(jī)器學(xué)習(xí)算法模型的可解釋性方面(可解釋性機(jī)器學(xué)習(xí),Interpretable Machine Learning)已經(jīng)取得了一定進(jìn)展,以幫助解釋機(jī)器學(xué)習(xí)模型。本章將重點介紹常見的可解釋性機(jī)器學(xué)習(xí)(IML)算法。
IML的想法來源
在機(jī)器學(xué)習(xí)任務(wù)中,僅僅確定一個能夠優(yōu)化預(yù)測性能的機(jī)器學(xué)習(xí)模型是遠(yuǎn)遠(yuǎn)不夠的。具有可解釋性及可信性是一個性能較好的模型的標(biāo)志,也是別人采用我們模型的前提條件。當(dāng)我們在應(yīng)用和嵌入越來越復(fù)雜的預(yù)測模型和機(jī)器學(xué)習(xí)算法時,不論是我們模型開發(fā)者還是模型應(yīng)用者,都需要一些方法來解釋和理解模型的結(jié)果,以保證模型可以應(yīng)用于相關(guān)決策。
現(xiàn)在,可解釋性的引入使我們能夠從最先進(jìn)的機(jī)器學(xué)習(xí)模型中提取關(guān)鍵見解和可操作信息。這些進(jìn)展使我們能夠回答以下問題:
- 哪些最重要的客戶屬性影響其行為?
- 這些屬性與行為之間的關(guān)系如何?
- 多個屬性是否相互作用,導(dǎo)致不同客戶之間的不同行為?
- 我們?yōu)槭裁搭A(yù)計某個客戶會做出特定的決策?
- 我們基于預(yù)測結(jié)果做出的決策是否公平可靠?
解釋模型的方法可以根據(jù)回答上述示例問題的范圍,大致分為提供全局或局部解釋兩種方式。全面了解在全局范圍內(nèi)訓(xùn)練的整個模型相當(dāng)重要,同時也要放大到數(shù)據(jù)或預(yù)測的局部區(qū)域,并得出解釋。能夠回答這些問題并提供兩個層次的解釋對于任何機(jī)器學(xué)習(xí)項目的成功和接受、采用、嵌入和正確利用至關(guān)重要。
全局解釋(Global interpretation)
全局解釋性是基于對其特征的整體觀點以及它們?nèi)绾斡绊懙讓幽P徒Y(jié)構(gòu)的整體觀點來理解該模型如何做出預(yù)測。它回答了哪些特征相對具有影響力,這些特征如何影響響應(yīng)變量,以及可能發(fā)生的潛在交互作用。全局模型解釋性有助于理解響應(yīng)變量與各個特征(或其子集)之間的關(guān)系。可以說,全面的全局模型解釋性在實踐中很難實現(xiàn)。任何超過少數(shù)特征的模型將難以完全理解,因為我們無法一次理解整個模型結(jié)構(gòu)。
雖然全局模型解釋性通常難以實現(xiàn),但我們有機(jī)會至少可以在模塊級別上理解一些模型。這通常圍繞著了解哪些特征最具有影響力(通過特征重要性),然后關(guān)注最具影響力的變量如何驅(qū)動模型輸出(通過特征效應(yīng))。盡管我們可能無法完全理解具有數(shù)百個特征的模型,但實際上,只有十幾個變量對于驅(qū)動模型的性能起到了真正的重要作用。而且,我們有可能對這十幾個變量如何影響模型的性能有很清晰的理解。
局部解釋(Local interpretation)
全局解釋性方法幫助我們理解輸入與響應(yīng)變量的整體關(guān)系,但在某些情況下可能會產(chǎn)生誤導(dǎo)(例如,在出現(xiàn)強(qiáng)烈的交互作用時)。盡管某個特征可能會影響整體模型的預(yù)測準(zhǔn)確性,但并不意味著該特征對于特定觀測值或者一組觀測值的預(yù)測值具有最大的影響。局部解釋幫助我們理解哪些特征影響了特定觀測值的預(yù)測響應(yīng)。局部解釋不僅可以幫助我們回答客戶可能會做什么,還可以解釋模型對于特定觀測值的具體預(yù)測原因。
局部解釋有三種主要方法:
局部可解釋模型無關(guān)解釋(Local interpretable model-agnostic explanations, LIME)
Shapley值
局部逐步過程
以上三種方法下文會有系統(tǒng)介紹。當(dāng)然,這些方法的目標(biāo)是相同的:解釋哪些變量在預(yù)測一組觀測值上最具影響力。
模型特定 vs. 模型無關(guān)(Model-specific vs. model-agnostic)
還有一點很重要,那就是解釋模型的方法可以分為模型特定和模型無關(guān)兩種。在前面的章節(jié)中,我們看到的許多特征重要性理解方法都是模型特定的。例如,在線性模型中,我們可以使用t統(tǒng)計量的絕對值作為衡量特征重要性的指標(biāo)(不過當(dāng)線性模型涉及交互項和轉(zhuǎn)換時,情況會變得復(fù)雜)。另一方面,隨機(jī)森林可以記錄數(shù)據(jù)的OOB部分的預(yù)測準(zhǔn)確性,然后在對每個預(yù)測變量進(jìn)行置換后重復(fù)同樣的操作,并計算兩個準(zhǔn)確性之間的差異,然后在所有樹中進(jìn)行平均,并通過標(biāo)準(zhǔn)誤差進(jìn)行歸一化。這些模型特定的解釋工具局限于各自的模型類別。使用模型特定的方法也有一些優(yōu)點,因為它們與模型性能更緊密相關(guān),可能能夠更準(zhǔn)確地納入預(yù)測變量之間的相關(guān)性結(jié)構(gòu)。然而,這些方法也存在一些缺點。例如,許多機(jī)器學(xué)習(xí)算法(例如堆疊集成算法)沒有固有的方法來衡量特征重要性。
此外,在不同模型之間比較特征的模型特定重要性非常困難,因為這種情況下是在比較不同的測量指標(biāo)(例如,在線性模型中是(t)-統(tǒng)計量的大小,而在隨機(jī)森林中是預(yù)測準(zhǔn)確度的降低)。在模型無關(guān)的方法中,模型被視為一個“黑箱”。將可解釋性與具體模型分離使我們能夠輕松地在不同模型之間比較特征的重要性。
置換特征重要性
概念
在之前的章節(jié)中,我們展示了一些針對特征重要性的模型特定方法(例如,對于線性模型,我們使用了(t)-統(tǒng)計量的絕對值)。然而,對于支持向量機(jī)(SVM)來說,我們必須依賴于一種模型無關(guān)的方法,該方法是基于布雷曼(Breiman,2001)提出的用于隨機(jī)森林的排列特征重要性測量方法,并由費舍爾(Fisher)、魯丁(Rudin)和多米尼奇(Dominici)(2018)進(jìn)一步擴(kuò)展。
置換特征重要性是一種衡量特征對模型預(yù)測的重要性的方法。它的基本思想是在訓(xùn)練數(shù)據(jù)中對某個特征進(jìn)行隨機(jī)置換,然后觀察模型預(yù)測性能的變化。如果某個特征對模型的預(yù)測結(jié)果有重要影響,那么在置換該特征后,模型的性能會明顯下降。
具體步驟如下:
訓(xùn)練模型:首先,使用原始的訓(xùn)練數(shù)據(jù)來訓(xùn)練機(jī)器學(xué)習(xí)模型。
計算基準(zhǔn)性能:在訓(xùn)練完成后,使用模型對測試數(shù)據(jù)進(jìn)行預(yù)測,并計算模型的性能指標(biāo)(如準(zhǔn)確率、均方根誤差等),作為基準(zhǔn)性能。
置換特征:接下來,隨機(jī)選擇一個特征,并在訓(xùn)練數(shù)據(jù)中將該特征的值進(jìn)行隨機(jī)置換。
計算置換性能:使用置換后的數(shù)據(jù)進(jìn)行模型預(yù)測,并計算性能指標(biāo)。
計算特征重要性:將置換后的性能與基準(zhǔn)性能進(jìn)行比較,通過計算性能的變化來衡量特征的重要性。如果性能變化較大,說明該特征對模型預(yù)測有重要影響,其重要性較高;反之,如果性能變化較小,說明該特征對模型預(yù)測影響較小,其重要性較低。
通過反復(fù)執(zhí)行以上步驟,可以得到每個特征的重要性排序,從而幫助理解模型對不同特征的依賴程度。這種方法在解釋復(fù)雜模型的預(yù)測結(jié)果以及選擇最重要特征方面具有重要的應(yīng)用價值。
實現(xiàn)
置換特征重要性計算可以通過DALEX、iml和vip包來實現(xiàn),每個包都有其獨特的優(yōu)勢。
iml包提供了FeatureImp()函數(shù),使用置換法計算一般預(yù)測模型的特征重要性。FeatureImp()函數(shù)允許用戶指定通用損失函數(shù)或從預(yù)定義列表中選擇(例如,loss = "mse"表示均方誤差)。用戶還可以指定重要性是作為原始模型誤差與置換后的模型誤差之差還是比值來衡量。用戶還可以指定在對每個特征進(jìn)行排列時使用的重復(fù)次數(shù),以幫助穩(wěn)定過程中的變異性。
DALEX包也通過variable_importance()函數(shù)提供置換特征重要性分?jǐn)?shù)。與iml::FeatureImp()類似,該函數(shù)允許用戶指定損失函數(shù)以及如何計算重要性分?jǐn)?shù)(例如,使用差異或比值)。variable_importance()函數(shù)還提供了一個選項,在對數(shù)據(jù)計算重要性之前對訓(xùn)練數(shù)據(jù)進(jìn)行抽樣(默認(rèn)使用n_sample = 1000),這可以加快計算速度。
vip包專門關(guān)注變量重要性圖(VIPs),并提供多種模型特定和模型無關(guān)的的方法來計算變量重要性,包括置換法。使用vip包,我們可以使用自定義的損失函數(shù)(或從預(yù)定義列表中選擇),執(zhí)行蒙特卡洛模擬來穩(wěn)定過程,對特征置換之前對觀測值進(jìn)行抽樣,以及并行執(zhí)行計算,這可以加快處理大數(shù)據(jù)集的運行時間,等等。
以下示例通過vip執(zhí)行置換特征重要性計算。為了加快執(zhí)行速度,我們對訓(xùn)練數(shù)據(jù)進(jìn)行了30%的抽樣,但重復(fù)模擬了3次以增加我們估計的穩(wěn)定性
# 加載依賴包
library(dplyr) #數(shù)據(jù)操縱
library(ggplot2) # 可視化
# Modeling packages
library(h2o) # H2O
library(recipes) # 機(jī)器學(xué)習(xí)藍(lán)圖
library(rsample) # 數(shù)據(jù)分割
library(xgboost) # 擬合GBM模型
# 模型可解釋性包
library(pdp) # 偏依賴圖及ICE曲線繪制
library(vip) # 變量重要性VIP圖
library(iml) # 普遍IML相關(guān)函數(shù)
library(DALEX) # 普遍IML相關(guān)函數(shù)
# devtools::install_github('thomasp85/lime')
library(lime) # 局部可解釋模型無關(guān)解釋
load("inputdata.Rda")#加載示例數(shù)據(jù)
inputdata<-inputdata[,-1]
inputdata$Event<-factor(inputdata$Event,levels = c(0,1),labels = c("Alive","Death"))#結(jié)局變量因子化
set.seed(123) # 設(shè)置隨機(jī)種子保證可重復(fù)性
split <- initial_split(inputdata, strata = "Event")#數(shù)據(jù)分割
data_train <- training(split)
data_test <- testing(split)
# 分類變量ML藍(lán)圖
blueprint <- recipe(Event ~ ., data = data_train) %>%
step_other(all_nominal(), threshold = 0.005)
#為h2o產(chǎn)生訓(xùn)練數(shù)據(jù)集和驗證集
h2o.init()#啟動h2o
train_h2o <- prep(blueprint, training = data_train, retain = TRUE) %>%
juice() %>%
as.h2o()
test_h2o <- prep(blueprint, training = data_train) %>%
bake(new_data = data_test) %>%
as.h2o()
#定義響應(yīng)變量(目標(biāo)變量)和特征變量
Y <- "Event"
X <- setdiff(names(data_train), Y)
#定義GBM網(wǎng)格搜索超參數(shù)
hyper_grid <- list(
max_depth = c(1, 3, 5),
min_rows = c(1, 5, 10),
learn_rate = c(0.01, 0.05, 0.1),
learn_rate_annealing = c(0.99, 1),
sample_rate = c(0.5, 0.75, 1),
col_sample_rate = c(0.8, 0.9, 1)
)
#定義隨機(jī)網(wǎng)格搜索標(biāo)準(zhǔn)
search_criteria <- list(
strategy = "RandomDiscrete",
max_models = 25
)
#建立網(wǎng)格搜索
random_grid <- h2o.grid(
algorithm = "gbm", grid_id = "gbm_grid", x = X, y = Y,
training_frame = train_h2o, hyper_params = hyper_grid,
search_criteria = search_criteria, ntrees = 5000, stopping_metric = "AUC",
stopping_rounds = 10, stopping_tolerance = 0, nfolds = 10,
fold_assignment = "Modulo", keep_cross_validation_predictions = TRUE,
seed = 123
)
# 使用GBM算法擬合一個堆疊模型
ensemble <- h2o.stackedEnsemble(
x = X, y = Y, training_frame = train_h2o, model_id = "ensemble_gbm_grid",
base_models = random_grid@model_ids, metalearner_algorithm = "gbm"
)
#創(chuàng)建一個自定義函數(shù),將預(yù)測值返回為一個向量
pred <- function(object, newdata) {
results <- as.vector(h2o.predict(object, as.h2o(newdata)))
return(results)
}
#以下過程會花費較長時間
vip(
ensemble,
train = as.data.frame(train_h2o),
method = "permute",
target = "Event",
metric = "AUC",
reference_class="Alive",
nsim =3,
sample_frac = 0.3,#抽取30%的樣本
pred_wrapper = pred
)
偏依賴圖
在機(jī)器學(xué)習(xí)中,偏依賴圖(Partial Dependence Plot,簡稱PDP)是一種可視化工具,用于分析模型中特征與預(yù)測結(jié)果之間的關(guān)系。它幫助我們了解單個特征對預(yù)測結(jié)果的影響,同時控制其他特征的平均效果。
偏依賴圖的繪制過程如下:
- 首先,選擇一個特征作為要分析的目標(biāo)特征。
- 在這個特征的取值范圍內(nèi),生成一組等間距的值,稱為網(wǎng)格。
- 對于每個網(wǎng)格值,保持其他特征不變,使用訓(xùn)練好的模型進(jìn)行預(yù)測,并記錄預(yù)測結(jié)果。
- 繪制網(wǎng)格值和對應(yīng)預(yù)測結(jié)果的散點圖,并計算每個網(wǎng)格值的平均預(yù)測結(jié)果。
- 最后,繪制平均預(yù)測結(jié)果隨目標(biāo)特征取值的變化曲線,即偏依賴圖。
通過偏依賴圖,我們可以直觀地觀察到特征與預(yù)測結(jié)果之間的非線性關(guān)系,發(fā)現(xiàn)特征對預(yù)測結(jié)果的貢獻(xiàn)程度,從而更好地理解模型的行為和預(yù)測結(jié)果的解釋。它對于解釋模型、調(diào)整特征、優(yōu)化模型以及發(fā)現(xiàn)數(shù)據(jù)中的隱藏模式都具有重要的幫助作用。
偏依賴圖的實現(xiàn)
pdq包(Brandon Greenwell 2018)是一個被廣泛用于構(gòu)建PDPs(Partial Dependence Plots)的R包。
iml和DALEX包也提供PDP的功能。然而,pdq包內(nèi)置了對許多模型的支持,但對于不支持的模型(例如h2o堆疊模型),我們需要封裝一個自定義的預(yù)測函數(shù),如下所示。首先,我們創(chuàng)建一個自定義預(yù)測函數(shù),但這里我們返回預(yù)測值的平均值。
# 自定義函數(shù),返回預(yù)測值的均值
pred.prob <- function(object, newdata) {
pred <- predict(object, as.h2o(newdata),type="prob")
prob<-pred[, 2]
mean(prob)
}
然后,我們使用pdp::partial()函數(shù)計算偏依賴值。
# 計算部分依賴值PDP
pd_values <- partial(
ensemble,
type="classification",
train =as.data.frame(train_h2o),
pred.var ="ABHD2",
pred.fun = pred.prob,
grid.resolution = 20
)
我們可以查看下PDP值
head(pd_values)
# ABHD2 yhat
# 1 1.249515 0.7794302
# 2 1.574986 0.7794302
# 3 1.900457 0.7794302
# 4 2.225927 0.7794302
# 5 2.551398 0.7794302
# 6 2.876869 0.7794302
我們可以使用autoplot()函數(shù)和ggplot2來查看PDPs。
# Partial dependence plot
autoplot(pd_values, rug = TRUE, train = as.data.frame(train_h2o))+
theme_bw()+
geom_line(linewidth=1,color="red")
PDPs主要用于展示特征對預(yù)測響應(yīng)值的邊際效應(yīng)。然而,Brandon M Greenwell、Boehmke和McCarthy(2018)提出了一種方法,使用偏依賴函數(shù)的相對“平坦程度”作為變量重要性的衡量指標(biāo)。其思想是對預(yù)測響應(yīng)值具有更大邊際效應(yīng)的特征更為重要。我們可以通過使用vip包,并設(shè)置method = "pdp"來實現(xiàn)基于PDP的特征重要性度量。此外,基于上述過程得到的變量重要性分?jǐn)?shù)還保留了計算的偏依賴值。
個體條件期望(Individual Conditional Expectation,ICE)
個體條件期望(Individual Conditional Expectation,ICE)是一種用于解釋機(jī)器學(xué)習(xí)模型預(yù)測結(jié)果的方法。它可以幫助理解某個樣本在特征空間中的預(yù)測值是如何隨著特征的變化而變化的。ICE圖是通過在特征空間中對某個樣本進(jìn)行采樣,然后固定其他特征的值,僅改變一個特征的值,來計算預(yù)測結(jié)果的期望。通過繪制每個特征的ICE圖,我們可以直觀地看到在不同特征取值下,模型的預(yù)測結(jié)果是如何變化的。這可以幫助我們發(fā)現(xiàn)模型中的非線性關(guān)系和交互作用,進(jìn)一步理解模型的預(yù)測能力和局限性。
與PDPs類似,用于繪制ICE曲線的首選包是pdp包;但是,iml包也提供了ICE曲線繪制功能。使用pdp包創(chuàng)建ICE曲線的過程與PDPs基本相同,不同之處在于在自定義預(yù)測函數(shù)中不再對預(yù)測值進(jìn)行平均化(不應(yīng)用mean())。默認(rèn)情況下,autoplot()會繪制所有觀測值,我們可以通過設(shè)置center = TRUE以使每個觀測值所對應(yīng)的曲線按照第一條曲線居中。
# Construct c-ICE curves
#先自定義函數(shù)用于返回預(yù)測值,與PDP不一樣的是這里不取均值
pred.ice <- function(object, newdata) {
results <- as.vector(h2o.predict(object, as.h2o(newdata))[,2])
return(results)
}
#繪制ICE圖
partial(
ensemble,
train = as.data.frame(train_h2o),
pred.var = "ABHD2",
pred.fun = pred,
grid.resolution = 20,
plot = TRUE,
center = TRUE,
plot.engine = "ggplot2"
)
下一章節(jié)我們將介紹:
LIME[1]
SHAP[2]值
局部逐步過程[3]