2015阿里移动推荐算法比赛第一赛季总结

2015-05-17

第一赛季是在四月底结束,分数还凑合,过了9.00%。本文只是一篇总结性的文章。

发现的问题:
1、还是学的不怎么样
2、了解的不够深入,实战经验少
3、PRML和NG的视频都没看,不算好好学过机器学习
4、论文看得太少
5、没人指点
6、机器设备太差
7、比赛参加的有点晚,中间还出去溜达了几天
8、单人作战很酸爽~

比赛题目

官方提供了两个文本文件,第一个是tianchi_mobile_recommend_train_user.csv

user_id,item_id,behavior_type,user_geohash,item_category,time
99512554,37320317,3,94gn6nd,9232,2014-11-26 20
9909811,266982489,1,,3475,2014-12-02 23
......

每一行代表了用户user_id对属于分类cat_id的物品item_idtime这个时间于地点user_geohash发生了交互,交互类型是behavior_typebehavior_type包括浏览、收藏、加购物车、购买,对应取值分别是1、2、3、4。tianchi_mobile_recommend_train_user.csv中的数据约有1200万行。

一共有31天的交互数据,最后要预测地32天有哪些user会购买哪些item。 举办方对你提交的数据计算F1,并进行排名。

然而,还有一个商品子集的文件tianchi_mobile_recommend_train_item.csv

item_id,item_geohash,item_category
327414838,,11991
169831798,,7876
320523991,,3370
......

这个文件约有44万条数据,是tianchi_mobile_recommend_train_user.csv中出现的item的一个子集。官方的第32天的会发生购买的user, item中的item都是这个文件中的item,所以我们预测的user, item需要根据这个文件来过滤掉一些结果。

基本思路

这个预测,可以考虑预测发生过交互行为user, item会不会在第32天购买,也可以预测没有发生过交互行为user, item会不会在第32天购买。笔者这一次只考虑了发生过交互行为user, item。我们要有一份自己的训练集和测试集来评估自己的模型(算法),当觉得自己的模型比较好了,就可以拿着模型去预测了。

清洗数据

比如去除总的交互次数很低(低于2或者低于3或者…)的user, item,去除最后10天没有发生交互的user, item。还可以继续删除,比如双12的所有数据。不过删多了可不一定好。

特征工程

一个简单算法在精心选择的特征上的效果比一个漂亮的算法在较差的特征上的效果还要好。

如何构造特征很重要,特征构造得好,同一算法下准确率也可以提升很多。个人认为构造特征是这次比赛中最重要的任务。

Iris数据集为例,其默认提供了4个特征:花萼和花瓣的长度和宽度。对此我们可以构造更多的特征,例如花萼宽度/花萼长度花萼宽度/花瓣长度花萼宽度×花萼长度等等,只要觉得合理,就可以构造。

另外,特征的优劣会影响到一些机器学习算法的效果,或者特征太多机器会跑不动。筛选特征可能会成为一个很重要的步骤。假设现在有100个有标号的样本,每个样本10个特征,可以通过下面几种方法:

方法1: 拿出两个特征对应的两个100维的向量,使用pearson相关系数、归一化互信息量等方法计算两个特征的相关性,如果相关性很高,可以考虑删除其中一个特征。

方法2: 利用决策树的内置的特征筛选方法筛选好的特征

方法3:特征递归消除。可以参考http://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.RFE.html

scikit-learn库提供了多个特征选择的方法,点这里

也可以考虑降维。点这里

那么,一个user, item可以构造什么特征呢?

以前30天的所有数据为例(第31天有没有购买当作target): 最后一天user有没有购买item、最后的4天user有没有购买item、最后的4天user有没有点击item、最后的4天user对item的点击量、最后的4到8天user对item的点击量,最后的4天user的点击量,最后的4天item的的点击量,最后的4天item的的购买量除最后的4天item的的点击量…… 去年比赛的PPT中都讲到了这些。 另外,geohash也可以拿来生成特征,例如判断用户的最新位置和item最近的位置有多近;cat_id也可以考虑一下。再开个脑洞,将user, item的构造的某些特征进行聚类,样本所属的簇、样本离某个簇心的距离等也可以当作该样本的新特征。

