数据STUDIO

又一个机器学习模型解释神器:LIME


在机器学习的许多应用中,要求用户信任模型来帮助他们做出决策。 医生肯定不会仅仅因为“模型这么说”就给病人做手术。 即使在风险较低的情况下,例如从 Netflix 选择要观看的电影时,在我们根据模型放弃几个小时的时间之前,也需要一定程度的信任。 尽管许多机器学习模型都是黑匣子,但了解模型预测背后的基本原理肯定会帮助用户决定何时信任或不信任他们的预测。

下图是模型预测某个患者患有流感的一个示例。由“解释器”解释预测,该“解释器”突出显示对模型最重要的症状。有了这些关于模型背后基本原理的信息,

简单的模型例如线性回归,LR等模型非常易于解释,但在实际应用中的效果却远远低于复杂的梯度提升树模型以及神经网络等模型。

现在大部分互联网公司的建模都是基于梯度提升树或者神经网络模型等复杂模型,遗憾的是,这些模型虽然效果好,但是我们却较难对其进行很好地解释,这也是目前一直困扰着大家的一个重要问题,现在大家也越来越加关注模型的解释性。

本文讨论了一种被称为LIME的新的解释技术,它可以解释任何分类器的预测。可以他认为是 SHAP ( 用 SHAP 可视化解释机器学习模型实用指南 )的升级版,更多详情可以查看Github链接:https://github.com/marcotcr/lime

什么是LIME?

LIME ,即 Local Interpretable Model-Agnostic Explanations ,是一种解释分类器或回归器预测的算法,通过用可解释的模型对其进行局部近似。它通过调整特征值来修改单个数据样本,并观察其对输出的影响。它扮演着 "解释者" 的角色,解释每个数据样本的预测。LIME的输出是一组解释,代表每个特征对单个样本预测的贡献,这是一种局部可解释性。

LIME 训练及解释模型

import lime
from lime import lime_tabular
from sklearn.ensemble import RandomForestClassifier
classifier=RandomForestClassifier()
classifier.fit(x_train,y_train)
interpretor = lime_tabular.LimeTabularExplainer(
    training_data=np.array(x_train),
    feature_names=x_train.columns,
    mode='classification')
exp = interpretor.explain_instance(
    data_row=x_test.iloc[5], ##new data
    predict_fn=classifier.predict_proba)
exp.show_in_notebook(show_table=True)
这是 索引为5的 测试数据的的解释的样子。

LIME将单个记录作为输入,然后将解释作为输出。

该解释有三个部分。

  1. 最左边的部分显示预测概率,在我们的例子中,0的概率是0.33,而1的概率是0.67。
  2. 中间部分返回最重要的特征。对于二元分类任务,它有两种颜色:橙色/蓝色。橙色的属性支持class 1,蓝色的属性支持class 0,Age>44 的支持class 1,水平条上的浮点数字代表这些特征的相对重要性。
  3. 颜色编码在各部分是一致的。它包含了变量的实际值。

LIME实战案例

LIME(Local Interpretable Model-agnostic Explanations)支持的模型包括:

  • 结构化模型的解释
  • 文本分类器的解释
  • 图像分类器的解释

LIME被用作解释机器学习模型的解释,通过LIME我们可以知道为什么模型会这样进行预测。本文介绍两种常用的监督模型:二分类及回归模型。更多详情可以查看Github链接:https://github.com/marcotcr/lime

LIME解释二分类模型

这里使用 fetch_20newgroups 数据集。为了简单起见,将使用两类子集:无神论atheism和信仰基督教christianity。
from sklearn.datasets import fetch_20newsgroups
categories = ['alt.atheism', 'soc.religion.christian']
newsgroups_train = fetch_20newsgroups(subset='train', categories=categories)
newsgroups_test = fetch_20newsgroups(subset='test', categories=categories)
class_names = ['atheism', 'christian']
使用文本数据常用处理的 tfidf 矢量化方法来处理数据。
vectorizer = sklearn.feature_extraction.text.TfidfVectorizer(lowercase=False)
train_vectors = vectorizer.fit_transform(newsgroups_train.data)
test_vectors = vectorizer.transform(newsgroups_test.data)

