关于在Python HTML中显示SHAP力图的教程

这是这是本教程的源代码,这样您就可以跟着学习,并且可以直接运行app.py看看结果。

动机

SHAP图对于模型的解释性非常有用(参见在这里关于它们的精彩演讲)。

作为最近使用SHAP显示英雄联盟数据逻辑回归的项目的一部分(你可以看到项目web应用程序)在这里以及下面的截图),我努力寻找一种在页面加载时显示SHAP图的方法,而不必先保存图像。我非常习惯在Jupyter笔记本或类似的东西上使用SHAP图,但我真的想在web应用程序上显示它。

因为这对我来说是一个很大的痛点,我想巩固我所学到的并在这里写下来。我会帮我弥补一些在试镜过程中遇到的困难base64plt.savefig ()我将以使用HTML iFrames的解决方案作为结束。

为了让这个结果可视化,一个示例最终结果是在Flask web应用程序中显示SHAP力图:

动态地将力图合并到用户界面中(您可以在上搜索“100 close”)看一样)

方法1:Base64编码

Base64是一个二进制到文本的编码方法。使用这个,我们可以定义我们的force_plot和使用plt.savefig ()把它存储在一个变量中缓冲区稍后我们可以解码成ASCII码。在我看来,理解功能不是很重要,但是结果你的电脑会保存每一张图片,然后以HTML格式显示。这意味着img标记的src变量必须在本地定位每个保存的图像。

使用XGBoost进行Base64编码的示例

