前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自己动手写推荐系统

自己动手写推荐系统

作者头像
机器学习AI算法工程
发布2018-03-13 10:10:45
8570
发布2018-03-13 10:10:45
举报

在下面介绍的做推荐系统的流程中,我只是想给大家介绍个普通的推荐系统该怎么做,所以很多地方都有偷懒,还请大家见谅。而且由于我不是做的在线的推荐系统,而是属于隔天推荐的那种离线的,所以叙述工程的时候就是只叙述离线的推荐。 数据准备: 一般来说,做推荐系统的数据一般分两种,一种从在线的读取,比如用户产生一个行为,推荐系统就反应下(传说豆瓣fm就是这么做的?),还有一种就是从数据库里读。

我个人一般是这样做的:跟做反作弊的人打个招呼,让他们在记用户行为数据的时候顺便存到各个线上服务器上,再写个php脚本,从各个服务器上把我需要的日志抓过来,然后当日要的最新的数据就来了。

但是这种地方其实存储的数据是加了一些判断的,也就是说是分类记录的(因为很多记录是别人刷的,比如丢一个链接到qq群里让别人帮忙投票什么的),这里不细说,到后面fighting spam的地方再讨论。 数据过滤: 当我们得到了每天产生的数据后,说实在这些数据实在是太多了,我们当然用不到这么多,就要写个过滤模块,把一些我们用不到的数据过滤掉。

我一般是这样做的:写个python的脚本,把过滤器放到一个单独的模块,要用的过滤器就到责任链里面注册下。这样别人和自己维护起来也方便点,顺便一说,过滤的东西一般来说有这样几种:一种是一个item只有一个user打过分的,而且以前没有人打分的,这样的数据放到推荐的模型里去跑虽然mahout会自动无视它,但其实按照power law来说是有不少的,内存能省就省吧;还有一种是有些黑名单的,有item和user各自的黑名单,这些也是事先要去掉的。 数据存储: 这个就是大家仁者见仁,智者见智的时候了,因为一般来说,是你选用的算法和算法具体的实现方式以及基础架构决定了你的存储方式,就不多说了。 我一般是这样做的:一般做成增量处理的方式,然后每天一计算,一周一回滚。由于算法实现的特殊性,每40个item user对存储在一起,有点类似于bitmap吧。 推荐系统算法部分: 这部分以前写过类似的小记录和心得笔记之类的东西,就直接贴了_(:з」∠)_ 这里的推荐系统的核心算法主要用mahout实现。 各种算法对于推荐都有着自己的特定的假设,对于什么时候什么样的算法会有比较好的performance应该对于假设反复验证。说白了就是做实验。 然后我们一般用什么算法呢,看看mahout给的算法吧,花样繁多,什么item based,user based,slop-one,SVD等等,常用的都有了,那我们要用什么算法呢。 先简单说下user based的算法在mahout中的一些实现:

第一步应该先算出所有人的相似度矩阵W,再去对于item进行遍历,事实上mahout也是这样做的。

相似度矩阵也许可以保留下来,这样可以用来做谱聚类来验证。 UserSimilarity 封装了用户之间的相似性 UserSimilarity similarity = new PearsonCorrelationSimilarity (model); UserNeighborhood封装了最相似的用户组 UserNeighborhood neighborhood = new NearestNUserNeighborhood (2, similarity, model);

