高薪算法+计算机职称考试Python数据结构与算法

滴滴大数据算法大赛Di-Tech2016参赛总结

2016-09-04  本文已影响9774人  刀刀宁
  • 写在前面

写在前面

我是一个之前PhD做分布式计算、虚拟机调度,毕业之后年初才转ML的家伙,自恃有点学习开发能力和混迹ICPC竞赛的底子,对数据还有些敏感度,有那么几个可以跟着学习的人,斗胆在5月底开始利用业余时间玩一玩。
最后的成绩是预赛58名,队名robust(预赛结束前一周还混迹在前15名之内的一个队名),滴滴官方在剔除掉前50名的作弊参赛队之后,出乎我意料的没有“扩充”名额,仅41队参加决赛(这和官网上挂出的“50队探索科学边界”的标语形成鲜明对(da)比(lian))。
就是说我的最终排名应该在49名(最差)。所以如果参加了决赛,再让我学习一个月,结果可能还真未尝可知。详情请翻到本文最后“趣(tu)事(cao)”篇。

言归正传,以下介绍题目、方法(包括我知道的一些其他队伍的方法),然后说说我的总结和感想,最后还有一些趣(tu)事(cao)。

因为我最后没进决赛,所以我的总结和感想中会带着很多和我自己方法的对比,以及会着重写一写我自己后来觉得值得学习和改进的东西。大牛们可能会觉得比较弱,可以自行跳过。总体上感觉应该还是比较适合入门级选手。
本文部分图是借用其他队伍的答辩PPT(会注明)。
文中会产生一些不专业不严格的名词等等,还请大家批评指正。


更新:20160929,补充了一大批PPT报告的截屏图片,丰富了一下内容。
更新:20170101,补充了一些关于神经网络方法的想法。从滴滴比赛结束之后我一直在做机器视觉方面的工作,比较集中关注目标检测以及目标检测问题在移动设备上的实时性问题,欢迎感兴趣的同学讨论交流。
可能还会时不时的更新我新学到的东西。


题目

http://research.xiaojukeji.com/competition/detail.action?competitionId=DiTech2016

数据:

  1. 某市一段时间内(20+天,决赛时更换了数据连同预赛数据一起有40+天的数据)的打车订单日志,包含乘客,司机,时间,价格,起始区域。司机为空代表该单没有被满足。数据量有上千万条。
题目描述 test数据集中有被预测时间片的前30分钟订单、天气、交通等信息

目标:
预测未来某时间(一般是未来十天)区域内打车供需差:即该时间片该区域中总的订单数减去被满足的订单数量。后文会称其为gap值。

猜测动机:
得到供需关系,为合理调度快车司机提供数据支撑。

评测指标:
预赛 MAPE(Mean Absolute Precise Error)
每个时间片每个地区的预测值和真实值差值的绝对值/真实值,最后求总的平均值
决赛 MAE(Mean Absolute Error)
每个时间片每个地区的预测值和真实值差值的绝对值,最后求总的平均值
所有时间片所有地区,取平均时权重相等。

MAPE and MAE

基本解决方法:
预测问题,回归方法

简单评价:

  1. 我觉得地理信息给的有点少。
  1. 评价指标,尤其是预赛的,匪夷所思。

建模方法

需要设计的无外乎样本,标签,以及验证集。
样本构造的“标准方法”,即被训练时间片的前30分钟(或者20分钟)的特征作为该时间片的样本,而这个样本对应的标签即接下来的10分钟的gap值。
其代表的物理含义是根据趋势进行预测,而不是根据历史进行预测。

后文都将对此方法称为30:10,或者20:10,即代表30分钟样本数据对应10分钟标签数据。

造成这个方法成为“标准方法”的根本原因是因为,只有几十天的数据,如果训练样本中需要用到跨天甚至垮周的数据,势必造成训练样本数量减少,并且没有直接证据可以证明用了跨天或者跨周数据会带来非常好的提升。所以几乎所有取得好成绩的队伍都是使用的该方案。
换言之,从这个数据集的角度出发,我们可以下这样的结论:影响供需的主要因素就是这个时间片前面的20到30分钟的种种特征。
所以最后如果每天有144个时间片,每个时间片都有前20-30分钟的样本,在不扩充样本的情况下每个区域拥有144*21(+24)=3024(6480)个样本,括号代表决赛。