”“”
示例实现XGBoost算法和base64方法来保存SHAP力图,然后在HTML中显示。
如果你在Flask中这样做,ML在app.py中,你传递SHAP力图作为一个变量,你可以在你的HTML页面中索引。”“”#火车测试分裂#让我们假设你有一些X_, y_…Xt, Xv, yt, yv = train_test_split(X_,y_, test_size=0.2, random_state=10)Dt = xgb。DMatrix (Xt,标签=欧美。值、enable_categorical = True)
Dv = xgb。DMatrix(十五、标签= yv.values)
通过超贝叶斯优化优化超参数
参数= {
“埃塔”:0.5,
“max_depth”:8
“min_child_weight”:1、
“目标”:“二进制:物流”,
“冗长”:0,
“base_score”:np.mean(次),
:“eval_metric logloss”,
“colsample_bytree”:0.7434869381604485,
“伽马”:1.1053886968419446,
“reg_alpha”:49.0,
“reg_lambda”:0.9997899615065826
#运行模型
Model = xgb。Train (params, dt, 35, [(dt, " Train "), (dv, "valid")], early_stopping_rounds=5, verbose_eval=35)
#SHAP解释器值(NumPy数组)
explainer = shape . treeexplainer(模型)
shap_values = explainer.shap_values(Xv)
# SHAP *力*图本身(使用这种方法,我认为你可以
#也做蜂群情节,但我没有尝试过)
Shap_plot = shap_force_plot (explainer.expected_value,
shap_values[1],特性= Xv.iloc [1:],
feature_names = Xv.columns (0:20),
matplotlib=True, show=False, plot_cmap=['#77dd77', '#f99191'])
#编码到base64,
#回答灵感:https://stackoverflow.com/questions/60621103/is-there-a-way-to-render-shap-or-lime-output-from-flask-to-react/60669449#60669449
buf = BytesIO()
plt.savefig(缓冲区,
格式= "png",
Dpi = 150,
bbox_inch = 'tight')
dataToTake = base64.b64encode(buf.getbuffer()).decode("ascii")
返回dataToTake
# HTML集成示例
这种方法存在的问题

虽然这对于单个地块生成很方便,但在生产环境中并不可行,因为这意味着您将保存每个地块。

方法2:plt.savefig()

使用plt.savefig ()我们缩短了我们的工作(Base64不是完全必要的),但它是相同的结果,必须保存每个力图,并将其作为一个文件索引在我们的< img src = " wherever_the_plot_is_locally " >标签。

#只是使用上面相同的XGBoost模型def shap_plot(印第安纳州):
explainer = shape . treeexplainer(模型)
shap_values = explainer.shap_values(Xv)
P = shap.force_plot(解释器。期望值,shap_values[ind], Xv.iloc[[ind]])
plt.savefig(“temp.svg”)
plt.close ()
返回p
shap_plot (3)

是的,这更容易理解,但同样不适用于生产环境:您仍然保存每个图像。

方法3:使用.html()选项(我最终使用的)

使用这种方法,我们可以利用HTML iFrames,它可以嵌入我们的SHAPforce_plot到主HTML中。

#在Dash中工作
#从这里开始:https://stackoverflow.com/questions/54292226/putting-html-output-from-shap-into-the-dash-output-layout-callback
def _force_plot_html (* args):
Force_plot = shape。force_plot(*args, matplotlib=False)
shap_html = f”< > {shap.getjs()} < /头> <身体> {force_plot.html()} < /身体> "
返回的html。Iframe (srcDoc = shap_html,
Style ={"width": "100%", "height": "200px",
“边境”:0})

这并不能完全转化为我所使用的,即Flask。我采用了上面的想法,并将其应用到Flask环境中:

集成到Flask web应用程序的示例:

假设你有一个这样的逻辑回归模型:

Xt, Xv, yt, yv = train_test_split(X_, y_, test_size=0.2, random_state=10)model = LogisticRegression(刑罚='l2',求解器='liblinear', max_iter=900, C=0.1)。fit (Xt,欧美)解释=形状。解释器(model, Xt, feature_names= x .columns)
shap_values =解释器(Xv)

基本的想法是好的app.py要创建_force_plot_html函数使用讲解员shap_values,印第安纳州返回一个shap_htmlsrcdoc。我们会通过这个shap_html变量到我们的HTML使用render_template,并在HTML文件本身中显示shap_html在嵌入的iFrame中。

这是一个我们循环的例子印第安纳州,创建各种SHAP图,并在我们的HTML中显示为iFrames。

#在app.py从烧瓶进口*进口世鹏科技电子
从shap.plots。导入draw_additive_plot
从模型导入give_shap_plotapp = Flask(__name__)@app.route(“/”)def displayshap ():解释器,shap_values = give_shap_plot()Def _force_plot_html(解释器,shap_values, ind):
Force_plot = shap_values .force(shap_values[ind],
matplotlib = False)
shap_html = f”< > {shap.getjs()} < /头> <身体> {force_plot.html()} < /身体> "
返回shap_html
Shap_plots = {}对于I在范围(10):#你想要多少块
Ind = I
shap_values [i] = _force_plot_html(explainer, shap_values, ind)

返回render_template('displayshap.html', shap_plots = shap_plots)
如果__name__ == '__main__':
app.run ()
#退出app.py
# # #
<!--HTML -->
<!--在displayshap.html -->
{% for I in shap_plots: %}
< iframe srcdoc = " {{shap_plots[我]}}”风格={“宽度”:“2000 px”;“高度”:“200 px”;} > . Border: none
{% endfor %}

shap.getjs ()是非常重要的,因为没有它,你会在你的HTML中得到一个“可视化省略,Javascript库未加载!””的问题。

来自本文教程存储库的示例结果。运行逻辑回归的代码借鉴于SHAP的文档,“情感分析与逻辑回归”。你得到相同的悬停效果,所有的javascript是保留的。

缺点

这种解决方案的一些缺点是它只适用于力图

  • 我不能得到蜂群/酒吧的图像这样工作:
#可行的情节类型:
Force_plot = shap_values .force(shap_values[ind],matplotlib = False)
#不起作用的情节类型:
Force_plot = sha_plot .beeswarm(shap_values)
Force_plot = shap.plot .bar(shap_values[ind])
#我认为没有。html()方法是为这些写的?我不太确定

谢谢你!

感谢您的阅读!我希望这对想要将SHAP合并到web应用程序中的任何人都有帮助。您可以找到本教程的源代码在这里

你可以在网上找到我我的网站LinkedIn,或github.你可以读更多我的作品在这里

使用Medium应用程序

一个写着“在应用商店下载”的按钮,如果点击它将引导你进入iOS应用商店
一个写着“开始吧,谷歌Play”的按钮,如果点击它,就会引导你进入谷歌Play商店
Baidu
map