理解XGBoost機器學習模型的決策過程

機器之心發表於2017-12-20

隨著機器學習的產業應用不斷髮展,理解、解釋和定義機器學習模型的工作原理似乎已成日益明顯的趨勢。對於非深度學習型別的機器學習分類問題,XGBoost 是最流行的庫。由於 XGBoost 可以很好地擴充套件到大型資料集中,並支援多種語言,它在商業化環境中特別有用。例如,使用 XGBoost 可以很容易地在 Python 中訓練模型,並把模型部署到 Java 產品環境中。


雖然 XGBoost 可以達到很高的準確率,但對於 XGBoost 如何進行決策而達到如此高的準確率的過程,還是不夠透明。當直接將結果移交給客戶的時候,這種不透明可能是很嚴重的缺陷。理解事情發生的原因是很有用的。那些轉向應用機器學習理解資料的公司,同樣需要理解來自模型的預測。這一點變得越來越重要。例如,誰也不希望信貸機構使用機器學習模型預測使用者的信譽,卻無法解釋做出這些預測的過程。


另一個例子是,如果我們的機器學習模型說,一個婚姻檔案和一個出生檔案是和同一個人相關的(檔案關聯任務),但檔案上的日期暗示這樁婚姻的雙方分別是一個很老的人和一個很年輕的人,我們可能會質疑為什麼模型會將它們關聯起來。在諸如這樣的例子中,理解模型做出這樣的預測的原因是非常有價值的。其結果可能是模型考慮了名字和位置的獨特性,並做出了正確的預測。但也可能是模型的特徵並沒有正確考慮檔案上的年齡差距。在這個案例中,對模型預測的理解可以幫助我們尋找提升模型效能的方法。


在這篇文章中,我們將介紹一些技術以更好地理解 XGBoost 的預測過程。這允許我們在利用 gradient boosting 的威力的同時,仍然能理解模型的決策過程。


為了解釋這些技術,我們將使用 Titanic 資料集。該資料集有每個泰坦尼克號乘客的資訊(包括乘客是否生還)。我們的目標是預測一個乘客是否生還,並且理解做出該預測的過程。即使是使用這些資料,我們也能看到理解模型決策的重要性。想象一下,假如我們有一個關於最近發生的船難的乘客資料集。建立這樣的預測模型的目的實際上並不在於預測結果本身,但理解預測過程可以幫助我們學習如何最大化意外中的生還者。


import pandas as pd
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import operator
import matplotlib.pyplot as plt
import seaborn as sns
import lime.lime_tabular
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import Imputer
import numpy as np
from sklearn.grid_search import GridSearchCV
%matplotlib inline


我們要做的首件事是觀察我們的資料,你可以在 Kaggle 上找到(https://www.kaggle.com/c/titanic/data)這個資料集。拿到資料集之後,我們會對資料進行簡單的清理。即:


  • 清除名字和乘客 ID
  • 把分類變數轉化為虛擬變數
  • 用中位數填充和去除資料


這些清洗技巧非常簡單,本文的目標不是討論資料清洗,而是解釋 XGBoost,因此這些都是快速、合理的清洗以使模型獲得訓練。


data = pd.read_csv("./data/titantic/train.csv")
y = data.Survived
X = data.drop(["Survived", "Name", "PassengerId"], 1)
X = pd.get_dummies(X)


現在讓我們將資料集分為訓練集和測試集。


X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)


並通過少量的超引數測試構建一個訓練管道。


pipeline = Pipeline([('imputer', Imputer(strategy='median')), ('model', XGBClassifier())])
parameters = dict(model__max_depth=[3, 5, 7],
model__learning_rate=[.01, .1],
model__n_estimators=[100, 500])
cv = GridSearchCV(pipeline, param_grid=parameters)
cv.fit(X_train, y_train)


接著檢視測試結果。為簡單起見,我們將會使用與 Kaggle 相同的指標:準確率。


test_predictions = cv.predict(X_test)
print("Test Accuracy: {}".format(accuracy_score(y_test, test_predictions)))
Test Accuracy: 0.8101694915254237


至此我們得到了一個還不錯的準確率,在 Kaggle 的大約 9000 個競爭者中排到了前 500 名。因此我們還有進一步提升的空間,但在此將作為留給讀者的練習。

