猜你喜欢”推荐算法大赛冠军分享

最近在整理一些以往的比赛经验,下面这篇文章是我在DataCastle 参加“猜你喜欢”推荐算法大赛获得冠军的思路分享。

我是Yes,boy! ,来自东北大学计算机学院。在猜你喜欢推荐系统竞赛中,很幸运取得第一名的成绩,下面我简单介绍下我的思路。
本次比赛的赛题背景是给出了约3400万条数据,包含一个商品网站站内顾客在某一时刻对某一个商品的打分值,分值范围为1至5分。目的是通过对这些数据的学习和训练,准确预测未来某时刻某个用户对某个商品的评分。
通过背景可知这是一个关于推荐系统的研究问题。而推荐系统在预测准确度上有不同的研究方向,一种是基于TopN的研究,即主要是给用户一个个性化的推荐列表,一般通过准确率度量推荐的优劣;一种是基于评分预测的研究, 它的度量方式一般是RMSE或者MAE 。在本次比赛就是通过RMSE来评价预测的好坏。那么我们接下来要使用的方法就集中在优化评分预测的RMSE上。
在具体做的过程中,我觉得有几点需要注意的:
1. 分析数据,了解数据的大致规律
2. 方法先尝试简单方法,再尝试复杂方法;对复杂方法,要一点点的调整
基于此,我由简及繁使用了三类模型:
1. 基于聚类的推荐
2. 基于协同过滤的推荐
3. 基于模型学习的推荐
在这三类中,每一类又包含很多方法,不能绝对的说哪一类模型最好,依照具体的数据形式、数据内容而定。
第一类的模型我大概使用到的方法:
1. 全局均值
2. 物品均值
3. 用户均值
4. 用户分类-物品均值
5. 物品分类-用户均值
6. 用户活跃度
7. 物品活跃度
8. 改进的用户活跃度
9. 改进的物品活跃度

这类模型的共同特征是通过设计聚类方法来对用户和物品分类,利用同类用户对同类物品的评分均值来预测用户对物品的评分。另外通过该模型的实现对用户和商品的特征有一个基本的了解。

下面是其中一种方法(用户分类-物品均值)的代码:

import pandas as pd
import numpy as np

train = pd.read_csv('data/train.csv')
test = pd.read_csv('data/test.csv')

rate_rank = train.groupby('uid').mean().loc[:,['score']].iloc[:,-1]
rate_rank=pd.DataFrame(np.int32((rate_rank*2).values),index=rate_rank.index,columns=['group'])
rate_rank_des = rate_rank.reset_index()

train_plus = pd.merge(train,rate_rank_des,how='left',on='uid')
test_plus = pd.merge(test,rate_rank_des,how='left',on='uid')
res = train_plus.groupby(['iid','group']).mean().reset_index().loc[:,['iid','group','score']]
result6 = pd.merge(test_plus,res,how='left',on=['iid','group']).filllna(3.0)

第二类的模型我主要使用的方法是基于物品的协同过滤,它的核心思想是当预测用户对一个物品评分时,主要考虑与该物品最相似且用户已打过分的若干物品。所以在这其中相似度的度量方法尤其重要,包括欧氏距离、皮尔逊相似度度量、余弦相似度度量、改进的余弦相似度度量。(之所以不使用基于用户的协同过滤,是由于建立用户-用户的相似度矩阵过于巨大)

实现代码见 similarity.py 和Model4.py

第三类的模型使用的方法有:
1. SVD
2. NMF
3. RSVD
4. SVD++
5. SVDfeature
6. Libmf
7. Libfm
这一类模型的共同特点是矩阵分解。即对用户-物品评分矩阵分解成若干个小矩阵,目的是分解之后的矩阵乘积接近原始矩阵,于是也实现了对原始矩阵为空的值的预测。在这些方法中,比较重要的几个参数有:隐特征个数,随机梯度下降中的学习率,正则化参数,总迭代次数。具体在每个方法中这些参数的最优值也不尽相同。
具体介绍其中两个在本赛题上表现最好的模型:svdfeature 和 libfm
Svdfeature 是一个feature-based协同过滤和排序工具,由陈天启所在的上海交大Apex实验室开发,大名鼎鼎的xgboost 同样来自于他们。里面能够方便实现svd ,svd++ 等方法。在使用过程中,步骤如下:
1. 数据预处理:用户和物品的id 不是连续的,需要进行重新的映射,转换为从1至用户/物品个数这样的连续取值。
2. 数据格式转换:要转换为模型要求的格式
3. 为了存储空间和计算速度,最好再转换为二进制形式
4. 设置各类参数。
5. 预测
在主要参数如下设置的情况下,线上得分能达到7.86
base_score = 3 全局偏置
learning_rate = 0.005 学习率
wd_item ,wd_user =0.004 正则化参数
num_factor =4000 隐含特征个数

LibFM是专门用于矩阵分解的利器,尤其是其中实现了MCMC(Markov Chain Monte Carlo)优化算法,比常见的SGD优化方法精度要高,但运算速度要慢一些。LibFM中还实现了SGD、SGDA(Adaptive SGD)、ALS(Alternating Least Squares)等算法。
在这里面,也有很多参数和方法可以灵活设置,比如-dim 维度,-iter 迭代次数,-learning_rate 学习率,-method 优化方法,-task 任务类型,-validation验证集,-regular 正则化参数
数据处理方式和上面类似,主要设置参数如下,这个方法的最优线上结果是7.88
-iter 100 –dim 1,1,64 –method MCMC –task –r
除此以外, libmf 模型效果也不错,最优结果能达到7.85 。而基于scipy 的svd 和基于sklearn的NMF在小数据集上效果很好,数据量特别大的情况下效果不理想;也可能是我调参和优化不够好的问题。

关于融合
一种是采用联级融合,即使一种模型的预测结果作为下一个模型的输入,不过要同时调整下一个模型的目标函数。另外一种方法是模型加权融合,最简单的是线性融合,通过各个模型在验证集的结果和超参数优化方法Hyperopt 找到最佳的融合系数,然后在线上使用这些融合系数进行融合。

关于时间
时间的因素我一直没有使用,后来我读到过有在svd++ 中加入时间因素的资料,预计加入后能够提升模型效果。

由于比赛期间没有把思路整理成文档,赛后才开始总结自己的思路,有写的不明白的地方大家都可以提出来,然后在讨论中相互启发。

    原文作者:ToSouth
    原文地址: https://blog.csdn.net/u010414589/article/details/52185257
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