转自:第一次参加Kaggle拿银总结python
做者:ScarletPangit
个人比赛代码已经放到github --> Kaggle-Rental-Listing-Inquireiesgithub
在这篇博客开始以前,我必须感谢导师给我提供服务器资源,@Fenix Lin学长从他自身经验出发耐心地为我解答一些困惑,素未谋面的@Wille学长的一篇很是优秀的博文如何在Kaggle 首战中进入前 10%帮助入门,以及广大Kaggler的无私分享,我确实在Kaggle举行的这场Rental Listing Inquiries比赛中收益良多,得到了很多知识。做为第一次参加比赛,得到了Top 5%的成绩已经让我很是满意了。算法
这篇文章的目的是介绍本身第一次参加Kaggle的心历路程,总结遇到的问题和解决思路,为本身之后参赛作准备。同时这篇文章也能够做为一个初学者的入门Kaggle的参考,若是想要在入门kaggle的时候拿到一个好的名次,能够参考个人一些方法实践。本文能够随意转载,但务必注明出处和做者, 而且发邮件myscarlet@sina.com通知与我。json
从刚接触machine learning的时候就有在学长口中、博文中、社区中听到过它的名字,当初我对它的理解还比较浮浅,只是知道是一个数据比赛的平台,有不少公开的数据集,好比大二寒假作的第一个ML练手项目就是一个用word2vec进行情感分析的Tutorial级比赛Bag of Words Meets Bags of Popcorn,而且写了一个Research report。这过程当中只用到了教程和数据集。数组
后来从新接触Kaggle才发现,它的价值所在是各类高质量的比赛,以及每场比赛下面的社区讨论(包括比赛中的分享、答疑,和比赛后的top solution分享),所以若是想要得到关于数据挖掘,机器学习实战经验的话,打一场kaggle比赛绝对是一个高回报的工做。服务器
由于仍是学生,不知道kaggle比赛到底是否会为本身求职工做有举足轻重的影响,可是单从Kaggle被google收购一点来看,它会在行业内一点点提高影响力的。app
一场比赛一般持续2~3个月,在比赛的简介中会有规则、评价指标(好比这场比赛为mlogloss),时间轴等信息。另外还有数据区、Kernel区(一些Kagglers在kaggle上成功运行的ipython notebook或者代码),Discussion(讨论区),LeaderBoard(LB,分为公开的用户提交能够显示结果的榜单,和非公开的比赛结束后肯定最终排名的榜单),固然还有提交区(通常为必定格式的csv文件提交)。dom
另外就是奖牌问题,通常来说在1000+量级的比赛中,top 10+ 0.2%为金牌,5%为银牌,10%为铜牌,这里有更具体的奖牌发放方式。机器学习
我的认为,若是想在入门Kaggle阶段就得到一个好的成绩的话,关注discussion是很是重要的,会有不少人分享本身的思路、困惑甚至代码和结果。有时候,一场比赛中比较关键的feature可能就是从讨论区中得到的,好比Two Sigma Connect: Rental Listing Inquiries这场比赛的最后几天,我觉得本身特征提取得已经差很少了,没有任何idea了的时候,一个来自讨论区magic feature从天而降,从而使得榜单大变,一晚上之间个人排名从70多掉到了120多。
首先拿到一个比赛题目,你须要下决心是否参加这个比赛,对我我的而言最重要的无非两点 1. 是否是有rank point,也就是奖牌, 2. 数据集是否令我满意。 所以对数据的探索首先须要你从Kaggle网站上查看数据的简介,并把数据下载下来。好比Rental Listing Inquiries包含了80G的图片数据,和几份json文件。
咱们将下载下来的train.csv用python pandas 打开,取少许样本进行观测
1
import pandas as pd
2
train = pd.read_json("input/train.json")
3
train.sample(2)
抛开图片数据不谈,咱们能够看到给定的数据里包含多种多样的feature:
数值型feature
高势集类别(High Categorical)型feature
时间型feature
文本feature
稀疏特征集feature
id型feature
咱们看到有这么多不一样的feature,一看几乎每一个feature都有深度挖掘的价值,况且还有80G的图片feature,无疑是让人兴奋的,所以我选择了这个比赛,由于它的数据集的确让我舒心。
另一定要搞明白的一件事是这场比赛是一个预测比赛仍是分类比赛,咱们能看到最重要预测的是用户的interest_level,分为low,medium,high三级,很显然是个分类问题了。
接下来的是就是对数据进行可视化探索了,我由于是初期参赛的,因此本身作了一份可视化方案,从中能够发现不少有趣的分布、outlier等。在这里推荐三份在比赛中分享出来的比较好的EDA:
有了以前数据探索的基础,咱们很快能提取到一些基础的feature,好比数值型feature进行简单的加减乘除,类别型feature用id顺序编码,稀疏特征集用one-hot编码,时间特征生成年、月、日等。将一些基础的特征转换成相应的输入input_X矩阵后,再将label也转换成数值形式:
1
target_num_map = {'high':0, 'medium':1, 'low':2}
2
3
y = data["interest_level"].apply(lambda x: target_num_map[x])
懂机器学习的人都知道,有了这些(X,y)对,咱们就能够进行模型训练了。
咱们用cross-validation(CV)的成绩来判断咱们本地的实验结果,也就是将(X,y)训练集拆分红训练和验证集,训练相应分类器对训练集拟合,再在验证集上进行loss的计算来评估模型的好坏。
常见的分类器有Logistic Classifier,SVM, NN softmax,Random Forest等。可是在kaggle上用的比较多的仍是一些封装好的库,如sklearn里的各类分类器,大名鼎鼎的xgboost,最近崭露头角的lightgbm等。
早就听闻xgboost的好用,我就直接在电脑上pip了xgboost,做为我接下来一两个月以来的核心分类器。将原先的(X,y)对中的训练部分输入xgboost进行fit,而后用验证部分predict计算mlogloss。
至此为止,比赛初期的第一个模型就已经训练好了。
训练完一个比较好的模型以后,就能够对测试集进行预测了,首先将训练集(X,y)对输入xgboost中从新训练,而后对测试集也像对训练集同样进行特征处理,预测出来的结果按照比赛指定的格式保存到文件(在这里仍是建议用pandas),便可提交。
第一次提交意味着你正式进入比赛,提交的结果会在Leader Board上显示你当前的排名,固然这个排名只起到参考做用,由于你提交上去的大部分结果kaggle都没有进行评估。
在一系列的初始操做之后,你就要踏上FE的漫漫长征了。本人断断续续在数据清洗、特征提取上作了约两个多月,在比赛最后一段时间模型融合完毕后还在继续地寻找、测试新的特征。后期评论区中magic feature的出现,让每一个人的预测结果好了0.01~0.02个点。不得不说,特征工程才是Kaggle比赛获胜的关键所在,所以初学者耗费大量精力在这上面是没错的。而本博文也是重点想讲一下本身发现新特征的一些心历路程。
在对一些基础的特征进行生成以后,我开始了漫长地测试特征的长征路,测试的思路我后来发现并非很好,由于是经过新增长一个或几个feature,若是cv分数上去了,就增长这个feature,若是cv分数没有上去,就舍弃这个feature,也就是至关于贪心验证。这样作的弊处在于,若是以前被舍弃的feature和以后被舍弃的feature联合在一块儿才会有正面影响,就至关于你错过了两个比较好的feature。所以特征的选择和联合显得很是关键。
在比赛阶段,花费大量力气去建立一个feature,到头来却选择放弃这个feature的事情很常见,我后期的特征有不少是新添加的,旧有的一些特征并无保留。接下来就让我总结一下这场比赛中有哪些“好”的feature,为之后的比赛提供灵感和经验。
这个乍一看仿佛没有道理可言,可是事实上却能挖掘出几个feature之间的内在联系,好比这场比赛中提供了bathrooms和bedrooms的数量,以及价格price,合租用户可能会更关心每一个卧室的价格,即bathrooms / price,也会关心是否是每一个房间都会有一个卫生间bathrooms / price ,这些数值型feature之间经过算数的手段创建了联系,从而挖掘出了feature内部的一些价值,分数也就相应地上去了。
什么是High Categorical的特征呢?一个简单的例子就是邮编,有100个城市就会有好几百个邮编,有些房子坐落在同一个邮编下面。很显然随着邮编的数量增多,若是用简单的one-hot编码显然效果不太好,所以有人就用一些统计学思想(经验贝叶斯)将这些类别数据进行一个map,获得的结果是数值数据。在这场比赛中有人分享了一篇paper里面就提到了具体的算法。详细就不仔细讲了,用了这个encoding以后,的确效果提高了不少。那么这场比赛中哪些数据能够进行这样的encoding呢,只要知足下面几点:1. 会重复,2. 根据相同的值分组会分出超过必定数量(好比100)的组。也就是说building_id, manager_id, street_address, display_address都能进行这样的encoding,而取舍就由最后的实验来决定了。
针对于时间数据来说,提取年、月、日、星期等可能仍是不够的,有另一些points能够去思考,用户的兴趣跟发布时间的久远是否有关系?能够构造以下的feature来进行测试:
1
data["latest"] = (data["created"]- data["created"].min())
2
3
data["passed"] = (data["created"].max()- data["created"])
能够看到latest指的是从有数据开始到该房建立为止一共过去了多少时间,而passed则是该房记录建立为止到最后有记录的时候一共过去了多少时间。
另外针对于时间特征还能够用可视化的方式来与其余特征创建联系,好比咱们观察listing_id与时间变化到底有怎样的联系,可以绘制出以下的图来:
可能简单的相除就能得到很好的结果
想到地理位置,就会想到聚类,一个简单的方式将每一个房子划分到同一块区域中去;除了聚类之外,算出几个中心点坐标,计算曼哈顿距离或者欧式距离可能都会有神奇的效果。
实话说本身是看中此次比赛中有文本数据才参加的,所以在文本挖掘中作了很大的努力,好比提取关键词、情感分析、word embedding聚类之类都尝试过,但效果都不是很好, 对于文本的特征的建议仍是去找出一些除了停用词之外的高频词汇,寻找与这个房屋分类问题的具体联系。
除了最后爆料出来的magic feature(后文会提到)之外,我只用了一个房子有几个照片这个信息。讨论区中都说对于图片特征用CNN提取、简单特征提取之类的效果都不是很好。
其实就至关于一系列标签,不一样标签的个数也是挺多的,本次比赛我只是简单地采用了counterEncoding的方式进行one-hot编码。值得一提的是,有些标签是能够合并的,好比cat allowed 和 dog allowed能够合并成为 pet allowed,我在这场比赛中手工地合并了一些feature数据,最终结果略微有所提高。
在树结构的分类器好比randomforest、xgboost中最后可以对每一个特征在分类上面的重要程度进行一个评估。这时候若是已经选定了一些feature进行训练了以后,查看feature importance的反馈是很是重要的,好比本场比赛制胜的关键是运用manager_id这个feature,而它的feature importance反馈结果也是很是高。经过对重要特征的从新再提取特征,可以发现不少有意思的新特征,这才是用FE打好一场比赛的关键所在。
下面列出了一些比赛结束后获胜者分享的idea,这大概是我这场比赛中获益最大的一块地方了。
主要是针对manager_id生成了很是多的feature。如根据不一样时间出现的manager_id判断一个manager是否活跃(manager与time进行group,manager掌管有几个不一样的房子(manager与building_id进行group)、平均天天处理多少房子(比值)、活动范围(同个manager掌管的房子的最大最小经纬度group),经理的开价程度(选择bedroom和bathroom做为房子型号指标,把相同房型的均价来衡量经理对于全部房子的开价程度),对经纬度进行聚类再计算每一个区域中有多少个manager竞争、一个manager同时经营几个区域、在同个区域中manager的开价水平等。从Top 1选手分享的代码来看,其对于manager的各类处理的确是让人大开眼界。
从更为经验老道的选手给出了一些特征提取建议。其中有一类被做者称为"Likelihood Features",他对High Cardinal Categorical的特征用了一些额外的条件几率来计算其似然值,如p(y|manager_id, bathrooms)等,而且进行了点积操做来计算出一个合适的encoding值(相似于先前讨论区中出现的manager_skills,同时为了防止过拟合对这些似然估计出来的feature建立了2层嵌套。另外还有一种对我启发比较大的feature是对description出现频率最高的15k单词进行一个one-hot深度xgboost训练,将这个训练出来模型的预测结果做为description的encoding。
其FE的第一部分给出了group的一套方案,相似于我本身FE中的group方法。第二部分使用了magic feature相关的feature,方法与第一部分相似
没有细说,可是列出了一个feature name的详单,但愿之后没有idea的时候能从中找到一些insight
KazAnova无疑是这场比赛中的明星选手,他分享了对初学者模型融合比较关键的Stack-Net,以及对最后榜单变更起到决定性做用的magic feature。几乎全部在榜上的Kagglers都要向他致敬。同时在FE这一块,他注意到了数据集中存在不少相似的数据(仅仅在价格上有区别),所以他创建了不一样的group,并在这些group间建立了不少aggregated features,好比最高的price,平均price等
用到了基于高势集类别数据的group的一些统计量。
也是用了不少基于manager_id group的统计feature。
模型调参的话,可以在FE完以后为你提高0.001~0.002分数,所以如何为咱们的分类器,好比xgboost选择好正确的参数是很是关键的。
比较经常使用的是进行Grid Search,从你的输入组合中暴力地搜索cv结果最优的组合。我通常会设定一个learning rate,而后尝试不一样的参数组合,取最优值,由于训search的代价比较高,最好选择必定范围,好比你事先cv的时候知道estimater会在700~1000的范围内,那就不要search这个范围之外的值了。
若是你没有idea了的话,就模型融合吧!模型融合是可以快速提升比赛成绩的捷径,如今的比赛几乎没有人不用到这个技巧,一般获胜者会对不少不少模型进行融合,而且会选择不一样的模型融合的方式。这里有一篇很是好的模型融合解析博文,相信每一个看过它的人都会对模型融合有一个清楚的了解
本次比赛中我使用了两种模型融合方式,一种是Averaging,一种是Stacking。
先来讲说Stacking,由于这场比赛一名贡献比较大的选手分享了一个叫StackNet的库,做为新手我就直接用了。首先我用个人xgboost cv集交叉预测出结果做为feature的一部分放到train data中,再对test data进行预测的结果做为feature的一部分放到test data中,再在第二层上选择了Logistic Classifer,GradientBoostingClassifer,AdaBoostClassifer,NNSoft-maxClassfier,RandomForestClassifer等进行交叉预测,第三层选取了一个randomForest做为最后的结果训练和预测。Stacking主要增多了模型的diversity,使个人成绩上升了至少0.003的量级。
而后是Averaging,以前提到过Stacking须要交叉预测,我就选取了10组随机种子分别对训练集进行10-kfold交叉预测取平均,以及每一个flod训练预测的时候我都对个人xgboost选取5个随机种子取平均。也就是说,在第一层Stacking的CV集交叉预测时我总共训练了500个模型进行平均。分数的提高大约在0.002左右。
直到比赛结束看了排名靠前的选手的模型融合后,才发现本身对于模型融合只是作了一点微小的工做,提高空间还很是大。详情能够看FE部分分享的solution连接。
在这场比赛中有一名在一开始的两个月一直遥遥领先的选手爆出这个比赛有个magic feature,你们陷入了疯狂找这个feature的过程当中,直到那位分享了StackNet的选手分享出了这个magic feature:80G图片数据每一个文件夹的建立时间,因而榜单大变,我一觉醒来后发现本身掉了不少就发现到了不对劲,便迅速加入到这个magic feature疯狂屠榜的大军中,从这里能够看见,一个信息量巨大的feature若是被发现的话,对比赛成绩会带来多么大的影响。
有一些group的feature可以起到很是重要的做用,详细见我比赛后发表的一个小样例discussion topic。可是必定要防止过拟合。
这篇博文还有一些关键的点没有涉及到,好比数据的清洗,有些数据在记录中彷佛是不一样的,可是意思是同样的,就应该归位同一个类别,还有就是清除一些outlier等。
对这个比赛的top solution总结得仍是没到位,基本没有coding实现他们的idea过。因为课程压力比较大,等到时候空了的时候再好好整理。
另外还有就是须要锲而不舍地打这个比赛,由于你觉得你idea都没有了,模型调参、融合完毕了的时候,可能你们都找出了另外一个"magic feature",轻松地把你挤出奖牌的范围内了。
最后,Kaggle is fun!