机器学习模型经常被批评为黑盒子:我们将数据放在一边,并得出答案 - 通常非常准确的答案 - 而另一方面没有解释。在本系列的第三部分展示了一个完整的机器学习解决方案,我们将深入研究我们开发的模型,以尝试理解它如何进行预测以及它可以告诉我们有关该问题的内容。我们将讨论机器学习项目中最重要的部分:记录我们的工作并展示结果。
该系列的第一部分包括数据清理,探索性数据分析,特征工程和特征选择。第二部分介绍了缺失值,实现和比较机器学习模型,使用随机搜索和交叉验证进行超参数调整,以及评估模型。
该项目的所有代码都在GitHub上。对应这篇文章的第三个Jupyter笔记本就在这里。我鼓励任何人分享,使用和构建此代码!
提醒一下,我们正在通过监督回归机器学习问题。利用纽约市建筑能源数据,我们开发了一个模型,可以预测建筑物的能源之星得分。我们构建的最终模型是Gradient Boosted回归量,它能够将测试数据上的能量之星得分预测到9.1分(1-100分)。
梯度增强回归量位于模型可解释性中间的中间位置:整个模型很复杂,但它由数百个决策树组成,这些决策树本身是可以理解的。我们将研究三种方法来理解我们的模型如何进行预测:
前两种方法特定于树的集合,而第三种 - 正如您可能从名称中猜到的 - 可以应用于任何机器学习模型。LIME是一个相对较新的软件包,代表了解释机器学习预测的持续努力中令人兴奋的一步。
功能重要性
要素重要性尝试显示每个要素与预测目标任务的相关性。特征重要性的技术细节很复杂(它们测量平均减少杂质,或者包括特征的误差减少),但我们可以使用相对值来比较哪些特征最相关。在Scikit-Learn中,我们可以从任何基于树的学习者集合中提取特征重要性。
通过model
我们训练有素的模型,我们可以找到使用的特征重要性model.feature_importances_
。然后我们可以将它们放入pandas DataFrame中并显示或绘制前十个最重要的:
import pandas as pd
# 模型训练的模型
importances = model.feature_importances_
# train_features是训练特点的数据帧
feature_list = list(train_features.columns)
# 将要素重要性提取到数据框中
feature_results = pd.DataFrame({'feature': feature_list,
'importance': importances})
# 显示最重要的前十名
feature_results = feature_results.sort_values('importance',
ascending = False).reset_index(drop=True)
feature_results.head(10)
在Site EUI
(能源使用强度),并且Weather Normalized Site Electricity Intensity
是目前最重要的特征,占到总的重要性超过66%。在前两个功能之后,重要性显着下降,这表明我们可能不需要保留数据中的所有64个功能以实现高性能。(在Jupyter笔记本中,我看一下仅使用前10个功能并发现该模型不太准确。)
基于这些结果,我们最终可以回答我们的一个初步问题:建筑物能源之星得分最重要的指标是场地EUI和天气归一化场地电力强度。虽然我们确实需要注意过多地阅读特征重要性,但它们是开始理解模型如何进行预测的有用方法。
虽然整个梯度增强回归量可能难以理解,但任何一个单独的决策树都非常直观。我们可以使用Scikit-Learn功能可视化森林中的任何树export_graphviz
。我们首先从集合中提取树,然后将其保存为点文件:
from sklearn import tree
# Extract a single tree (number 105)
single_tree = model.estimators_[105][0]
# Save the tree to a dot file
tree.export_graphviz(single_tree, out_file = 'images/tree.dot',
feature_names = feature_list)
使用Graphviz可视化软件,我们可以从命令行将点文件转换为png:
dot -Tpng images/tree.dot -o images/tree.png
结果是一个完整的决策树:
模型中的完整决策树
这有点压倒性!尽管这棵树的深度只有6(层数),但很难遵循。我们可以修改调用export_graphviz
并将树限制为更合理的深度2:
决策树限制为2的深度
树中的每个节点(框)都有四条信息:
mse
其是该节点的误差的测量samples
是在节点的实施例(数据点)的数目value
是节点中所有样本的目标估计值决策树中的单个节点
(叶节点只有2.-4。因为它们代表最终估计并且没有任何子节点)。
决策树通过从称为根的顶部节点开始并沿着树向下工作来对数据点进行预测。在每个节点,询问数据点是或否。例如,上述节点的问题是:建筑物的Site EUI是否小于或等于68.95?如果答案为是,则将建筑物放置在右子节点中,如果答案为否,则建筑物将转到左子节点。
在树的每一层重复该过程,直到数据点被放置在树的底部的叶节点中(叶子节点从小树图像中裁剪)。对叶子节点中所有数据点的预测是value
。如果samples
叶节点中有多个数据点(),则它们都获得相同的预测。随着树的深度增加,训练集上的误差将减少,因为有更多叶节点并且示例可以更精细地划分。但是,太深的树将过度拟合训练数据,并且无法推广到新的测试数据。
在第二篇文章中,我们调整了许多模型超参数,它们控制每棵树的各个方面,例如树的最大深度和叶节点中所需的最小样本数。这些都会对under over和over-fit的平衡产生重大影响,并且可视化单个决策树使我们能够看到这些设置如何工作。
虽然我们无法检查模型中的每一棵树,但查看一个树可以让我们了解每个学习者如何进行预测。这种基于流程图的方法看起来很像人类做出决策,一次回答一个关于单个值的问题。基于决策树的集合组合了许多单个决策树的预测,以便创建具有较小方差的更准确的模型。树木的集合往往非常准确,也很容易解释。
我们将探索的最终工具,试图理解我们的模型“思考”是模型解释领域的新进入。LIME旨在通过使用简单模型(如线性回归)在数据点附近创建模型近似来解释任何机器学习模型中的单个预测(完整细节可在本文中找到)。
在这里,我们将使用LIME来检查模型完全错误的预测,看看它可能告诉我们模型为什么会出错。
首先,我们需要找到我们的模型最错误的观察结果。我们通过使用模型进行训练和预测并提取模型具有最大误差的示例来实现此目的:
from sklearn.ensemble import GradientBoostingRegressor
# 创建具有最佳超级参数的模型
model = GradientBoostingRegressor(loss='lad', max_depth=5, max_features=None,
min_samples_leaf=6, min_samples_split=6,
n_estimators=800, random_state=42)
# 适合并测试功能
model.fit(X, y)
model_pred = model.predict(X_test)
# 找到残差
residuals = abs(model_pred - y_test)
# 提取最错误的预测
wrong = X_test[np.argmax(residuals), :]
print('Prediction: %0.4f' % np.argmax(residuals))
print('Actual Value: %0.4f' % y_test[np.argmax(residuals)])
Prediction: 12.8615
Actual Value: 100.0000
接下来,我们创建LIME explainer对象,将我们的训练数据,模式,训练标签和数据中的特征名称传递给它。最后,我们要求解释器对象解释错误的预测,并将其传递给观察和预测函数。
import lime
# 创建一个lime explaininer对象
explainer = lime.lime_tabular.LimeTabularExplainer(training_data = X,
mode = 'regression',
training_labels = y,
feature_names = feature_list)
# 错误预测的解释
exp = explainer.explain_instance(data_row = wrong,
predict_fn = model.predict)
# 绘制预测解释
exp.as_pyplot_figure();
解释这一预测的plot如下:
以下是如何解释绘图:y轴上的每个条目表示变量的一个值,红色和绿色条表示此值对预测的影响。例如,顶部条目表示Site EUI大于95.90,从预测中减去约40个点。第二个条目表示天气归一化场地电力强度小于3.80,这增加了预测的10个点。最终预测是截距项加上每个单独贡献的总和。
我们可以通过调用explaininer .show_in_notebook()
方法再看看相同的信息 :
# Show the explanation in the Jupyter Notebook
exp.show_in_notebook()
这通过显示每个变量对预测的贡献来显示左侧模型的推理过程。右侧的表格显示了数据点变量的实际值。
对于此示例,模型预测大约为12,实际值为100!虽然最初这个预测可能令人费解,但从解释来看,我们可以看到这不是一个极端的猜测,而是根据数据点的值给出的合理估计。现场EUI相对较高,我们预计能源之星得分较低(因为EUI与得分强烈负相关),这是我们的模型共享的结论。在这种情况下,逻辑是错误的,因为建筑物的满分为100。
当模型出错时可能会令人沮丧,但这些解释有助于我们理解模型错误的原因。此外,根据解释,我们可能想调查为什么尽管有如此高的Site EUI,建筑物仍然有一个完美的分数。也许我们可以在不调查模型的情况下学习一些新的问题。像这样的工具并不完美,但它们在帮助我们理解模型方面还有很长的路要走,这反过来可以让我们做出更好的决策。
任何技术项目经常被忽视的部分是文档和报告。我们可以在世界上做最好的分析,但如果我们没有清楚地传达结果,那么它们就不会有任何影响!
当我们记录数据科学项目时,我们会采用所有版本的数据和代码并对其进行打包,以便我们的项目可以被其他数据科学家复制或构建。重要的是要记住代码的读取频率高于编写代码,并且我们希望确保我们的工作对于其他人和我们自己都是可以理解的,如果我们几个月后再回来的话。这意味着在代码中添加有用的注释并解释您的推理。我发现Jupyter笔记本是一个很好的文档工具,因为它们允许一个接一个地解释和编码。
Jupyter笔记本也可以成为将结果传达给他人的良好平台。使用笔记本扩展,我们可以隐藏最终报告中的代码 ,因为虽然很难相信,但并不是每个人都希望在文档中看到一堆Python代码!
就个人而言,我很简洁地总结了我的工作,因为我想详细介绍所有细节。但是,在您呈现和相应地定制消息时,了解您的受众非常重要。考虑到这一点,这是我在项目中的30秒内容:
最初,我被这个项目作为初创公司的工作筛选“任务”。对于最终报告,他们希望看到我的工作和结论,所以我开发了一个Jupyter笔记本来交。但是,我没有直接转换为Jupyter中的PDF,而是将其转换为Latex .tex
文件,然后我在texStudio中编辑在渲染为最终版本的PDF之前。Jupyter的默认PDF输出具有不错的外观,但只需几分钟的编辑就可以显着改善它。此外,Latex是一个功能强大的文档准备系统,了解基础知识是很好的。
在一天结束时,我们的工作只有它所能做出的决定一样有价值,并且能够呈现结果是一项至关重要的技能。此外,通过正确记录工作,我们允许其他人重现我们的结果,给我们反馈,以便我们成为更好的数据科学家,并在我们未来的工作基础上继续发展。
在这一系列帖子中,我们已经完成了一个完整的端到端机器学习项目。我们首先清理数据,进入模型构建,最后研究如何解释机器学习模型。提醒一下,机器学习项目的一般结构如下:
虽然确切的步骤因项目而异,并且机器学习通常是迭代而非线性过程,但本指南应该在您处理未来的机器学习项目时为您提供良好的服务。我希望这个系列让你有信心能够实现自己的机器学习解决方案,但请记住,我们都不是自己做的!如果您需要任何帮助,有许多令人难以置信的支持性社区,您可以在那里寻求建议。
一如既往,我欢迎反馈和讨论,可以在Twitter @koehrsen_will上联系。
原文:https://towardsdatascience.com/a-complete-machine-learning-walk-through-in-python-part-three-388834e8804b