数据弱鸡的天池观光游(一)

作者:字节
链接:https://zhuanlan.zhihu.com/p/23845169
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

国庆节前后,公司小伙伴给我推荐了个传说中的天池机器学习算法大赛(赛题链接:机场客流量的时空分布预测),说要参加下试试。作为一名名声在外的机器学习叶公好龙宗师,我内心一开始是拒绝的……妈蛋我也就上了几个课会调用调用MLlib的水平啊,这怎么突然就要来真枪实弹了,还以公司名义组了个队,这有点虚……正好那阵子业务开发也比较忙,就一直搁置着……

转眼到了10月中旬,正好有个下午无心干活,又想起了这个比赛,反正新手嘛,谁不是在被虐中成长起来的,要不就来天池划个水试试吧。说干就干,下载了数据,起了个Jupyter notebook,开始……学习pandas……

虽然之前没参加过比赛,不过上过几门课还是了解一些大致的流程。首先看下比赛提供的原始数据,主要就是5张表:

  • 机场中700多个WIFI AP点每分钟的详细连接数。这个也是最后需要预测的值。初赛比较简单,只需要预测某一天下午15-18点之间每个AP点每10分钟的平均连接数,总共大概是13590个预测值。
  • 机场每天的航班排班表,其中有航班号,预定起飞时间和实际起飞时间。里面有不少缺失值。
  • 机场所有登记口和机场区域的关联表。WIFI AP的Tag上有机场区域信息,如E1, W1, T1, EC之类,而航班表里都是登机口比如B225,这个表就是用来做关联的。
  • 机场每天的乘客checkin记录表,包括航班号,起飞时间和checkin时间。根据我自己坐飞机的经验,这个应该指的是值机?感觉值机时人不一定要在机场,而且数据本身也有很多缺失。
  • 机场每天的乘客安检记录表,同样包含了航班号,安检时间。这个感觉会靠谱一些,虽然同样数据也有很多缺失。两张乘客表里的乘客ID也都有提供,不过两个表用的ID体系不同,无法关联。试着distinct了一下发现ID没有重复的,也就是说无法通过ID来确定某个乘客,基本就是无用的信息。

有了原始数据,就开始搞探索性分析。嗯,看看咋导入数据,要读取csv嘛……pandas.read_csv就可以了!果然简单!(省略各种pandas库方法的各种google搜索学习……)然后查看下数据质量啦(有没有缺失值异常值),画画图看看有啥分布规律啦,看看统计关联度啦等等……这块是我的弱项,可能因为本身数学功底比较差,对于画图也不是很有sense,所以也没有什么特别的发现。第一天基本就在pandas和matplotlib的基本使用学习中度过了。晚上试着跑了个平均值,作为第一次预测结果提交了。

10月15号,第一次结果揭晓,竟然排到了200名以内!(当时总参赛队伍有2000多)简直不敢相信……搞个平均值就能进10%,这比赛真是对新手太友好了……

10月16号,继续学习pandas,做了些其它的分析比如乘客一般会在预定起飞时间前多久来机场过安检,飞机的平均延误情况如何,机场每天的航班排布是不是比较接近,然后略微改进了下简单的平均,做了下花式加权平均,进行了第二次提交。然后就冲到了100名附近。感觉自己势不可挡木哈哈……

1480397905-8032-0d03926217a4a2d6d978a63648-b10月17号,既然平均效果都这么好了,那要不试试ARIMA之类的经典时序预测?又学了下statsmodels库,看了下ARIMA模型需要序列stationary……好吧那做下一阶差分。然后模型拟合需要设置auto-regressive和moving-average的参数,这有点懵逼……随便瞎猜了下可能的回归周期,发现这个跑起来又慢效果也不怎么好,可能更适合长期粗粒度时间序列的预测吧……所以也就暂时没有采用。不过移动平滑这个好像是个不错的主意,继续加入到原先的加权平均模型中,做了第三次提交,貌似名次没什么变化……