总而言之,用DataModel来生成data model,用UserSimilarity生成User-user之间的相似度矩阵,用户的邻居的定义用UserNeighborhood定义,推荐引擎使用Recommender实现。 对于推荐的评判是使用evaluator来进行评判 double score = evaluator.evaluate(recommenderBuilder, null, model, 0.95, 0.05); 用95%的数据构建模型,用5%的数据进行test Fixed-size neighborhoods 对于到底用多少人作为用户周围的一圈,我们事实上没有一个确定的值,就像做生物实验一样需要不断在特定的数据集里跑出来。 Threshold-based neighborhood 当然,我们也可以定义个threshold去找出最相似的用户群。 Threshold定义为-1到1(相似度矩阵返回的相似度就是在这个范围) new ThresholdUserNeighborhood(0.7, similarity, model) 我们对于各个算法做个简单的比(吐)较(槽): (假设我们是要像亚马逊一样对商品做推荐,然后我们最终是要做top k的推荐) Item based 一般来说item-based要跑得快一些,因为item比user少 Slop one 说实在话我觉得在对于一些个人品味比较看重的东西上这个算法不是很靠谱 但是它在GroupLens 10 million数据的结果是0.65 当然,对于股票系统这种还是可取的 这个算法的假设是对于不同item的preference有种线性关系 不过slope-one有个好处是它的online算的很快,并且它的性能不由用户的数量决定 。 在mahout中的调用方法是new SlopeOneRecommender(model) 这个方法提供了两种weight:weighting based on count and on standard deviation count 是越多的user的给越多的权重,对出的是一个加权的平均数 , standard deviation则是越低的deviation给予越高的权重 , 这两个weight是默认采用的,当然disable它们只会让结果变得稍微坏一点0.67 不过这个算法有个很明显的缺点是比较占内存 , 但是幸运的是我们可以把它存在数据库里:MySQLJDBCDataModel Singular value decomposition–based recommenders 事实上,尽管SVD失去了一些信息,但是有时候它可以改善推荐的结果。 这个过程在有用的方式平滑了输入 。 new SVDRecommender(model, new ALSWRFactorizer(model, 10, 0.05, 10)) 第一个参数10是我们的目标属性个数 ,第二个属性是lambda->regularization 最后一个参数是training step跑的次数 Linear interpolation item–based recommendation KnnItemBasedRecommender 囧,事实上这个是用的knn的方式来做的算法,和前面的选择一个threshold然后圈画用户的算法是比较像的, 但是用knn代价是非常高的,因为它要去比较所有的items的对 ItemSimilarity similarity = new LogLikelihoodSimilarity(model); Optimizer optimizer = new NonNegativeQuadraticOptimizer(); return new KnnItemBasedRecommender(model, similarity, optimizer, 10); 结果也还不算差,是0.76 Cluster-based recommendation 基于聚类的推荐可以说是基于用户的推荐的算法的变体中最好的一种思路 对于每一个聚类里面的用户进行推荐 ,这个算法在推荐里面是非常快的,因为什么都事先算好了。 这个算法对于冷启动还是挺不错的 。 感觉mahout里面用的聚类算法应该类似于Kmeans? TreeClusteringRecommender UserSimilarity similarity = new LogLikelihoodSimilarity(model); ClusterSimilarity clusterSimilarity = new FarthestNeighborClusterSimilarity(similarity); return new TreeClusteringRecommender(model, clusterSimilarity, 10); 注意的是两个cluster之间的相似度是用ClusterSimilarity来定义的 其中cluster之间的相似度还有NearestNeighborClusterSimilarity可选 对于算法的选择,其实我们是要和我们要推荐的目标挂钩的。为什么最近学术界搞SVD那一系的算法这么火,什么LDA,plsa各种算法层出不穷,事实上因为netflix的要求是要优化RMSE,在机器学习的角度来看,类似于回归问题,而工业界的角度来说,我们一般的需求是做top k的推荐,更加类似于分类问题。所以为什么相比用SVD系列的算法,用item based这种更加ad hoc的算法要表现的更好一些。当然2012年的KDD cup第一名的组用的是item based+SVD的算法,这是后话。 那么我就假设解我们这个top k的商品推荐的问题就用item based好了(速度快,结果又不算差),接下来就是确定相似度了。 相似度确定: 我们对于各个相似度做一些比(吐)较(槽): PearsonCorrelationSimilarity (-1, 1)越是相似,就越接近1,不相似就是0,相反接近-1 Pearson correlation: coeff = corr(X , Y); function coeff = myPearson(X , Y) % 本函数实现了皮尔逊相关系数的计算操作 % % 输入: % X:输入的数值序列 % Y:输入的数值序列 % % 输出: % coeff:两个输入数值序列X,Y的相关系数 % if length(X) ~= length(Y) error('两个数值数列的维数不相等'); return; end fenzi = sum(X .* Y) - (sum(X) * sum(Y)) / length(X); fenmu = sqrt((sum(X .^2) - sum(X)^2 / length(X)) * (sum(Y .^2) - sum(Y)^2 / length(X))); coeff = fenzi / fenmu; end %函数myPearson结束 当两个变量的标准差都不为零时,相关系数才有定义,皮尔逊相关系数适用于: (1)、两个变量之间是线性关系,都是连续数据。 (2)、两个变量的总体是正态分布,或接近正态的单峰分布。 (3)、两个变量的观测值是成对的,每对观测值之间相互独立。 1.没有考虑到用户偏好重合的items的数量 2,只有一个item是相交错的话是不能得到correlation的,对于比较稀疏或者小的数据集这是个要注意的问题。不过一般来说两个用户之间只有一个item重叠从直觉上来说也不那么相似 Pearson correlation一般出现在早期的推荐的论文和推荐的书里,不过并不总是好的。 在mahout中使用了一个增加的参数Weighting.WEIGHTED,适当使用可以改善推荐结果 EuclideanDistanceSimilarity Return 1 / (1 + d) CosineMeasureSimilarity 当two series of input values each have a mean of 0(centered)时和PearsonCorrelation是有相同结果的 所以在mahout中我们只要简单的使用PearsonCorrelationSimilarity就好 Spearman correlation 这个方法用rank的方式,虽然失去了具体的打分信息,不过却保留了item的order Return的结果是-1和1两个值,不过和pearson一样,对于只有一个item重叠的也算不出。 而且这个算法比较慢,因为它要算和存储rank的信息。所以paper多而实际用的少,对于小数据集才值得考虑 CachingUserSimilarity UserSimilarity similarity = new CachingUserSimilarity( new SpearmanCorrelationSimilarity(model), model); Ignoring preference values in similarity with the Tanimoto coefficient TanimotoCoefficientSimilarity 如果一开始就有preference value,当数据中signal比noise多的时候可以用这个方法。 不过一般来说有preference信息的结果要好。 log-likelihood Log-likelihood try to access how unlikely 这些重叠的部分是巧合 结果的值可以解释为他们的重合部分并不是巧合的概念 算法的结果可能比tanimoto要好,是一个更加聪明的metric Inferring preferences 对于数据量比较小的数据,pearson很难handle,比如一个user只express一个preference 于是要估计相似度么......... AveragingPreferenceInferrer setPreferenceInferrer(). 不过这种办法在实际中并不是有用的,只是在很早的paper中mention到 通过现在的信息来估计并不能增加什么东西,并且很大的降低了计算速度 最终我们要通过实验来比较上面的相似度,一般来说是用准确率,召回率,覆盖率评测。 其实算法按流派分是分为下面这些类别的,大家有兴趣也可以了解下,我这里就不多做介绍: Similarity-based methods Dimensionality Reduction Techniques Dimensionality-based methods Diffusion-based methods Social fltering Meta approaches