我們繼續關於理解模型學習到什麼的討論。常用的方法是使用 XGBoost 提供的特徵重要性(feature importance)。特徵重要性的級別越高,表示該特徵對改善模型預測的貢獻越大。接下來我們將使用重要性引數對特徵進行分級,並比較相對重要性。


fi = list(zip(X.columns, cv.best_estimator_.named_steps['model'].feature_importances_))
fi.sort(key = operator.itemgetter(1), reverse=True)
top_10 = fi[:10]
x = [x[0] for x in top_10]
y = [x[1] for x in top_10]

理解XGBoost機器學習模型的決策過程

從上圖可以看出,票價和年齡是很重要的特徵。我們可以進一步檢視生還/遇難與票價的相關分佈:

理解XGBoost機器學習模型的決策過程

我們可以很清楚地看到,那些生還者相比遇難者的平均票價要高得多,因此把票價當成重要特徵可能是合理的。


特徵重要性可能是理解一般的特徵重要性的不錯方法。假如出現了這樣的特例,即模型預測一個高票價的乘客無法獲得生還,則我們可以得出高票價並不必然導致生還,接下來我們將分析可能導致模型得出該乘客無法生還的其它特徵。


這種個體層次上的分析對於生產式機器學習系統可能非常有用。考慮其它例子,使用模型預測是否可以某人一項貸款。我們知道信用評分將是模型的一個很重要的特徵,但是卻出現了一個擁有高信用評分卻被模型拒絕的客戶,這時我們將如何向客戶做出解釋?又該如何向管理者解釋?


幸運的是,近期出現了華盛頓大學關於解釋任意分類器的預測過程的研究。他們的方法稱為 LIME,已經在 GitHub 上開源(https://github.com/marcotcr/lime)。本文不打算對此展開討論,可以參見論文(https://arxiv.org/pdf/1602.04938.pdf


接下來我們嘗試在模型中應用 LIME。基本上,首先需要定義一個處理訓練資料的直譯器(我們需要確保傳遞給直譯器的估算訓練資料集正是將要訓練的資料集):


X_train_imputed = cv.best_estimator_.named_steps['imputer'].transform(X_train)
explainer = lime.lime_tabular.LimeTabularExplainer(X_train_imputed,
feature_names=X_train.columns.tolist(),
class_names=["Not Survived", "Survived"],
discretize_continuous=True)


隨後你必須定義一個函式,它以特徵陣列為變數,並返回一個陣列和每個類的概率:


model = cv.best_estimator_.named_steps['model']
def xgb_prediction(X_array_in):
if len(X_array_in.shape) < 2:
X_array_in = np.expand_dims(X_array_in, 0)
return model.predict_proba(X_array_in)

最後,我們傳遞一個示例,讓直譯器使用你的函式輸出特徵數和標籤:


X_test_imputed = cv.best_estimator_.named_steps['imputer'].transform(X_test)
exp = explainer.explain_instance(X_test_imputed[1], xgb_prediction, num_features=5, top_labels=1)
exp.show_in_notebook(show_table=True, show_all=False)

理解XGBoost機器學習模型的決策過程

在這裡我們有一個示例,76% 的可能性是不存活的。我們還想看看哪個特徵對於哪個類貢獻最大,重要性又如何。例如,在 Sex = Female 時,生存機率更大。讓我們看看柱狀圖:

理解XGBoost機器學習模型的決策過程

所以這看起來很有道理。如果你是女性,這就大大提高了你在訓練資料中存活的機率。所以為什麼預測結果是「未存活」?看起來 Pclass =2.0 大大降低了存活率。讓我們看看:

理解XGBoost機器學習模型的決策過程

看起來 Pclass 等於 2 的存活率還是比較低的,所以我們對於自己的預測結果有了更多的理解。看看 LIME 上展示的 top5 特徵,看起來這個人似乎仍然能活下來,讓我們看看它的標籤:


y_test.values[0]
>>>1


這個人確實活下來了,所以我們的模型有錯!感謝 LIME,我們可以對問題原因有一些認識:看起來 Pclass 可能需要被拋棄。這種方式可以幫助我們,希望能夠找到一些改進模型的方法。


本文為讀者提供了一個簡單有效理解 XGBoost 的方法。希望這些方法可以幫助你合理利用 XGBoost,讓你的模型能夠做出更好的推斷。


原文地址: https://blogs.ancestry.com/ancestry/2017/12/18/understanding-machine-learning-xgboost/

相關文章