在数据量很大,例如有20周数据时,右方法的样本数量就不会比左方法差太多了,这时其效果我觉得可能会比左方法好。但是在比赛数据有限的前提下,右方法的样本数量太少。

不管是30:10还是20:10,这里面能做的文章还有很多。因为订单信息是精确到秒的,但交通和天气信息大体是按10分钟一个时间片来划分的,所以直观的,就是使用10,10,10:10(就是三个10分钟的综合特征对应10分钟的标签)这样的样本。之所以说他直观,是因为我就是用的这个方法,相当的naive,当时使用的样本数量大概为21w个。
其实,可以做的文章有很多:

30,20,15,10,5,2:10的组合方式 5分钟步长的滑窗

验证集构造方法常见的有两种

如果预测23号就用16号做验证。这样样本量减少1天(或者更少)。结果是验证效果有偏。另外,还可以用16号、9号、2号做三次验证取平均值 样本量不变。样本抽取特征的空间变小了,很多人觉得舍不得,但是事实上半小时前的特征对GAP影响并不大。验证效果基本无偏。

事实证明第二种略优一点。虽然使用第二种的代价是训练样本时间从30:10变为20:10,但是事实证明,缩减掉的前30分钟数据对结果影响并不大;相比之下使用训练集最后一周数据则因为不同天反应出的不同特点严重影响验证集效果,造成本地验证效果无法体现在上传结果上。
我的方法在验证集构造上失误了,因为我一直用的第一种方法,略不同的是我选的还不完全是最后一周的数据,而是一个精心设计的验证集,简单说是三个不同训练-验证集交叉验证结果(这么做的原因是因为当时发现1月20号的数据极端诡异,缺数据,数据分布和6/13号两天不同),依旧抵不过使用第二种构造方法。造成我预赛最后几天因为本地验证集合线上测试集严重不匹配,又缺乏经验,各种抓狂,却又无计可施。


特征工程

这里简单描述一下常规的特征工程,复杂的、具有决定意义的特征工程放在下面提升方法中归纳总结时提出。
特征工程是和样本构造紧密相关的。
我的特征最后只有140维左右,加上POI的50维,最多的时候也只有190维左右。并且前140维大部分是前30分钟3个时间片的重复特征。基本的特征大概是50维左右。


我的几次提升方法

  1. 目标函数映射
    因为预赛的评价指标是MAPE,而我用的XGBoost的目标函数是线性的(小声说,其实一开始我还不知道要去修改目标函数,后来知道了也不知道怎么自定义目标函数。不过还好,现在都学会了),所以想了一种映射方法,即把标签取log,然后预测完之后把结果取power。
    这个改进非常有效果。其物理含义是重新拉伸了目标值域的数据分布,增加了小数据预测时的敏感程度,放松了大预测值的精度。我前面有讲,因为MAPE本身对小数据敏感,这个改进那是相当的make sense。
    直观上,决赛修改成MAE之后貌似是不需要再修改映射关系了,但是据说有的队在决赛时候同样通过这个映射完成了提升。我猜测是因为gap值本身成指数分布,对小值预测敏感一些就合理了。

其他工作

  1. 验证集预测结果分析。也就是前文的5. 数据后处理,还有一些其他的繁琐的分析,主要集中在和真实结果的比对上,我并没有统计出什么太多规律出来。

这个领域,不经意的一个小改动可以大幅提升效果,而费尽心思的一个很大的改动可能并不能起到什么效果,甚至是负效果。但是你不尝试不知道,甚至有可能有理论或者感觉可以支持一个改动,但是有可能实现完还是会没有用或者负作用。尤其是在特征工程中,只提取几个简单特征可能会带来一定的提升,当继续增加特征时,效果可能越来越不明显。但是这时,可能最有效的提升就是由一点又一点的特征积累得到的,尤其是越来越难以想到的,隐含的越来越深的,那些高阶特征。
是的,这是一个磨炼耐心的过程,一个“修行”的过程。