我上面所说的相似度和推荐算法,只能算是Similarity-based methods和Dimensionality Reduction Techniques里的非常小的一小部分,只当抛砖引玉了。

Ps:刚在豆瓣上问了下,他们说就用前两种,事实上我也是觉得协同过滤+SVD 偶尔做做topic model就够了 如果没事干再上点social trusted的东西 增加规则: 记得hulu在做presentation的时候说过“不能做规则定制的推荐系统不是一个好的推荐系统”(好像是这样吧......)事实上我们做出来的推荐的结果是需要做很多处理再展现给用户的,这时候就是需要增加规则的时候了。

改善推荐效果:

有些协同过滤的算法,做出来的结果不可避免的产生一些让人啼笑皆非的结果,比如用户什么都买,导致你有可能跟姑娘们推荐的时候在佛祖下面推荐泳装什么的(真实的故事)。这时候就有两种办法,一种就是调整模型,一种就是增加规则做一定的限制。再举个常见的例子就是有时候会在推荐冬装的时候出现夏装什么的,这时候一般我的处理方式是给这种季节性商品做一个随时间的衰退。

增加广告和导向:

插入广告,我们的最爱,这个就不多说了,靠规则。而所谓用户喜欢的,其实不一定就是最好的,比如用户一般来说就喜欢便宜的,还有什么韩流爆款之流,如果你推出来的东西都是这样的,整个系统就变成洗剪吹大集合了,非常影响定位,这时候也要上规则。 做一些数据挖掘和fighting spam的工作:这个在fighting spam的地方细说 可视化参数调整: 做完上面的工作,一般来说推荐系统的基础架构就差不多了,但是往往各个算法以及你自己上的规则都有多如牛毛的参数要调整,这时候一般要自己写个测试脚本,将调整的结果可视化下一下,我个人推荐的是highchart,看参数以及比较各个指标非常清爽, 还可以自己做一些比如是取log之类的定制,很是方便。 http://www.highcharts.com/

