【总结】IJCAI-17 口碑商家客流量预测参赛总结

时间:2023-01-08 11:16:47

说是总结其实更多是教训,成绩不好。
关键词搜进来的想来学习的朋友可能要失望了。。。

参赛经历

时间: 2017.2.21~ 2017.3.14

比赛链接: IJCAI-17 口碑商家客流量预测

结果:
【总结】IJCAI-17 口碑商家客流量预测参赛总结

大概只比平均值的效果好了一点点。

比赛分析

比赛介绍

问题 Statement

预测客户流量对商家的经营管理至关重要。在口碑平台上,我们将客户流量定义为“单位时间内在商家使用支付宝消费的用户人次”。在这个问题中,我们将提供用户的浏览和支付历史,以及商家相关信息,并希望参赛选手可以以此预测所有商家在接下来14天内,每天的客户流量。

评测 Evaluation

在这次比赛中,每只队伍需要预测测试集中所有商家在未来14天(2016.11.01-2016.11.14)内各自每天(00:00:00-23:59:59)的客户流量。预测结果为非负整数。
【总结】IJCAI-17 口碑商家客流量预测参赛总结
ps: 这个loss函数以前没遇到过,也不知道有没有定义,到结束后看到别人的分享才知道是SMAPE

数据 Data

提供从2015.07.01到2016.10.31(除去2015.12.12)的商家数据,用户支付行为数据以及用户浏览行为数据。

提供的原始数据是客户-商家的所有支付记录和浏览记录。记录量较大,4G内存的笔记本直接用pd.read_csv读入和操作是都会有内存不足的问题。所以将记录整理简化为所有商家每天的客流量数据。当然这个过程丢失了很多原始信息,看到其他选手有从每小时消费量提取特征,但是限于当时的思路和实际情况还是采用这种方式。

比赛过程

由于是第一次参加类似比赛,也是第一次需要完成完整的数据分析处理的过程。刚开始的阶段就耽误了很多时间。开始一周主要用来熟悉jupyter notebook, pandas等等常用的工具。

Load Data

这里是通过迭代的方式load data, 以及对pd.DataFrame进行groupby等操作,避免处理大数据量时内存不足的问题。

# load the dataset
in_file = './dataset/dataset/user_pay.txt'
reader = pd.read_csv(in_file, iterator=True, \
header=None, names=['user_id', 'shop_id', 'time_stamp'], \
parse_dates=[2])

loop = True
chunk_size = 100000
chunks = []
while loop:
try:
chunk = reader.get_chunk(chunk_size)
chunks.append(chunk)
except StopIteration:
loop = False
print('Iteration is stopped.')
full_data = pd.concat(chunks, ignore_index=True)
# groupby DataFrame
size = 1000000
i = 0
flow = {}

while (i < full_data.shape[0]):
data_i = full_data[i: i+size]
if i == 0:
flow = data_i.groupby(['shop_id', 'time_stamp']).count().reset_index()
else:
flow = flow.append(data_i.groupby(['shop_id', 'time_stamp']).count().reset_index(), ignore_index=True)
# break
i = i + size
flow.describe

主要思路

好不容易做完load data的一步,已经浪费了不少时间和耐心了。后面对于如何预测时间序列又陷入了僵局。
按照以前的知识来说,这个问题就是一个回归问题嘛。但是每天的客流量又是一个时间序列,如何用机器学习的回归方法来预测一个时间序列,这个问题又很纠结。

大概百度下,时间序列的预测方法主要还是在金融,统计方面有广泛应用,很多用到statsmodel中的各种时间序列预测方法,但是那些时序算法是没有办法加入特征的,至少我是不知道如何加入特征,还要先对输入做取对数,平稳等预处理,当时就暂时先搁置了。

后来参考了往届音乐流行趋势比赛的经验,决定先用RF和XGBoost对每个商家建模,分别进行预测。

数据预处理