从其他队伍那里学习到的几个提升方法

以下的方法都不是我自己实践的,结合通过各种渠道获得的信息,加上自己的理解,先把干货抛出来,希望可以和大家共同讨论。

  1. 特征统计属性
    从最终比赛成绩来看,仅使用XGBoost+特征工程确实可以做到前几名。但是这样做做的最好的队伍,在特征中融合了大量的统计特征,这与他们拥有坚实的经济学、统计学理论背景是有分不开的关系的。

我自己的总结和感想

  1. 用来实现回归的方法主要还是:决策树和神经网络两大类。

神经网络方法的一点思考

我的感觉是大部分人使用神经网络还是作为一个替代决策树的回归器,真正使用神经网络来提取特征的队伍少之又少,能掌握这项技术的人也不多。
另外我的感受是,神经网络的效果还是很不错的,但是在这个问题本身看,其单位功耗创造的价值则远小于决策树模型。
这个问题同时存在于非图像语音自然语言处理等数据挖掘领域,即便是在这几个神经网络大放异彩的领域,传统方法在移动计算等方向上,因为计算成本的要求,依旧有着巨大的生命力。
当然,这不代表神经网络不重要,或许某一天,随着硬件成本的下降,算法能力的提升,这些问题就不再是问题了。

----170102更新分割线----
滴滴比赛结束也有小半年时间了,这段时间做了不少神经网络方面的工作。简单总结一下,以CNN为首的这一波深度学习大潮,我认为核心带来的应该是简单特征的非线性组合关系对有用特征的筛选能力上。
如果我们处理的是图像,那么像素值就是简单特征,那么多层卷积层之后得到的特征,就是简单特征的非线性组合。简单特征相对比提取后的特征,虽然特征表达能力不行,但是保留了最多的信息量。同时,神经网络对简单特征的非线性组合关系是多层的,非线性叠加非线性,从使反向传播机制获得的特征,其所能表达的事物和描述的能力,都是人工特征所无法比拟的。由于无用特征往往在训练过程中因为权重调整已经被“过滤”掉了,因此,由非线性组合出来的高层/深层特征,也使得后续分类/回归器再整个模型训练过程中变得较传统方法没有那么重了。
回到滴滴比赛,以及类似的有已经较为抽象的特征(订单信息、时间信息、天气信息、交通信息等等)的问题上,神经网络依旧可以发挥其对简单特征的非线性组合能力。不同的是,第一,这类问题的简单特征本身已经不再简单,换言之,这类特征是已经被组合过一次了的,因为他们可能本身就已经是统计性的信息,丢失一些只有简单特征才有的信息,类比图像里面像素级的信息;第二,在这些特征中组合出来的更加复杂的高维特征,因为维度较高,其可解释性较差,很难加入领域相关的先验知识进去,而组合过程的盲目性较大,导致真正有用的高维特征难以被筛选出来。反而是传统人工特征方法在比赛这样的数据量级下面并不输给神经网络。
另外,由于本届滴滴比赛里面人为刻意略掉了地理位置信息,相当于扔掉了一块很大的空间信息,而卷积神经网络本身是强在处理空间数据的,这也是传统特征工程可以不输于神经网络的一个重要原因。

----170102更新end----

利用深度学习来进行时空数据挖掘,这个领域也是由来已久。如果我们把一个城市平面当成是一张图,而把时间序列看做是多张图组成的一个视频,那么就可以相应对交通拥堵、流量预测、订单预测等问题进行建模了。
这里推荐两篇文章:

讲堂|郑宇:多源数据融合与时空数据挖掘(上)
讲堂|郑宇:多源数据融合与时空数据挖掘(下)

----170426更新end----


大数据量与分布式计算的一点思考