训练集和测试集的构造

基于上面的内容,现在可以构造训练集和测试集了。

  • 新数据集1: 将1-27天的数据拿出来做特征,第28天作为target。 -> 用于训练
  • 新数据集2: 将2-28天的数据拿出来做特征,第29天作为target。 -> 用于训练
  • 新数据集3: 将3-29天的数据拿出来做特征,第30天作为target。 -> 用于训练
  • 新数据集4: 将4-30天的数据拿出来做特征,第31天作为target。 -> 用于测试
  • 新数据集5: 将5-31天的数据拿出来做特征。 -> 用于最终的预测。

正负样本比例问题: 对于上面生成的一个数据集,正例(target是购买)的数量只是几千,而负例上百万。只能说太不平衡了,不适合做训练集。可以这样做:将多个数据集的正例放在一起以增加正例数量;对负例进行随机采样。可以考虑生成多个训练集来观察模型的稳定性。

如何评估模型:新数据集4做测试,其实只需要把新数据集4其中的正例拿出来,计算F1即可。如果这个F1做的比较好了,可以认为提交结果的F1也会很好。

分类还是回归?

很明显,这是一个二分类问题。不过如果只看做二分类,会出一些问题。举办方那边有约500条数据(从第32天的实际购买user, item抽取出来的)来计算参赛者提交数据的F1,如果你只预测了100个user, item 或者预测了2000条user, item,这些数据并不适合提交上去,提交的比较好的数据量是400~1200之间。

利用回归来解决是个不错的思路。基于回归的预测结果可以简单看成user会购买item的概率,概率越高,购买的可能性越大。通过设置一个阈值就可以得到任意数量的提交结果了。

机器学习库、机器学习方法

网上能找到很多机器学习库,例如scikit-learn、Spark MLlib、Apache Mahout、R等。

上两个网址:
InfoQ:机器学习的11个开源项目
知乎:请问学习机器学习有哪些好工具推荐呢?

scikit-learn支持很多机器学习方法,列举一二:

Logistic Regression:分类器,predict_proba()函数可以当作回归来使用。

决策树 - 分类

决策树 - 回归

随机森林 - 分类

随机森林 - 回归

GBDT - 分类

GBDT - 回归

Spark 的机器学习库MLlib提供的方法也不少,可以进入Machine Learning Library (MLlib) Guide了解一下。

只用1个算法去预测的队伍应该挺多,也可以考虑多个经典机器学习算法融合到一起(Ensemble learning)。

参数调优
每个模型都有很多参数,参数的选择也会影响到最后的效果。思路:

1、手动调参数;
2、枚举一些参数值,一个个测试;
3、遗传算法、粒子群算法等。

方差和偏差问题

训练后的模型测试的效果很差,叫做高偏差,这往往意味着模型太简单。解决方法是:增加更多特征、使用别的模型、使用更复杂的模型等。

同一模型,用随机采样的多个数据集训练并测试的多个结果相差很大,叫做高方差,这往往意味着模型太复杂,导致了过拟合。解决方法是:使用更多数据、降低模型复杂度等。

单机还是集群?

这次比赛数据量偏大,要不加内存,要不用集群。

提交多少数据?

同一模型、同一训练集得到的预测结果,通过阈值可以得到不同数量的结果,提交1000条结果和提交600条结果的F1分数可能差距很大,提交600条结果和提交560条结果的F1分数也可能差距很大。如果模型做得足够好的话,提交400~1000条数据都能得到很好的F1分数;如果模型方面到瓶颈了,就需要好好考虑提交多少条数据比较好了。

其他工具

使用MapReduce对数据做预处理。
存储基本特征、中间结果等考虑使用数据库(MySQL或者MongoDB)。

如何查找作弊现象

想了想,可以是下面的一些方法:
1、两个队伍提交的数据完全相同(先排序,再求编辑距离)
2、两个队伍提交时使用的IP相同,但是不同的队伍可能用同一个代理
3、一个浏览器提交了多个队伍的数据(在浏览器中加入cookie)
4、实名认证
5、提交代码,代码查重

总结

收获很多,自己在机器学习这方面还有很大进步空间。

学习并使用了Spark的MLlib。

( 完 )