10月18号,这天好像是换了数据,初赛只剩下最后6次提交了……这天花了非常多的时间,看了好些Kaggle winner’s solution,开始上模型了!(后来才知道我之前用的那些平均之类的方法被大家称之为“规则”,很多情况下规则方法就可以达到不错的成绩了)添加了航班数量的feature,加上之前的时间点平均,滑动窗口,一阶差分等等,用sklearn搞了个GBRT模型!离线验证下效果也不错,信心满满进行提交!果然成绩一出,冲到了第6名……当时的感觉就是,一个能打的都没有啊!(摇手指

10月19号,这天继续疯狂地学习着各种比赛经验,以一种王者的姿态哈哈哈,把玩我的模型们。唔,原来随机森林这种bagging为基础的ensemble方法是主要降低variance的,所以每棵树的深度不能太小,否则bias会过大……而gradient boosting主要降低bias,所以每棵树不能太深太细……唔,原来做模型融合不只有简单的加权平均,还可以在模型基础上做stacking……期间借鉴了很多Kaggle前辈们在github和Kaggle kernels上的代码,不得不表示Kaggle的分享氛围真的是非常好啊!像我这样一次参赛的新手也瞬间变得一招一式有板有眼起来……不过当天快到提交了还没跑完grid search,只能随便填了个估计参数上去预测了,又是自信爆棚提交结果!没想到评测成绩反而大幅下降……妈蛋,我是不是拿错剧本了……

1480397905-3654-7b4333851f9da525f720396548-b10月20号,此时的我已经杀红了眼,前一天肯定是under fit了!于是我开启狂暴模式,除了自己本本还用了几台公司的虚拟机进行并发模型超参数grid search。这里犯了不少错误,比如很多时候特征工程,数据清洗之类的要远比复杂的模型重要,有了基本模型之后花太多时间做超参数搜索其实也是非常浪费时间,而且数据量(应该做一下down sampling)和模型复杂度上去之后,跑一个简单的cross validation都需要几个小时,而提升很可能并不大。最要命的是,真正比赛时的cross validation方法其实是很讲究的,而我只是很傻很天真地使用了random split……结果就是凄惨的over fit,离线效果很好,上线效果傻逼。这还不是最悲催的,那天几乎是通宵作战,到起床收训练结果的时候才发现,模型预测时需要依赖前几个时间点的数据,而在预测集里面这些值都是未知的,必须得边跑预测边把预测值填进去进行下一个点的预测,这些feature的权重还都相当高。早上6点多发现问题,7点多改完程序后一直跑到10点(每天系统评分的时间点)结果还是没有出来。所以那天就相当于提交了个全0的结果,浪费了一次宝贵的验证机会……

1480397906-4770-d3b9279424d25e573e86bb30b8-b10月21号,倒数第三天了,我终于静下心来总结下前面成绩下降的原因,其实是over fit而不是under fit,而且CV的方法也与线上评测不一致导致结果过于乐观。思考一下接下来的战术选择,一条战线是完善之前的树模型,用上xgboost(这货比sklearn带的GBRT快了不止一点点,果然是大杀器)跟random forest和extra trees做混合,用一个2-fold stacking,第二层采用线性回归。然后超参数调优也学乖了点,用上了效率更高一些的bayersian optimization。Feature方面完善了下时间(数据中包含了中秋节,做了点特殊处理),AP点位置等信息,pandas的get_dummies做one hot encoding相当清爽,一行代码搞定。提交完之后成绩终于止血回升,不过名次还是在40名左右。(由于提交次数有限,还有很多想法没法在比赛中验证。赛后对这条战线做了些进一步的优化,将第一次几个模型的预测结果作为feature加入到原来的训练数据中来做第二层的模型训练和预测,最终成绩可以排进前20。)

10月22号,受到几个Kaggle分享的启发,对几个分类分别建立模型训练很可能比对整体数据建一个大模型训练效果要好,于是加了条新战线,打算对AP点做下归类然后分别建模。看了下貌似有Dynamic Time Wrapping做时间序列的距离函数效果不错,结合KMeans做clustering,然后用xgboost里拿到的权重比较高的几个feature,对几个cluster分别建线性模型来做预测(也是受了一位KDD Cup大神的影响,她说她赢了3届KDD,用的都是线性模型,给跪了),训练预测速度比树模型们快了不少。Validation方法也改成尽量跟线上一致的预测一段连续时间的值。尝试了下L1,L2模型正则化,混合一下做了提交。这天的结果到了12名。(看我的语气,简直风淡云轻!)

10月23号,最后一天了,进复赛应该很稳,心态也更加平和了……这天也是进入倒计时后难得的早早地在晚上9点就提交结果了,其它几天基本都是晚上通宵跑模型,早上6,7点起来看结果,做提交。这天主要是看了下各天数据的相关度,果断去掉了前面一大段的时间,只用最后一周的数据来做训练。然后用elastic net来替代之前的手动L1,L2混合,略微调整了下超参数,就提交了。

1480397905-6349-857ecb0b12c55d4b43b662f51d-b最终截止日,我都没有去看成绩,还是微信上同事告诉我说最后冲到了第5名。前几十名的差距都不大,能拿到这个名次还是有很大的运气成分……

1480397905-2905-fb44402c4751f87522cab3e8d2-b第一赛季就这么结束了,虽然是后半程才加入,不过基本上每天都是如饥似渴地学习新知识,边跑模型,边看文章,跑完一轮再加点新调整,机器学习,我也学习……慢慢地也掌握了不少新技术,对数据竞赛也算有了些感性认识。其中走了不少弯路,尤其是一个人参赛,很容易思路僵化,走到“局部最优”点上去,怎么调都没提高……这个时候就要果断切换思路,好好做数据探索,可视化分析,特征提取。放到真实应用场景中,对业务本身的理解绝对是最重要的……对于大多数的问题,模型再高大上再复杂可能也只是微量的提升,但付出的训练,预测的时间代价都是相当大的,可能这也是为什么Netflix当年并没有采用大赛冠军的算法的原因之一吧。反观数据质量,业务特征这些往往是能拉开很大差距的地方。

当然,这些结论都是在不了解深度学习的我看来如此的……在比赛过程中我经常感觉我做的很多人肉工作比如特征选取完全可以由auto-encoder来替代,而不断提交结果不断改进模型的行为,也像极了一个SGD优化过程。我还在寻找自己作为一个人类的独有价值所在……
附几个当时看到的不错的学习资源:

某Kaggle大神的参赛示范代码:github.com/ChenglongChe

Kaggle某次类似时间序列预测比赛的赛后分享和讨论:kaggle.com/c/walmart-re

Phunter大神分享的比赛脚本模板:kaggle.com/phunter/flav

来自北大的著名天池选手的github(初赛第二名):github.com/wepe

跟上面的大牛一起组队的另一只大牛的博客:blog.csdn.net/bryan__/a

ensemble必读:mlwave.com/kaggle-ensem

xgboost调参指南:analyticsvidhya.com/blo

复旦小鲜肉的Kaggle比赛指南:dnc1994.com/2016/04/ran

时间序列特征提取库:github.com/blue-yonder/
后面还有第二赛季,有空再写吧。

内容多来自网络,如有侵权,请联系QQ:23683716,谢谢。:一起大数据 » 数据弱鸡的天池观光游(一)

优秀人才不缺工作机会,只缺适合自己的好机会。但是他们往往没有精力从海量机会中找到最适合的那个。 100offer 会对平台上的人才和企业进行严格筛选,让「最好的人才」和「最好的公司」相遇。 注册 100offer,谈谈你对下一份工作的期待。一周内,收到 5-10 个满足你要求的好机会!
赞 (1)
分享到:更多 ()