因为比赛只提供了预赛21天,决赛24天,单个城市(某一线城市)一共45天。相比滴滴公司的日常数据量,因为没关注商务方面,所以简单猜测全国大小城市应该都覆盖过去了,应该有相当于至少一百个一线城市的量(不负责的猜测),每年产生365天的数据。
相比比赛的数据,一年的数据就相差了至少3个数量级,同时还是增量的,流式的,这很可怕。
同时,这个比赛的供需问题,仅仅是滴滴日常面临的问题中,可能还是相对比较不紧迫的问题,之一。因为不同问题对数据的需求不一定相同,用到全部数据的方法不一定比例特别高,但是完全可以猜测,这么大的数据量,同时去处理这么多的问题,真的是世界级的难题。当然我这么猜测的主要原因主要还是因为坊间分布式架构大牛的跳槽。


参加比赛和学习知识的对比

参加比赛时间紧,有压迫性,好玩有趣,因此有动力去搞。但是往往目标单一,一切需要掌握的东西都围绕着比赛目标出发,在整个知识体系中,是一条线而不是网络和体系。
这种方法是从实际问题出发的,会去找到问题本身的特性,针对其给出方法和优化,重点是把掌握的知识和实际问题相结合。
这种方式进行学习,适合初学入门的人快速切入,但是随着比赛次数的增加,你每次能从比赛中学到的东西会相对越来越少。即便运气好,你也几乎不可能完全通过比赛来完善自己的知识体系。

而日常学习知识则正好相反,时间宽裕,但是往往需要自己编织知识网络,因为经常要深入一些看起来没有用的小知识点,必然枯燥无味,容易懈怠,会混沌会茫然会停滞不前。
这种方法的研究手段也不一样,往往从一篇paper或者是已有模型/算法,通过理论或者推导,找到其不足的地方,再去优化。处理的往往是一个泛化的问题,从解决一个具体的问题升华到了解决一类问题上面去。
这种方式,学到的知识相对系统,完整。日后随时随地用起来的时候引经据典,信手拈来,驾轻就熟,讨论起来的时候拍案惊奇,舌战群儒,滴水不漏。不过也容易走过头变成纸上谈兵。

所以,两者相结合也是极好的。通过比赛发现问题,通过问题作为切入点展开学习,最后再通过比赛查漏补缺。
所谓学而不思则罔思而不学则殆是也。(这里学代表学习知识,思代表动手实践得到第一手资料)


最后的感受

从一点不会,到一步步分析问题,分析数据特点,思考解法,设计模型,学习算法,编写代码,加进新想法,分析结果,尝试不同的方法,提交,等待结果时的紧张和兴奋,与其他人交流时的倾听与学习,看到了一次又一次突破性方法带来的成绩提升,也曾为了能突破11名进入第一页苦苦拼搏。

我的比赛其实在6月20号就结束了,细看看,从5月26号下载数据开始的一个月很充实,吃饭在想,睡觉在想,出差在想,崴了脚还在想。时间过得很快,有一种沉浸其中的感觉,我想这是我很久以来没有找到的一种感觉了,一种当年参加ACM竞赛时的投入感,第一次实际把学到的机器学习的东西付诸实践,也算是去尝试解决一个实际的问题。很久没有实际解决真实问题了,确实很兴奋。


趣事

我是一个之前PhD做分布式计算、虚拟机调度年初才转ML的家伙,自恃有点学习和开发能力,有点对数据的敏感度,有几个可以跟着学习的人,斗胆在5月底下载了滴滴比赛的数据,因为一开始先拿到了师弟天池比赛预测的方法和一些基础代码,所以决定利用业余时间好好学习一下这个领域。
一开始并没有太多想法,但是随着几次比较大的优化,比如重建样本集和映射目标函数两个大的优化,大概在6月3日左右就爬到了33名,当时着实被惊到了,真的是没有想到。其实我觉得真实原因必须是因为我的队名起的好,因为我用了早年参加ACM WF时的队名robust,如果实在不是那就一定是因为那天是我家崽崽一周岁生日的原因。
反正,总之,这个时候自己的学习热情已经全部被激发了起来。6月8号报名截止时一口气冲到11名。12号test数据切换完之后,一度掉到30+名,但是简单调整之后14号又重新回到13名,这时候觉得进复赛应该是没问题了。
因为毕竟可以多一件衣服,想到自己最近正好没钱买T恤衫了,想想还是非常非常有价值的。可能是被免费衣服搞兴奋了,结果15号去南京农大踢球的时候被人一个飞腿铲崴了脚,然后在南京某酒店床上躺了十天,最后竟然是坐轮椅在机场辗转回到长沙家里。
短暂恢复两天之后,在酒店床上完成了最后几天的比赛。但是这时候出现了比较严重的问题,应该是验证集选的不好,导致本地优化完全体现不到线上去,成绩一直没有超越过14号的成绩,需要大家脑补一下的曲线是这样的:14号13名,15号16名,16号22名,17号33名,18号58名。

