首次参赛,截止目前,成绩前15%。写这篇文章的动机在于复盘我们(队名JNaNU)的方案设计,关于这次比赛的详细信息,请看这里,具体包括赛制介绍,赛题与数据等。

在了解问题背景之后,我们就研究了阿里流行音乐大赛TOP5的解决方案(下文简称TOP5),定下了人工特征+模型融合的大框架。当时我们有三种模型观点,分别是神经网络,时序预测模型,回归模型融合,最后讨论的结果是做回归模型融合,融合还是不融合?在框架设计的时候是满足融合需要的。另一方面,在我们做了初步的数据分析后,得出了要做人工特征的结论。

比赛工具: python+pandas+numpy+sklearn+matplotlib+multiprocessing+vim+pdb

  • python: 编程语言
  • pandas: 轻文本处理库,负责文件读写,主要数据结构DataFrame,Series
  • numpy: 科学计算
  • sklearn: 机器学习算法库
  • matplotlib: 绘图库
  • multiprocessing: 多进程,分布式计算,用于代码加速
  • vim: 编辑工具
  • pdb: 调试工具

一.特征工程

1.数据预处理

user_pay大小约4G,数据量6000W+,将shop_info和user_pay利用pandas做group和join操作,得到2000个商家在有记录的日期内客流量(字段名称pay_sum,下文统一使用交易量代替客流量)。在TOP5的启发下,决定不使用商家信息中除了shop_id,city_name之外的其他信息,同时不使用user_view中的任何数据。虽然不使用的信息似乎对于客流量会产生直接的影响,比如,通常意义下,当日用户流量大的商家可能交易量也相应的大。由于日期数据可能存在不连续的情况,在交易量数据的基础上做了空值处理。同时也利用盒图做了离群值检测,这些离群值的产生很大程度上可能是由于商家当日促销活动造成的交易量暴增或者其他原因导致的暴减。实际上,峰值的出现可能是周期性的一个标志,后续我们也尝试了不做离群值剔除。

2.特征生成

问题的需求是预测2000个商家从2016.11.01到2016.11.14的14天客流量。虽然交易量数据大部分是从2015年开始的,但是我们决定利用2016.09.01到2016.10.31的两个月数据预测未来14天的交易量数据,这个过程,同样没有使用到较多的数据。虽然,后续我们尝试将训练数据改为前3个月,但是虽然可用数据更多,但是引入了新的问题,比如,某个商家8月份没有数据,这个时候在数据预处理阶段的空值处理的问题也就凸显出来了。关于人工特征设计,分为3类共11个特征,如下:

字段 含义 类型
time_stamp 日期 datetime,例如: 2016-08-01
dayofweek 一周中的第几天 整型,[0~6]
holiday 是否是工作日 枚举类型,0或1,0:工作日
lt 当日该城市最低温度 浮点类型
ht 当日该城市最高温度 浮点类型
sunny 当日该城市是否是晴天 枚举类型,0或1,0:非晴
m2M 当日起过去两个月交易量中值 浮点类型
w2A 当日起过去两周交易量均值 浮点类型
m1L 当日起多去一个月交易量最小值 浮点类型
d3w3 当日起过去三天交易量总和和当日起过去三周交易量总和的比值 浮点类型
m1Lar 当日起过去一个月的交易量最大值 浮点类型
w2Std 当日起过去两周的交易量标准差 浮点类型
pay_sum 当日交易量 浮点类型

从上表中可以看到,三类特征分别是节假日特征,天气特征和统计特征。其中节假日特征和天气特征的获取是通过爬虫工具。在写这篇文章的时候,在论坛看到有人加了空气质量数据。(好吧,吐槽一下,在论坛获得的最有价值的东西也就是这些公开数据了)

3.特征选择

由于特征量不大,故起初我们没有进行特征选择,后来张杰(目前, DC平台用户贷款风险预测TOP3)建议利用xgboost进行特征选择后再进行训练。我们发现不仅实现了降维,而且预测精度有提升。实际上在模型选择前,我们目前也只是做了xgboost的特征选择。

二.模型融合

在模型方面,我们选择了四种模型,分别是XGBRegressor, GradientBoostingRegressor, SVR, RandomForestRegressor。通常好的模型融合要求基模型关联度小同时预测精度相近。上述模型中,除了SVR,其余三种模型都是tree-based模型,实验结果表明,预测精度相近。至于这种模型选择是否是最佳融合方式,需要后续的实验对比。对于4个模型的最终预测结果,我们采用加权的方式处理,权重系数同样是需要选择的参数,通过选取合理的权重系数,保证融合结果最优。

在利用特征进行数据训练之前,采用5折交叉验证进行模型参数选择。在这个过程中,由于每个模型参数众多,故我们只选择了最重要的几个参数进行自动选择,我们理解的最重要是参数的改动对模型的预测精度会产生较大影响的参数,通常在文档说明中排前几位的参数是我们的重点tuning对象。比如在Xgboost有18个参数,我们选择了n_estimators和max_depth两个参数进行GridSearchCV(自己写了逻辑,后来才发现sklearn中有对应API,已经没有什么我大sklearn做不到的事情了),选择依据是交叉验证误差最小时对应的参数,回顾Andrew Ng在谈模型选择的时候针对线性回归模型选择时画的几张图。

在预测阶段,按照日期进行预测,由于存在滚动特征,比如统计特征,故待预测的第二天的特征需要用到已经预测的第一天的预测交易量。

此处给出了代码流程图:

代码流程图

输入中的weather是爬虫数据,word.data是在城市天气数据处理时涉及到的中英文城市名转换依赖的库。经过数据预处理,特征生成和模型训练预测,最终生成预测数据,并对结果可视化。

三.代码加速

特征生成阶段,时间耗费近3小时,但是在特征生成后,该数据作为训练数据可以保证在较长一段时间内不需要再重新生成。预测阶段耗时近40分钟,由于每当模型参数变化时,要重新预测,故此部分需要代码加速,具体加速方案可以看之前的文章代码加速篇代码加速附加篇

四.结论

通常在结论部分,总要总结下各种“坑”,以防“踩坑”。第一,由于模型部分主要采用sklearn,在使用模型和函数的时候存在一些焦虑,哪些是自己应该去做的,哪些是模型或者函数已经做了的?所以,在使用开源库的时候,在享受高效便利的同时,需要从宏观上了解别人做的和自己需要做的。第二,模型迭代时,控制变量数目。实践证明,我们对于复杂系统的控制能力远没有达到自以为的水平。第三,重视代码细节。有时候预测结果不好,可能不是特征或者模型不work,而是代码bug。

参考

1. How to Rank 10% in Your First Kaggle Competition

2. Kaggle Ensembling Guide

3. 使用sklearn优雅地进行数据挖掘

4. Bias v.s. Variance Andrew Ng

5. Complete Guide to Parameter Tuning in Gradient Boosting(GBM) in Python

6. jasonfreak博客