刚开始做还没有数据预处理的概念,大概就是碰到有缺失值,预测函数跑不起来的时候才想到要填充缺失值,做数据预处理。

缺失值处理对成绩还是有相当大的影响。刚开始就是最简单的用均值填充,后来用每周的均值来填充。也没有充分考虑哪种填充方法好。这方面的知识书本上也很少,却很重要,要多学习别人的方法。也想到应该用回归的预测值来填充,还要避免正常的客流低的点被填充进错误值,增加噪声,限于时间和能力,这些想法没能在比赛期间实现。

离群值的识别和处理也很重要,我用到最简单的方法就是直接把超出2*theta(标准差)范围的数据替换为阈值,简单粗暴,效果如何也不好说。标准的做法,应该使用模型的方法,判断离群点然后处理。结合这一步就可以把临近结束那几天有未营业的商家识别出来并处理,应该能够提高模型的准确度。

这个比赛里面用到主要就这两个,其他比如类别数据编码,等等影响不大就没有涉及。

特征工程

这一步是最关键的,但是没做过是真的体会不到。

刚开始就是想不到如何把日期信息转换为特征,卡了很久。后来从日期信息中提取到day, month, yeardayofweek, weekofyear等特征,其中dayofweek因为反应了序列的周期特性,在后面的模型中起到很大的作用。

时间序列的特征主要有趋势和周期两类,趋势特征就不是很好找。之前用了dayofweek.mean()的差分,但是与结果的相关性不高,甚至从加入这些特征之后成绩下滑了很多。如果用增长率或者其他值呢?

事实上要预测后一天的流量,将前两周内的每天作为特征,尤其临近几天的流量与结果相关程度很高,但是由于需要预测两周的数据,所以后面几天的特征就会缺失,这样就要考虑用迭代的方式每次预测一天,然后把预测值作为特征预测下一天,但是这样需要fit的模型数量就要*14, 限于时间没有做下去;另一个想法是尽量选用两周前的数据作为特征,避免特征缺失,这样的结果也不理想。

数据分割

如果线下评估的结果能和线上保持一致的话就可以尝试更多的改进,也能检验每次改动的优化程度。
一开始直接用from sklearn.cross_validation import train_test_split这是随机切出来的训练和测试集,预测结果较显示线上偏好,不能很好的反映实际情况。

后面采取的是将10.15~10.31作为测试集,基本能和线上一致。但是后面加了很多特征的时候出现了,线下结果好于线上的过拟合现象,主要还是趋势特征不够,模型预测的结果对近一点的效果更好,泛化能力不足。

模型

模型参考之前的经验选取了Random Forest和Gradient Boosting Decision Tree还有XGBoost以及Linear Regression作为参考。

在大部分结果中,RF的表现都要优于其他两种,但是每次的结果表现都不太一样。但是发现了一个问题就是,这几个模型除了LR其他的回归都不能直接做预测,比如输入和输出的关系是比较简单的线性关系,但是输入范围以外的预测值就是常数,不能像LR一样输出增长的序列。没有解决这个问题,模型在没有加入比较好的趋势特征时,预测能力就很有限。

调参没有做,因为本身每个商家的模型出来都是不一样的,分别调参不太可能,统一的参数设置对于成绩能有多少提升?我觉得还不足以帮助我的结果有可观的提升。

组合几种模型得出更好的结果,算是一种Bagging or Boost思想。但是之前没有操作过无从下手。
这次比赛中采用通过测试集计算loss,选取loss低的模型输出,这个步骤在前期也取得了一些进步。后面的混乱就没有办法得知效果了。

其实最后的阶段还尝试了分别拟合周期和趋势,XGB拟合dayofweek的周期信息,LR拟合趋势,两者相加,结果和均值差不多。做的不充分,这个思路应该能比一开始的结果好一些的。

赛后分析

比赛中以及结束后也接触到一些其他选手的做法。

群里有位用LR做到了0.85,也让我对数据和特征决定模型上限的说法有了新的认识。