我的成绩回顾

如果非要说这个曲线是正常的,杀进去的人都在最后时刻实力爆发,作为从中学就开始参加信息学竞赛、ACM退役之后又当了N年教练、组织过不知道多少比赛的我,是断然不会相信的。更何况这次决赛仅取前50名,而刚刚好又是我自己跨越了这个门槛。但是当时天真的我竟然相信一定会有个好的答复,衣服啊。
按照组织比赛的经验,网赛结束前一般都会出现诡异现象,其实是人性使然,也无可厚非。网赛作弊一是代码拷贝(或者小号),二是思路分享。第一种好检查,比对代码即可;第二种没办法。但是一般网赛后边都是现场赛,一般是适当按照相对公平的标准,在现场赛能容忍的前提下扩大一定的范围,你先进来,但是现场赛真刀真枪不会再任你胡作非为。
当然,肯定不能拿ACM竞赛来简单对比这种实际的比赛,毕竟大公司比赛的题目更加实际、比赛时间更长、赛事保障更加复杂。每个队的方法都不一样,单单代码复现这件事就意味着需要有大量人工投入进来,对于一个迅猛发展起来的大公司,嗯,也许大概的确可能还是有点紧张吧。
只对比几个能对比的吧,小号,代码拷贝,模型分享,思路分享。当然官方也意识到了这些问题,前一百名都被要求提交文档,没提交的肯定就是前三种,而第四种一样的没办法。
当然,我就寄希望于他们宁可放过一千也不愿错杀一个,毕竟办比赛的真实目的是为了扩大公司的影响力和招人,迫切需要解决的问题也一定不会通过比赛来解决。但是,多放进些人来,是一定可以扩大愿者上钩的范围的。哎,我替它考虑这干什么,还不是为了那件衣服。
万万没想到
滴滴官方最后的做法是这样的:预赛的实际排名前50名卡死,再去除小号,最后只剩41名。

官方决赛期间的主页上赫然标出:“50支队探索科学边界”,看来是把各种作弊僵尸算进去了,宁可错杀一千,也不愿多放进一个

顿时有一种说不出话的感觉。
不难受是不可能的。
用大脚趾头想都能想到,递补9个,无论我前面还有没有小号,我都可以进决赛啊。
然而
没有递补
没有递补,就没有衣服了啊。。
不过,
组委会后来终于在我的追问下告诉我说,衣服还是照送的,提交了文档的都有。哎,就是嘛,就当是给打车乘客的补贴嘛,小场面小场面。一颗悬着的心终于落地了,目的达成。

截止发稿,已经收到滴滴寄来的参赛纪念衫。

感谢wyz、gxz、lmn、xtt、qz等队友。
感谢一剑风吼,threshold等队提供的算法交流。
感谢Blitz队,提供的数据和丰富的图表。
感谢帮助过我的人们。
感谢滴滴。http://research.xiaojukeji.com/competition/main.action?competitionId=DiTech2016

很多人留言问数据:
链接: http://pan.baidu.com/s/1nv2aY5z 密码: 7ce4
只是不知道有没有侵权,如果有请告知我删除。

To be continued when 我什么时候再想到点什么的吧

上一篇下一篇

猜你喜欢

热点阅读