调整参数以及上线: 上线前有两个事要做,一般来说就是离线测试和AB test。 离线测试就是把数据抽样一部分,分为train data和test data,然后评估一些准确率,召回率以及coverage之类的指标,用上面的可视化工具观测比较下,感觉差不多了把pm叫过来让她给小编们看看,看看审美和效果之类的。这是比较粗糙的,有的地方做的比较过细,还有用户调研和请一些人来实际使用,这是后话。

AB test也是大家最喜欢的地方了。因为说实在,评估推荐系统学术界是看准确率那一些东西,但是工业界还是看pv uv转化率这种实打实带来效益的东西,而AB test就是评估这些的。我个人是比较推荐这种方法,说不上好,只是抛砖引玉,就是按一般的做法先空跑一个星期,然后再把系统上线实际做算法pk,然后选取的实验用户一半的几率进入原来的算法的推荐,一半的几率进入你的算法的推荐,每天看看转化率之间的比较,顺便还可以调下参数做做实验。如果算法稳定表现较好,就差不多了。 Fighting spam: 俗话说,有人的地方就有江湖,有推荐的地方就有人刷。刷子一般分三种类型的:average random和nuke。一般来说,average和random比较好对付,只要你的系统鲁棒性好点,基本影响不大。但是nuke的就非常烦,一般来说有两种思路解决,一种是提高系统鲁棒性,另外就是上规则。我们从这张图看看两种思路分布对应的解决效果:

其实鲁棒性的系统做的就是把efficient attack的曲线降低,其实效果不算太好。 规则就是做到提前检测,将危险扼杀在摇篮之中,就是做的蓝色的那块detectable的部分。

Fighting spam是个博大精深的问题,俗话说,与人斗,其乐无穷,就是说的这个意思。

我们从规则说来,一般来说规则可以放到最前面的数据收集和过滤的阶段,比如在收集数据的时候看看这个人是否是多个账号但是是一个ip,或者有些人用户名或者注册邮箱有群体相似性质,或者有没有出现pv等不正常的情况。有时候我们也可以从推荐的结果里上规则来查,比如有些人刷的过火了,导致推荐结果出现一些问题,我们就可以用迭代的方式按照先验的刷子的比例来排出刷子排行榜之类的东西。这些都是经验之谈,上不了台面,大家也可以自己摸索。 大体上做一个完整的简单推荐系统就是涉及到上面这些步骤。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-10-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大数据挖掘DT数据分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档