介绍
我最近偶然发现了雷切尔·托马斯撰写的描述博客各种优点的一篇文章,并有所启发。
我将在这篇文章中分享我参加的第一场Kaggle竞赛的经历。我因此快速学完了fast.ai的机器学习的网络课程,我希望将这门课程所获得的知识运用到这次kaggle竞赛中。
http://course.fast.ai/ml.html
概述
我们将采用Kaggle竞赛进行一次房价预测 。
描述
对于已完成机器学习在线课程的数据科学的学生来说,这是一场完美的竞赛,并希望在参加这个具有特色的竞赛之前扩展他们的技能。
https://www.kaggle.com/c/house-prices-advanced-regression-techniques
问题很简单,我们需要预测爱荷华州艾姆斯市(Ames)的居民住宅价格(因变量)。我们提供了79个解释特征(自变量)来描述住宅的各方面。
我们将使用随机森林来解决这个问题,这是一个决策树的集合。随机森林构建多个决策树,并将它们合并在一起以获得更加准确和稳定的预测。 查看数据
这些专栏和栏目中的大部分对我们来说没有多大意义,但是kaggle在竞赛的数据部分,我们提供了一些简短的描述。你可以进一步查找data_description.txt资源,以获取每列及其数据字段的详细说明。
评估指标
评估指标是RMSLE(均方根对数误差),因此在这种情况下获取因变量(即SalePrice)的日志是有意义的。
数据解释
你可能已经注意到"Alley"列的前六行都是NaN值(描述了相应行的缺失数据)。因此,让我们找出所有特征的整个数据集中缺失值的百分比。
缺少数据的列
我们有5个特征,Nan%大于50。很可能这些特征不会为我们提供有关数据集的任何有用的见解,所以我们现在可以考虑删除它们,但我们将很快看到特征重要性无论如何,让我们暂时保留它们,让随机森林为我们做出这个决定。
数据清理
为了将此数据集提供给随机森林,我们必须将所有非数值数据转换为数值数据。所有非数字数据列都代表两种类型的分类数据:
序数(Ordinal): 类别的顺序很重要。
名义(Nominal): 顺序无关紧要。
有两种方法可以将这些转换为数字:
标签编码: 用整数标签替换类别,范围从0到(类别数-1)。它使得分类数据按顺序排列。
One-Hot编码: 将具有分类数据的一列拆分为多列(等于类别数)。数字由1和0替换,具体取决于哪个列具有什么值。
有关Label vs One-hot编码的更多信息,可以查看这篇文章。 https://medium.com/@contactsunny/label-encoder-vs-one-hot-encoder-in-machine-learning-3fc273365621
无论如何,大多数列都是具有顺序的,所以我们将对这个数据集使用标签编码(稍后尝试了One-Hot编码,它将我的RMSLE增加了0.01)。"train_cats"和"proc_df"取自Github上的fastai repo。如果需要,你可以查看源代码和文档。
https://github.com/fastai/fastai/blob/master/old/fastai/structured.py
我们还用相应列的中位数替换了数值数据列的缺失值,并添加了{name} _na列 它指定数据是否丢失。
查看这些数据,我发现没有任何特征能够告诉住宅的房龄是多少,所以我将其添加到另一个可以提供住宅总居住面积的特征中。
拆分训练集和验证集
构建随机森林之前的最后一件事是将我们的数据集划分为两部分:训练集和验证集。可能机器学习中最重要的想法是拥有单独的训练和验证数据集。作为动机,假设你不划分数据,而是使用所有数据。假设你有很多参数:
对于最右侧的模型,图示数据点的误差最小(蓝色曲线几乎完美地穿过红点),但它不是最佳选择。这是为什么?如果要收集一些新的数据点,它们很可能会更接近中间图中的曲线。
将原始数据集拆分为训练集和验证集
这说明了如何使用我们的所有数据导致过度拟合。验证集有助于诊断此问题。验证集上模型的得分将代表你的模型在现实世界中的表现,以及之前从未见过的数据。因此,验证集只是数据集的一个子集,它将告诉你模型的通用化程度。
训练模型
我们终于准备建立随机森林了。将使用Parfit来优化我们的超参数
最好的超参数是:
min_samples_leaf:1,
max_features:0.4,
使用随机森林的优化参数,我们在验证集上得到了0.1258的RMSLE。
可视化随机森林
让我们从随机森林中的装袋中看一棵决策树(估算器,Estimator)。
随机森林中的一棵决策树
该决策树已经可视化到深度=2。决策树的每个节点将我们的数据分成两半,这样MSE的加权平均值是最好的。MSE随着进一步下降而减少,因为树基本上为每个节点找到了最佳分割点。
决策树首先在TotalLivingSf的基础上划分数据,然后根据AgeSold和TotalLivingSf分别对其子进行划分,依此类推。
我们在随机森林中有300个估算器(estimators),我们采用所有这些估算器的平均值来进行预测。
特征选择
接下来,我们将深入研究特征的重要性,以删除冗余功能,并找出哪些功能有助于深入了解我们的数据。
函数'rf_feat_importance'将返回一个包含列名及其各自特征重要性的pandas数据帧。我们使用'plot_fi'函数绘制一个水平条形图,描绘了所有列的特征重要性。
特征重要性条形图
该图显示特征的重要性以指数方式递减,因此不需要考虑几乎不提供数据集的洞察力的特征。我们将删除imp<0.005的所有特征,然后在新数据上重新训练我们的模型并检查RMSLE。
此后的RMSLE为0.12506,比之前的0.1258略有改善。特征的数量从79减少到25。一般来说,删除冗余列不应该使其更糟。如果它使RMSLE变得更糟,它们毕竟不是多余的。删除冗余列可能会使我们的模型更好一些。如果你考虑如何构建这些树,当算法决定分割什么时,需要考虑的事情就更少了。
采用更少的数据创建一棵更好的树的可能性很小,但是它不会改变结果。这将让我们关注最重要的特征。
基于相关的特征选择
现在我们将利用Spearman秩相关系数找到特征之间的相关性。如果两个特征为我们提供了相同的洞察力,那么去掉其中的一个是明智的,因为它基本上是多余的。这种技术有助于找到多个特征之间的联系。
我们将绘制一个树状图,它是一种层次聚类。从scipy.cluster导入层次结构为hc
https://en.wikipedia.org/wiki/Dendrogram
树状图显示所有特征之间的相关性
两个特征越快碰撞,它们就越相关。基于此,我们可以看到五对彼此高度相关的特征。
这些是:
1.)GrLivArea和TotalLivingSF。
2.)GarageArea和GarageCars。
3.)1stFlrSF和TotalBsmtSF。
4.)GarageYrBlt和YearBuilt。
5.)FireplaceQu和Fireplaces。
每对特征中的两个特征都为我们提供了类似的洞察力,因此从每对特征中删除一个特征是明智之举。但是这两者中的哪一个要被删除呢?让我们来看看。
现在,为了找出要删除的两个特征中的哪一个(在每对特征中),首先,我计算了一个基线分数(包括所有25个特征),然后开始逐个删除这10个特征。删除每个特征后,我们将再次计算得分(在重新训练模型之后)并将其与基线进行比较,以了解该特定特征的移除如何影响我们的得分。
我们的基线分数为0.12506。
现在我们将开始删除这10个特征并重新计算得分。
以下代码的每个输出在重新训练新数据模型后告诉RMSLE。第一个令牌告诉我们删除的功能(或列),第二个令牌在从数据中删除该特定功能后告诉我们RMSLE。
我们可以看到删除了GrLivArea、TotalBsmtSF、GarageYrBlt和GarageArea,减少了我们的错误。因此,我们可以删除所有这些冗余特征。
在删除所有冗余特征之后,我们的RMSLE从0.1258减少到0.12341。
我们现在只剩下从79开始的21个功能。这是我们的最终模式。
我们现在应该合并训练集和验证集,并在这个合并的数据集上重新训练我们的模型。
提交预测现在我们将为测试集生成预测,但在此之前我们需要在测试集上进行类似的转换。
这个模型在Kaggle测试集上给出了0.12480的分数,相当于LeaderBoard中4052的排名中1338,这使我们排在前34%。
结束语
我目前正在学习第二种类型的决策树集合,即Boosting。在本文的后面,我将介绍一个围绕梯度增强回归(gradientBoostingRegressor)而不是随机森林(Random.)的实现,并了解它如何影响我们的特性导入和最终得分。
我要感谢Jeremy Howard和Rachel Thomas;制作这些与众不同的大型开放式网络课程(MOOC)。我建议大家看看fast.ai,他们还有深度学习和计算线性代数课程以及机器学习的相关课程。