第一篇文章
背景
您想要进行的机器学习不是获得预测结果,而是根据预测结果做出一些决策。但是数据科学家并不处于决策位置(今天大部分时间),而是将决策权交给另一个人。
此时,数据科学家需要说明获得预测结果的原理,以便决策者可以信任预测结果并做出决策。
在许多机器学习的应用中,要求用户信任模型以帮助他们做出决策。医生肯定不会仅仅因为"模型如此说。"
局部可解释模型不可知解释(LIME)简介
我做了什么
LIME用于可视化和解释XGBoost和LightGBM的结果。
什么是LIME?
https://arxiv.org/abs/1602.04938
取得一个预测结果,并使用另一种可解释模型(例如线性模型)对它进行局部近似。根据此处获得的模型的偏回归系数,确定哪个特征量有助于预测结果以及影响程度。
本页上的解释非常容易理解。
使用数据
我们使用了UCI上发布的蘑菇数据集(该数据集根据蘑菇环的数量和伞的颜色等特征对可食用/不可食用蘑菇进行了分类)。
码
总结执行的代码和简短描述。
执行代码(GitHub)
https://github.com/qrlokki/learning/blob/master/LIME_test/notebooks/LIME_classification_with_XGBoost_and_LightGBM.ipynb
代码内容
图书馆,数据导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import os, sys, math import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt from sklearn.preprocessing import OneHotEncoder from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score from plotting import plot_extension import lightgbm as lgbm ### params RAWDATA_DIR = "../data/raw" RANDOM_STATE = 123 ### read data COLNAMES = [ "edibility", "cap-shape", "cap-surface", "cap-color", "bruises", "odor", "gill-attachment", "gill-spacing", "gill-size", "gill-color", "stalk-shape", "stalk-root", "stalk-surface-above-ring", "stalk-surface-below-ring", "stalk-color-above-ring", "stalk-color-below-ring", "veil-type", "veil-color", "ring-number", "ring-type", "spore-print-color", "population", "habitat" ] rawdata = pd.read_csv(os.path.join(RAWDATA_DIR,"agaricus-lepiota.data"), names=COLNAMES) |
可视化
1 2 3 4 5 6 7 8 9 10 | ### visualize count of value each features fig = plt.figure(figsize=(13,25)) for i, c in enumerate(rawdata.columns): ax = fig.add_subplot( math.ceil(len(rawdata.columns) / 3), 3, i + 1) # plot the continent on these axes sns.countplot(x=c, data=rawdata, ax=ax) ax.set_title(c) fig.tight_layout() plt.show() |
1 2 3 4 5 6 7 8 9 10 11 12 13 | fig = plt.figure(figsize=(13,25)) for i, c in enumerate(rawdata.columns): ax = fig.add_subplot( math.ceil(len(rawdata.columns) / 3), 3, i + 1) # plot the continent on these axes sns.countplot(x=c, hue="edibility", data=rawdata, ax=ax) ax.set_title(c) fig.tight_layout() plt.show() |
使用XGBoost
进行分类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | X = rawdata.iloc[:, 1:] y = rawdata.iloc[:, 0] # train/test split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, shuffle=True, random_state=RANDOM_STATE) # label encode mle = MultiColumnLabelEncoder() X_train = mle.fit_transform(X_train) X_test = mle.transform(X_test) le = LabelEncoder() y_train = le.fit_transform(y_train) y_test = le.transform(y_test) # one-hot cat_feats = X_train.columns X_train = pd.get_dummies(X_train, columns=cat_feats) X_test = pd.get_dummies(X_test, columns=cat_feats) missing_cols = set(X_train.columns) - set(X_test.columns) for c in missing_cols: X_test[c] = 0 X_test = X_test[X_train.columns] import xgboost as xgbm from sklearn import metrics watchlist = [(X_train.values, y_train), (X_test.values, y_test)] xgbm_classifier = xgbm.XGBClassifier( objectibe='binary:logistic', n_estimators=10000, learning_rate=0.01, reg_lambda=0.5, reg_alpha=0.5, colsample_bytree=0.8, subsample=0.8, seed=RANDOM_STATE) xgbm_classifier.fit( X_train.values, y_train, eval_metric='auc', early_stopping_rounds=100, verbose=50, eval_set=watchlist, ) y_test_pred_proba = xgbm_classifier.predict_proba( X_test.values, ntree_limit=xgbm_classifier.best_iteration) print('auc : {0:.6f}'.format(metrics.roc_auc_score(y_test, y_test_pred_proba[:,1]))) |
使用LIME
1 2 3 4 5 6 7 8 9 10 11 12 13 | import lime import lime.lime_tabular explainer = lime.lime_tabular.LimeTabularExplainer( X_train.values, mode='classification', feature_names=X_train.columns, class_names=["edible", "poisonous"], verbose=True ) i = 15 exp = explainer.explain_instance(X_test.values[i], xgbm_classifier.predict_proba, num_features=5) exp.show_in_notebook(show_all=False) print(y_test_pred_proba[i], exp.score, exp.intercept) |
进行LightGBM分类器并使用LIME
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | dtrain = lgbm.Dataset(X_train, y_train) dtest = lgbm.Dataset(X_test, y_test, reference=dtrain) params = { 'objective': 'binary', 'metric': 'auc', 'learning_rate': 0.01, 'reg_lambda': 0.5, 'reg_alpha': 0.5, 'colsample_bytree': 0.8, 'subsample': 0.8, 'seed': RANDOM_STATE } lgbm_classifier = lgbm.train( params, dtrain, valid_sets=dtest, num_boost_round=10000, early_stopping_rounds=50, verbose_eval=50, ) y_test_pred_proba = lgbm_classifier.predict( X_test.values, ntree_limit=lgbm_classifier.best_iteration) print('\nauc : {0:.6f}'.format(metrics.roc_auc_score(y_test, y_test_pred_proba))) # LIME def predict_fn(x): preds = lgbm_classifier.predict(x).reshape(-1, 1) p0 = 1 - preds return np.hstack((p0, preds)) explainer = lime.lime_tabular.LimeTabularExplainer( X_train.values, mode='classification', feature_names=X_train.columns, class_names=["edible", "poisonous"], verbose=True ) i = 15 exp = explainer.explain_instance(X_test.values[i], predict_fn, num_features=5) exp.show_in_notebook(show_all=False) print(y_test_pred_proba[i], exp.score, exp.intercept) |
结果
XGBoost:
LightGBM:
该图从左侧为
- 近似后的分类器结果
- 每个功能的权重
- 每个功能的实际价值
它是
。
这些是预测同一样本的结果,但是LIME近似的模型的内容完全不同。出现的功能相似,但权重不同。要素
以后要显示的功能数量可以通过
警告
我觉得我必须要小心。
-
LightGBM无法按原样使用预测方法。由于LIME符合sklearn,因此我认为在二进制分类的结果中,它将以(2,)的形式出现。但是,LightGBM的预测仅返回1d的结果,因此我制作了
predict_fn 方法并在explain_instance 中调用了它。
1 2 3 4 5 | # LIME def predict_fn(x): preds = lgbm_classifier.predict(x).reshape(-1, 1) p0 = 1 - preds return np.hstack((p0, preds)) |
- 对可解释模型的局部逼近结果与原始模型获得的结果不同。这次我还没有真正看过有什么区别,但是最好在实际使用时看看它。
最后
人们倾向于接受他们可以解释和理解的内容(我认为),因此我认为从信任结果的angular解释此类内容非常有效。可视化的方式易于理解和交谈。
有几点需要注意,但是我想利用它们。
说到结果解释,关于结果解释的课程刚刚从kaggle开始。三个主要主题是哪些特征很重要,这些特征如何对某个预测结果有所贡献以及每个特征如何对所有数据的预测有所贡献,并使用了eli5和ppdbox。还有运动,这是相当不错的。
我已经在GitHub上发布了我所做的事情,所以我想在总结时总结一下。
第一次写起塔很困难。花了很长时间。
如果您发现有问题,请在评论中告知我们。
参考
- https://github.com/marcotcr/lime
- https://arxiv.org/abs/1602.04938
- https://www.oreilly.com/learning/introduction-to-local-interpretable-model-agnostic-explanations-lime
- http://pesuchin.hatenablog.com/entry/2017/01/07/170859