考虑光棍节影响的做法,这个是我想都没想过的因素,这个人考虑了,貌似结果还不错,好像群里面做的比较高的了。

自称第七的大神,开源了一个改进过的kNN回归算法,好像我还没到那个层次。。。

3.23更新:

经过几天对stacking的学习,发现之前的工作只做到第一步。即用base learning machine对训练集的子集划分进行训练,这样得出的结果十分可能过拟合。之后应当再加入第二层回归,以shop_info…作为featrues, 同时加入第一层的预测结果作为特征训练模型,应当能有一些进步。

3.24更新:

昨天学习了异常值的简单检测和处理,有对问题有了新的理解。

如果使用回归方法对这个问题进行建模(不同于时间序列),是不需要把无营业记录的点作为缺失值进行填充的(这样会加入额外的噪声)。缺失值的概念还需要加深理解。比如缺失值填充时选择均值还是中位数或是众数,这些应该都有各自适合的数据情形,需要了解。

异常值可以通过删去与初步回归模型偏差最大的那些训练集(10%左右),可以减少异常值对模型的影响,增加泛化能力。

总结展望

后知后觉的发现这个比赛3.14就结束了,我一直以为还会有平台赛。。。

第一次参加这种比赛,学到了很多东西,也暴露出来不少问题。

问题

其实对于这次比赛的结果和过程我自己都是不太满意的,因为决定了秋招要找这方面的工作,没有相关项目,一个好看点的名次对找工作来说还是很重要的。

名次不好就算了,关键自己在处理问题,分析结果的环节也做的相当混乱,完全就是盲目的做,没有发挥出一点做科研,做实验的样子。开始提交的比较晚,每次提交包含的改动没有做好记录,控制变量,结果就是,不知道哪一步有提升,哪一步降低。

事实上真正学东西,做东西的时间也就开始两周,后面一周因为连续的成绩不理想基本丧失斗志了,从头再来以后,甚至没有办法复现最后的那次结果,这个是最失望的。

目前做的东西好像就只是掉包,知道每个函数的接口就行了,但是因为不知道原理,结果不是照自己预期的那样就不知道原因了,所以每个算法的原理还是要知道的。好像之前看的理论方面的知识没有怎么用到,是因为层次太低吗?以后多多尝试吧。

发现自己举一反三的那种能力丧失了,学完一个东西就是那样了,看到其他同学学习过程中能够利用学到的知识解决问题,这样才是真正的学习嘛。脑子这个东西不是省着用的,要经常锻炼。

交流沟通也是很重要的,如果有个队友,就算不是大腿,互相学习交流的结果也一定比自己蒙头做好的多。群里怎么才能问出干货呢?怎样利用这种交流平台解决自己的问题呢?这是需要锻炼的。

后续

通过这次比赛呢,还是决定要做这方面的工作了,因为觉得比较有意义,需求机会貌似也比较多。

但是现在这个水平去找工作基本就危险了,所以还是需要提高。具体通过这几个方面吧:

  • 补充一下基本知识,掌握整个数据挖掘的过程。书本上没有,就从Udacity上面看视频,做课程项目;
  • 多看别人的思路和代码,kaggle上面有很多开源的方法可以去学习参考;
  • 继续参加比赛:后续的KDD,CIKM的比赛也都开始了,这会时间也比较充裕,好好做吧。

总结

如果要把这次比赛经历写进简历要怎么写呢?

参加了xxx比赛,比赛需要利用一段时间的商家支付信息,预测未来时间的商家客流量。
通过提取日期信息中的dayofweek等特征反映周期信息,局部加权线性回归拟合趋势,结合两者预测结果。比赛结果进入排行榜前50%,400+/4000。
首次参加类似比赛,第一次完整的经历了数据挖掘的全过程,熟悉了利用python做数据分析所涉及到的相关工具,掌握了利用机器学习预测数据的一般步骤,对于数据的理解有了新的提高。

如果能看到这里的朋友一定很闲~欢迎批评指正,还有交流。