来源 磐创AI
作者 磐石001
编辑 zenRRan
【导读】本文是一个完整的机器学习项目在python中的演练系列。详细介绍了超参数调整与模型在测试集上的评估两个步骤。
大家往往会选择一本数据科学相关书籍或者完成一门在线课程来学习和掌握机器学习。但是,实际情况往往是,学完之后反而并不清楚这些技术怎样才能被用在实际的项目流程中。就像你的脑海中已经有了一块块”拼图“(机器学习技术),你却不知道如何讲他们拼起来应用在实际的项目中。如果你也遇见过同样的问题,那么这篇文章应该是你想要的。本系列文章将介绍一个针对真实世界实际数据集的完整机器学习解决方案,让你了解所有部分如何结合在一起。
本系列文章按照一般机器学习工作流程逐步进行:
1. 数据清洗与格式处理
2. 探索性数据分析
3. 特征工程和特征选取
4. 机器学习模型性能指标评估
5. 微调最佳模型(超参数)
6. 在测试集上评估最佳模型
7. 解释模型结果
8. 总结分析
通过完成所有流程,我们将看到每个步骤之间是怎么联系起来的,以及如何在Python中专门实现每个部分。该项目在GitHub上可以找到,附实现过程。本篇文章将详细介绍第五-六个步骤,剩下的内容将在后面的文章中介绍。前四个步骤详见:数据清洗与格式处理、探索性数据分析、特征工程和特征选取、机器学习模型性能指标评估。
随机搜索与交叉验证
我们通过随机搜索与交叉验证的方法实现超参数调整:
我们使用随机搜索(Randam Search:https://en.wikipedia.org/wiki/Hyperparameter_optimization#Random_search)来为我们的模型选择最佳超参数。我们定义一个网格(grid)后采用的是随机抽样的方式(random search)选取不同的超参数组合而不是像网格搜索尝试每一个超参数组合。(值得一提的是,使用随机搜索方法选择超参数的表现几乎和网格搜索一样,同时大大缩短了搜索时间。)
我们使用交叉验证(Cross Validation:https://www.openml.org/a/estimation-procedures/1)的方法来评估所选超参数组合表现。这里我们选择使用K-Fold交叉验证,而不是将训练集直接分成单独的训练集和验证集,那样会减少我们可以使用的训练数据量。在k-折交叉验证中,原始样本被随机划分为k等份子样本。在k份子样本中,保留一个子样本作为测试模型的验证集,剩下的k-1子样本用作模型训练。重复进行k次(the folds)交叉验证过程,每一个子样本都作为验证数据被使用一次。然后,这些折叠的k结果可以被平均(或其他组合)产生一个单一的估计。最后,我们将K次迭代的平均误差作为最终的性能指标。
K = 5的K-fold交叉验证过程如下所示:
使用随机搜索与交叉验证验证选择最优超参数组合的步骤为:
1. 设置一个超参数的网格(grid)用于评估
2. 随机抽样一组超参数
3. 用选定的超参数组合创建一个模型
4. 使用K-fold交叉验证评估模型
5. 确定表现最佳的超参数组合
当然,我们实际上是调用Scikit-Learn工具库中封装好的RandomizedSearchCV函数来实现上述操作的。
背景介绍:梯度提升法(GBM)
我们先简单介绍一下我们将要使用的梯度提升回归(Gradient Boosted Regression)模型。梯度提升是一种用于回归和分类问题的机器学习技术,该技术以弱预测模型(通常为决策树)的集合的形式产生预测模型。本项目中使用的也是决策树。虽然诸如随机森林之类的集成算法(https://machinelearningmastery.com/bagging-and-random-forest-ensemble-algorithms-for-machine-learning/)是通过并行地训练弱“学习者”并分别“投票”进行预测,但像梯度提升这样的增强方法(boosting method)则是通过依次训练“学习者”,并且每个学习者“集中”学习前面“学习者”所不擅长的部分。
增强方法(boosting method)近年来越来越流行,并且频繁地在各种机器学习竞赛中名列前茅。梯度提升法(GBM)是使用梯度下降来优化代价函数的一种特定实现。具体来说,它通过基于残差顺序训练“学习者”来实现。另外,使用scikit-learn工具库来实现Gradient Boosting的效率通常被认为是低于XGBoost 等其他库的。但是,它对于我们本项目所用到的小数据集来说是足够的,并且相当准确。
超参数调整
梯度提升回归模型(Gradient Boosted Regressor)有多项超参数,具体可以查看Scikit-Learn官方文档以了解详细信息。本项目中将优化以下超参数:
loss:损失函数的最小值设定
n_estimators:所使用的弱“学习者”(决策树)的数量
max_depth:决策树的最大深度
min_samples_leaf:决策树的叶节点所需的最小示例个数
min_samples_split:分割决策树节点所需的最小示例个数
max_features:最多用于分割节点的特征个数
完全弄懂这些超参数之间的相互作用是比较难的,所以最佳的方式就是去尝试多种超参数组合。
在下面的代码中,我们构建一个超参数网格,创建一个RandomizedSearchCV对象,并使用含有超过25种不同的超参数组合的4折交叉验证来执行超参数搜索:
执行搜索后,我们可以“核查”RandomizedSearchCV对象来找到最佳模型:
然后,我们还可以再次进行网格搜索,通过选择接近这些最优值的网格参数来执行网格搜索。但是,进一步调整不太可能显著地改善我们的模型。通常来说,合适的特征工程对模型性能的影响要比广泛的超参数调整更大。机器学习的收益递减规律(http://www.picnet.com.au/blogs/guido/2018/04/13/diminishing-returns-machine-learning-projects/):特征工程可以帮助你实现较大的提升,而超参数调整通常只会带来很小的收益。
我们可以尝试单一改变estimators(决策树)的数量,来看下模型表现。我们可以通过可视化的方法直观的看到此时模型表现的变化。具体结果如下:
随着模型使用的树的个数增加,训练集误差和测试集误差都会减少。但是,训练集误差比测试集误差下降得快很多。同时也可以直观的推测出来这样的模型存在过拟合现象:它在训练集上表现非常好,但在测试集上无法达到相同的性能。
这可能与我们所期待的不一样,毕竟我们可以看到:它在训练集上表现有所提升。但是,对比训练集上与测试集上的表现的显著差距表明模型存在过拟合现象。通常来说,我们可以通过获取更多训练数据来解决过拟合问题,或者通过调整超参数降低模型的复杂度来解决。对于本项目,我们将保持原先选择的超参数组合,不再对estimators(决策树)的数量进行调整。有兴趣可以再多去尝试一下。
对于最终模型,我们设定estimators=800--交叉验证中最低误差时的超参数值。接下来,让我们测试该模型在测试集上的表现。
在测试集上评估最佳模型
在之前的步骤中我们已经确保了模型训练时不接触到测试集。因此,我们可以根据模型在测试集上的表现准确客观的评估模型的最终性能。
在测试集上进行预测并评价性能是相对直接的方式。这里,我们比较了使用默认超参数的梯度提升回归模型与微调后的模型的性能:
从上面可以看出超参数调整将模型表现提高了约10%。某些情况下10%可能算是一个巨大的改进了,但是在一个大的时间成本前提下。
我们也可以使用%timeit命令来比较一下模型训练花费的时间。首先是默认配置下的模型:
1秒的训练时间似乎是合理的。最终调整超参数后模型并不是那么快:
这也说明了机器学习的一个基本特性:它是一种“权衡游戏”。我们需要不断地平衡准确性与可解释性、偏差与方差、准确性与运行时间等表现。正确的混合将最终取决于问题。本项目中,相对而言运行时间增加12倍是恐怖的,但绝对而言又不是显著(增加了十几秒)。
我们已经得到了最终的测试集预测值,接下来我们就可以评估他们是否与真实值有着明显的偏差了。上边是预测值和实际值的密度图,下边是残差直方图:
从上面的两张图可以看出:虽然模型预测值得密度峰值接近中值在(66)附近,而非真实值的密度峰值(接近100),但模型预测值密度分布大致接近实际值密度分布。尽管我们可以看到一些模型预测值远低于真值的较大的负值,残差几乎是符合正态分布的。我们将在下一篇文章中深入探讨分析模型的结果。
结论
在本篇文章中,我们介绍了机器学习工作流程中的以下几个步骤:
使用随机网格搜索和交叉验证进行超参数调整
在测试集上评估最佳模型
本次工作的结果表明,机器学习适用于本次任务-使用能源数据建立一个模型,可以预测建筑物的能源之星评分(ENERGY STAR Score)。使用梯度提升回归模型能够在测试集上的表现达到9.1分左右。此外,超参数调整可以在增加时间成本的情况下显著提高模型性能。虽然从实际表现来看我们的模型预测是准确的,但是我们也许想要或者应该知道模型可以做出来这种预测的原因和这些表现在针对我们的任务方面,实际上告诉了我们什么。这些问题将在下一篇文章中详细探讨。
推荐阅读:
TreeLSTM Sentiment Classification
有什么AI方面不懂的问题,可以在公众号右下角加我,我们一起探讨哈
欢迎关注深度学习自然语言处理公众号,我会每天更新自己在机器学习,深度学习,NLP,linux,python以及各种数学知识学习的一点一滴!再小的人也有自己的品牌!期待和你一起进步!