经过了近两个月的艰苦工作,这次在阿里天池的比赛终于结束了。第一次正经的去参加数据挖掘的比赛,从第一赛季开始到第二赛季结束,完整地经历了整个流程,每天提出新想法,学习新的方法,然后用编程的方法去实现,看着自己的MAPE一天天的下降,那种感觉也是很棒的。觉得付出了很多,也收获了很多,自己也找到了自己的方向,希望自己在未来可以朝着大数据和人工智能方向继续前行。而且这次比赛之后,自己在剩下三年的大学时光中还会继续参加很多这种比赛的,觉得这种比赛要比基础算法比赛更有趣,漫长的周期也更适合我比较散漫的生活方式。在这里回顾一下比赛,总结一下比赛的经验和教训吧。
初次接触数据挖掘大赛。
第一次参加数据挖掘比赛,虽然前面打过KDD CUP的比赛,而且类型都是差不多的,但是那次也只是分析了一下数据,然后用统计量做了一下填补而已。而这次我们要动真格的了,我们要用机器学习的模型去生成结果——大杀器Xgboost。至于Xgboost的厉害之处,我会在另一篇blog上写一下,据老师私下里给各个模型的排名,Xgboost除了在图像处理上略逊于深度学习,在其他领域上应该都是最厉害的模型了。
第一次提交结果。
第一天的时候,我们并没有去分析什么数据(其实以后也没怎么分析,我认为这也是我们犯下的一个很大的错误),而是直接去填了一个历史中位数,我当时并没有理解为什么要用这么个简单的中位数去填补结果,只是在第二天早上起来睡得懵懵地看了一眼线上结果,MAPE在0.4284,在当天排名中占25名。当时感觉还不错的,也没有在意什么别的东西,到了第二赛季的时候想了想,这么提交个中位数应该是为了获得一个MAPE标准,看看建模比这个统计量能提升多少。当时没有测试线下数据集的MAPE,也没有对提交有一个详细的日志,导致到了第二赛季刚开始时,很多问题找不到原因,想与第一赛季同样方法做出的结果做对比时却没有数据的尴尬。后来又对这个统计量做了一下优化,但是并没有提升多少,可见这种在KDD CUP上做起来效果还不错的方法在这次比赛上并不好。我觉得可能是这次比赛数据量比较大的原因吧,当数据量比较大时模型训练的就越完备,预测的也就越接近真实值,这是我的理解。
Xgboost建模。
由于有了之前用Sklearn中的liner-regression建模的经验,这次初次使用Xgboost建模并没有遇到多少的困难,只是Xgboost的训练集和测试集要求使用libsvm格式的文件,我尝试过把训练集和数据集做成libsvm文件的形式,但是出现了各种各样的格式问题。后来发现可以直接用numpy的二维数组导入。。。真的坑。
第一次建模没有采用任何的特征工程,也没有对数据采取任何的预处理,当时的数据纯净度还不是特别好。我们只用了历史中位数和路长两个特征,用了6月份6-7点的数据作为训练集,6月份8点的数据作为测试集来建模,最后的线上结果可以达到0.3540,相对于单纯的使用统计特征MAPE有了将近7%的提升,看来Xgboost果然名不虚传。但是刚刚开始做的时候,我建模的时候感觉特别别扭,因为感觉平时做建模的时候都不是这样做的,后来想了想,这样实际上是在历史中位数和真实值之间做了一个映射,而不是通过特征在历史数据和未来数据中建立映射,所以才会感到很别扭。
改变别扭。
在第二次建模时,我们采用了另一种方式,之前的建模方式是以时间为主要维度进行建模的,而第二次建模我们选择以日期为主要维度进行建模。这次我们选择了历史中位数,预测时间前两小时的旅行时间,路长这三个特征进行建模,最后的效果有了比较大的提升,在线上可以达到0.3273。之所以能够取得这样的提升,在后来我们考虑到了两个原因,第一个可能是在小时时间轴上数据的波动性比较强,第二个可能是因为采用这样的方式数据量比较少,所以我们在采用第二个方式建模时获得了较大的提高。在第二赛季时,我们又尝试过了基于更多特征的第一种建模方式,但是效果也比第二种建模方式差了百分之2,当时我们想可以用第一种模型预测出的结果作为第二种模型的特征,但是最后也没有实现。
增加特征。
在改进了建模方法之后,我们为模型增加了更多的特征,例如把原有提取近3个月的中位数的特征扩增为3个月的,2个月的,1个月的。基于类似的方法,我们为模型又增加了很多的特征,这些增加的特征对于模型有一定的提升,但是提升并不是特别大,后来我考虑可能是因为这些特征都在同一纬度上,各个特征之间差别比较小,所以对模型的提高不是特别大。
窗口平滑。
为了增加特征,我们还对数据进行了平滑处理,让数据在变化时变得更稳定,但是失去每个时间点和相邻时间点的特点。我们基于两个维度对数据进行了窗口平滑,一个是一天内每分钟之间的维度,另一个是每天之间的维度,在双重平滑处理后再提取特征,这样就增加了一倍的特征。但是在采用窗口平滑后效果提升并不明显,后来我们发现是由于在每分钟直接的维度方向上,由于采用两分钟为一个时间窗口,时间窗口太短导致三个时间段为一个窗口平滑变化太小,在我们采取了五个时间段为要给窗口平滑后,效果提升的就比较明显了。
更换目标函数。
在初赛进入到最后一天时,我们找到了一个让模型提高的好方法,而这个方法也是让我们能够进入第二赛季的关键。在最开始我们使用Xgboost的时候,为了适应比赛MAPE的评价指标,我们采取了对标签取ln运算,预测后再去exp的方法,当时我并不清楚采取这种方法的道理。xgboost的目标函数是残差(y-y')^2而我们希望MAPE的评价函数是(y-y' /y)的方式,我们把y和y‘取ln后运算,结果就是ln(1+(y-y'/y)),而(y-y')/y就是其泰勒展示的第一项。但是问题是这只是泰勒展示的第一项而已,所以存在一些误差,于是我们采取了自定义损失函数的方式,最终让结果提升到了0.3064,让我们顺利进入了第二赛季。
第二赛季比赛改为了线上平台赋权的方式,只能用SQL去操作数据的方式让我很不习惯,而且在线上操作需要等待很长时间,最后在我快要放弃的时候,比赛突然开放了数据集,允许在线下进行操作,这让我又有了一点希望。
第二赛季的首次提交。
这一次提交,我们依然选择填了个历史中位数,由于更换了数据集,第一次提交效果就达到了0.3105,也进入了首页。
建模。
我们用了之前的建模方式,在可视化平台上用GBDT进行了建模,但是由于在线上平台真的很难调参,跑起来也很慢,我们的建模结果并不理想,效果仅达到了0.3050,这让我们感到很失望,毕竟在第一赛季用合理的方法建模效果可以提升将近10%的!最开始我们考虑原因可能是三个时间段同时建模,对效果的影响会比较大,但是后来分开建模后效果也提升的并不是特别明显。我想最重要的原因就是调参的问题吧,当然由于切换数据集的原因也是可能的。
开放平台。
某天我早上正因为熬夜早起而头痛时,老师突然发来消息,说是可以在线下去做了,喜大普奔。在用第一赛季效果不错的模型,换用第二赛季数据后,建模效果还是不怎么好,提升到了0.2712,离我们的预期MAPE还是差了很多。但是总归有了努力的方法,毕竟在线下的环境还是我们比较熟悉的,而在线上提取特征简直太困难了!
增加特征。
按照以往的套路,当我们没有可以提高模型的方法时,也就是能再提取特征了。我们参考了2017KDD CUP答辩PPT的做法,又陆陆续续提取了最大值,最小值,标准差,锋度,偏度等特征。但是加上这些特征对于模型的提升依然很缓慢,效果在一点点的提升,不过在当时看来已经没有什么能够提高效果的方法了,只能一点点的增加特征。
去噪。
对于中位数这种特征,先天就有防止噪声影响的特性,但是对于平均值尤其是最大最小值,及其容易受到噪声的影响。所以我对数据进行了一次3δ去噪,将太偏离正态分布的数据替换成了中位数,并没有选择直接剔除的原因是毕竟有些特征还是可以包容噪声的。而且不知道是不是增加了特征的原因,进行了去噪后的数据建模的效果得到了较为明显的提升。
ZSCORE变换
后来我们又知道了一个让数据集增加信息量而且正则化的方法,就是ZSCORE变换。进行了ZSCORE变换后效果提升的并不是特别明显,但是迭代的次数显然减少了,原来基本要4000步迭代完现在2500步基本就能迭代好,总体上对于效果的提升一般。
基本上最大的问题还是线上线下的数据集构建的不好,代码写得太乱,还有就是没有作好记录。
总计以我的菜逼水平,到rank28已经很开心了。