使用随机森林模型进行分类。一般情况下,我们比较难以理解随机森林在做什么,尤其是有很多基树评估器的森林。

rf = sklearn.ensemble.RandomForestClassifier(n_estimators=500)
rf.fit(train_vectors, newsgroups_train.target)
pred = rf.predict(test_vectors)
sklearn.metrics.f1_score(newsgroups_test.target, 
                         pred, average='binary')
# 0.9166666666666666
从结果看,该分类器 F1_socre 很高,接下来看看随机森林是否已经过拟合。

用LIME解释预测

Lime解释器假设分类器作用于原始文本,而sklearn分类器作用于文本的矢量表示。为此,使用sklearn的 pipeline ,并使用 predict_proba 来预测概率。

from lime import lime_text
from sklearn.pipeline import make_pipeline
c = make_pipeline(vectorizer, rf)
print(c.predict_proba([newsgroups_test.data[0]]))
# [[ 0.274  0.726]]
现在创建一个解释程序对象,我们给 class_names 传递一个参数,以便更好地显示。
from lime.lime_text import LimeTextExplainer
explainer = LimeTextExplainer(class_names=class_names)

然后为测试集中任意文档生成最多6个特性的解释。

idx = 83
exp = explainer.explain_instance(newsgroups_test.data[idx], c.predict_proba, num_features=6)
print('Document id: %d' % idx)
print('Probability(christian) =', c.predict_proba([newsgroups_test.data[idx]])[0,1])
print('True class: %s' % class_names[newsgroups_test.target[idx]])
Document id: 83
Probability(christian) = 0.45
True class: atheism

分类器对这个例子的预测是正确的(它预测了无神论)。

解释结果如下:加权特征列表。

exp.as_list()
[('Host', -0.149264358677072),
('Posting', -0.12720106435313583),
('NNTP', -0.09852417087289796),
('edu', -0.030833516990747947),
('There', -0.012734449577693457),
('University', 0.010456648119358973)]

这些加权特征是一个线性模型,它近似于测试示例附近的随机森林分类器的行为。粗略地说,如果我们从文档中删除 “posting” 和 “Host” ,那么预测应该向相反的类别(christian)移动约 0.27 (两个特征的权重之和)。我们看看情况是否如此。

print('Original prediction:', rf.predict_proba(test_vectors[idx])[0,1])
tmp = test_vectors[idx].copy()
tmp[0,vectorizer.vocabulary_['Posting']] = 0
tmp[0,vectorizer.vocabulary_['Host']] = 0
print('Prediction removing some features:', rf.predict_proba(tmp)[0,1])
print('Difference:', rf.predict_proba(tmp)[0,1] - rf.predict_proba(test_vectors[idx])[0,1])
Original prediction: 0.414
Prediction removing some features: 0.684
Difference: 0.27

这些解释该文献模式的词语似乎还不错,与基督教或无神论都没有太大关系。其实这些都是出现在电子邮件标题中的单词,这将更加容易区分类。

可视化解释

解释可以作为 matplotlib 的 barplot 返回:
%matplotlib inline
fig = exp.as_pyplot_figure()
解释也可以导出为html页面(我们可以在本笔记本中呈现),使用 D3.js 呈现图形。
exp.show_in_notebook(text=False)
或者,我们可以将完整包含的 html 页面保存到一个文件:
exp.save_to_file('/tmp/oi.html')

最后,我们还可以包含原始文档的可视化,并突出显示解释中的单词。注意,对分类器影响最大的单词都在电子邮件标题中。

exp.show_in_notebook(text=True)
这里随机森林只是一个例子,这个解释程序适用于你可能想要使用的任何分类器,只要该分类器具有 predict_proba 功能即可。

LIME解释回归模型

from sklearn.datasets import load_boston
import sklearn.ensemble
import numpy as np
import lime
import lime.lime_tabular

boston = load_boston()
rf = sklearn.ensemble.RandomForestRegressor(n_estimators=1000)
train, test, labels_train, labels_test = sklearn.model_selection.train_test_split(
    boston.data, 
    boston.target, 
    train_size=0.80)

rf.fit(train, labels_train)
print('Random Forest MSError', np.mean((rf.predict(test) - labels_test) ** 2))
print('MSError when predicting the mean', np.mean((labels_train.mean() - labels_test) ** 2))
print('MSError when predicting the mean', np.mean((labels_train.mean() - labels_test) ** 2))

categorical_features = np.argwhere(np.array([len(set(boston.data[:,x])) 
                                             for x in range(boston.data.shape[1])]) <= 10).flatten()

explainer = lime.lime_tabular.LimeTabularExplainer(train,
                   feature_names=boston.feature_names,
                   class_names=['price'], 
                   categorical_features=categorical_features, 
                   verbose=True, mode='regression')

i = 25
exp = explainer.explain_instance(test[i], rf.predict, num_features=5)
Random Forest MSError 10.988590741176479
MSError when predicting the mean 79.26374406656593
MSError when predicting the mean 79.26374406656593
Intercept 23.529141771424232
Prediction_local [24.50725476]
Right: 22.748400000000025
exp.show_in_notebook(show_table=True)
exp.as_list()
[('6.99 < LSTAT <= 11.43', 1.7571320048618118),
('6.21 < RM <= 6.62', -1.5638211582388033),
('NOX > 0.62', -0.77384372989110417),
('19.10 < PTRATIO <= 20.20', -0.60756112694664299),
('2.08 < DIS <= 3.17', -0.39085870918058263)]

VevestaX保存结果

VevestaX是一个开源的Python包,它包含各种特性,使数据科学家的工作变得更加容易,尤其是在分析和从数据中获得见解的时候。

该包可以用于从数据集中提取特征,并可以跟踪代码中使用的所有变量。

这个包最好的部分是它的输出。VevestaX的输出文件为我们提供了大量EDA工具,如直方图、性能图、相关矩阵等,而无需分别为它们编写实际的代码。

如何使用VevestaX?

使用以下方式安装软件包:

pip install vevestaX

下面是云朵君安装时,新增的几个依赖包,除此之外,还有不少已经安装过的。

Installing collected packages: deprecation, 
pynacl, py4j, pikepdf, statistics, pyspark,
PyGithub, ipynbname, img2pdf, datetime, vevestaX

导入并使用:

from vevestaX import vevesta as v
V=v.Experiment()
# 跟踪使用和设计的特征
V.ds = pd.DataFrame(boston.data, columns=boston.feature_names)
# V.fe = dataframe

最后,为了将所使用的特性和变量转储到一个excel文件中,并了解这些数据所携带的用途:

V.dump(techniqueUsed='LIME',
       filename="LIME.xlsx",
       message="AIF 360 was used",
       version=1)

下面是输出结果(部分):

写在最后

信任对于人类与机器学习系统的有效交互至关重要,我们认为解释个人预测是评估信任的有效方法。LIME 是一种有效的工具,可以促进机器学习从业者的这种信任,并且是添加到他们的工具带中的好选择。最后! 觉得好看,可以点个赞和在看支持下云朵君~

🏴‍☠️宝藏级🏴‍☠️ 原创公众号『 数据STUDIO 』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括 可戳 👉 Python | MySQL | 数据分析 | 数据可视化 | 机器学习与数据挖掘 | 爬虫 等,从入门到进阶!
长按👇关注- 数据STUDIO -设为星标,干货速递