构建基于Spark的推荐引擎(Python)

标签: 机器学习 大数据 python spark | 发表时间:2017-12-19 18:29 | 作者:NULL
出处:https://segmentfault.com/blogs

构建基于Spark的推荐引擎(Python)

推荐引擎背后的想法是预测人们可能喜好的物品并通过探寻物品之间的联系来辅助这个过程

在学习Spark机器学习这本书时,书上用scala完成,自己不熟悉遂用pyshark完成,更深入的理解了spark对协同过滤的实现

在这里我们的推荐模型选用协同过滤这种类型,使用Spark的MLlib中推荐模型库中基于矩阵分解(matrix factorization)的实现。

协同过滤(Collaborative Filtering)

协同过滤简单来说是利用某兴趣相投、拥有共同经验之群体的喜好来推荐用户感兴趣的信息,个人通过合作的机制给予信息相当程度的回应(如评分)并记录下来以达到过滤的目的进而帮助别人筛选信息,回应不一定局限于特别感兴趣的,特别不感兴趣信息的纪录也相当重要。

很简单的例子来介绍就是日常我们生活中经常找电影会通过向和自己品味类似的朋友要求推荐,这就是协同过滤的思想

基于用户的协同过滤推荐机制的基本原理

基于用户或物品的方法的得分取决于若干用户或是物品之间依据相似度所构成的集合(即邻居),故它们也常被称为最邻近模型。

协同过滤

矩阵分解

这里我们要处理的数据是用户提供的自身偏好数据,即用户对物品的打分数据。

这些数据可以被转换成用户为行,物品为列的二维矩阵,即评分矩阵A(m*n)表示m个用户对n个物品的打分情况

UI i1 i2 i3
u1 3.0 3.0 ?
u2 ? 2.0 4.0
u3 ? 5.0 ?

这个矩阵A很多元素都是空的,我们称其为缺失值(missing value)。

协同过滤提出了一种支持不完整评分矩阵的矩阵分解方法,不用对评分矩阵进行估值填充。

在推荐系统中,我们希望得到用户对所有物品的打分情况,如果用户没有对一个物品打分,那么就需要预测用户是否会对该物品打分,以及会打多少分。这就是所谓的矩阵补全(矩阵分解)

对于这个矩阵分解的方式就是找出两个低维度的矩阵,使得他们的乘积是原始的矩阵。

因此这也是一种降维技术。要找到和‘用户-物品’矩阵近似的k维矩阵,最终要求得出表示用户的m x k维矩阵,和一个表示物品的k x n维矩阵。
这两个矩阵也称作因子矩阵。

对于k的理解为对于每个产品,这里已电影为例,可以从k个角度进行评价,即k个特征值

图片描述

由于是对‘用户-物品’矩阵直接建模,用这些模型进行预测也相对直接,要计算给定用户对某个物品的预计评级,就从用户因子矩阵和物品因子矩阵分别选取对应的行与列,然后计算两者的点积。

假设对于用户A,该用户对一部电影的综合评分和电影的特征值存在一定的线性关系,

即电影的综合评分=(a1 d1+a2d2+a3 d3+a4d4)

其中a1-4为用户A的特征值,d1-4为之前所说的电影的特征值

最小二乘法实现协同

最小二乘法(Alternating Least Squares, ALS)是一种求解矩阵分解问题的最优化方法。它功能强大、效果理想而且被证明相对容易并行化。这使得它很适合如Spark这样的平台。

使用用户特征矩阵$ U(m*k) $ 中的第i个用户的特征向量$ u_i $ ,

和产品特征矩阵$ V(n*k) $第j个物品的特征向量$ v_i $来预测打分矩阵$ A(m*n) $中的$ a_{ij} $,

得出矩阵分解模型的损失函数如下

$$ \large C = \sum\limits_{(i,j)\in R}[(a_{ij} - u_iv_j^T)^2+\lambda(u_i^2+v_j^2)] $$


通常的优化方法分为两种:交叉最小二乘法(alternative least squares)和随机梯度下降法(stochastic gradient descent)。Spark使用的是交叉最小二乘法(ALS)来最优化损失函数。
算法的思想就是:我们先随机生成然后固定它求解,再固定求解,这样交替进行下去,直到取得最优解$ min(C) $

使用PySpark实现

我们这里的数据集是Movielens 100k数据集,包含了多个用户对多部电影的10万次评级数据

下载地址

读取评级数据集,该数据包括用户ID,影片ID,星级和时间戳等字段,使用/t分隔

通过sc.textFile()读取数据为RDD,通过分隔符取前3个属性分别为用户ID,影片ID,星级

  rawData = sc.textFile('/home/null/hadoop/data/ml-100k/u.data')
rawData.first()
type(rawData)
  pyspark.rdd.RDD



  rawRatings = rawData.map(lambda line: line.split("\t")[:3])
rawRatings.first()
  ['196', '242', '3']



  # 导入spark中的mllib的推荐库
import pyspark.mllib.recommendation as rd

生成Rating类的RDD数据

  # 由于ALS模型需要由Rating记录构成的RDD作为参数,因此这里用rd.Rating方法封装数据
ratings = rawRatings.map(lambda line: rd.Rating(int(line[0]), int(line[1]), float(line[2])))
ratings.first()
  Rating(user=196, product=242, rating=3.0)


训练ALS模型

  • rank: 对应ALS模型中的因子个数,即矩阵分解出的两个矩阵的新的行/列数,即$ A \approx UV^T , k << m,n $m,n中的k
  • iterations: 对应运行时的最大迭代次数
  • lambda: 控制模型的正则化过程,从而控制模型的过拟合情况。
  # 训练ALS模型
model = rd.ALS.train(ratings, 50, 10, 0.01)
model
  <pyspark.mllib.recommendation.MatrixFactorizationModel at 0x7f53cc29c710>



  # 对用户789预测其对电影123的评级
predictedRating = model.predict(789,123)
predictedRating
  3.1740832151065774



  # 获取对用户789的前10推荐
topKRecs = model.recommendProducts(789,10)
topKRecs
  [Rating(user=789, product=429, rating=6.302989890089658),
 Rating(user=789, product=496, rating=5.782039583864358),
 Rating(user=789, product=651, rating=5.665266358968961),
 Rating(user=789, product=250, rating=5.551256887914674),
 Rating(user=789, product=64, rating=5.5336980239740186),
 Rating(user=789, product=603, rating=5.468600343790217),
 Rating(user=789, product=317, rating=5.442052952711695),
 Rating(user=789, product=480, rating=5.414042111530209),
 Rating(user=789, product=180, rating=5.413309515550101),
 Rating(user=789, product=443, rating=5.400024900653429)]


检查推荐内容

这里首先将电影的数据读入,讲数据处理为电影ID到标题的映射

然后获取某个用户评级前10的影片同推荐这个用户的前10影片进行比较

  #检查推荐内容
movies = sc.textFile('/home/null/hadoop/data/ml-100k/u.item')
movies.first()
  '1|Toy Story (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Toy%20Story%20(1995)|0|0|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0'



  titles_data= movies.map(lambda line: line.split("|")[:2]).collect()
titles = dict(titles_data)
titles
  moviesForUser = ratings.keyBy(lambda rating: rating.user).lookup(789)
type(moviesForUser)
  list



  moviesForUser = sorted(moviesForUser,key=lambda r: r.rating, reverse=True)[0:10]
moviesForUser
  [Rating(user=789, product=127, rating=5.0),
 Rating(user=789, product=475, rating=5.0),
 Rating(user=789, product=9, rating=5.0),
 Rating(user=789, product=50, rating=5.0),
 Rating(user=789, product=150, rating=5.0),
 Rating(user=789, product=276, rating=5.0),
 Rating(user=789, product=129, rating=5.0),
 Rating(user=789, product=100, rating=5.0),
 Rating(user=789, product=741, rating=5.0),
 Rating(user=789, product=1012, rating=4.0)]



  [(titles[str(r.product)], r.rating) for r in moviesForUser]
  [('Godfather, The (1972)', 5.0),
 ('Trainspotting (1996)', 5.0),
 ('Dead Man Walking (1995)', 5.0),
 ('Star Wars (1977)', 5.0),
 ('Swingers (1996)', 5.0),
 ('Leaving Las Vegas (1995)', 5.0),
 ('Bound (1996)', 5.0),
 ('Fargo (1996)', 5.0),
 ('Last Supper, The (1995)', 5.0),
 ('Private Parts (1997)', 4.0)]



  [(titles[str(r.product)], r.rating) for r in topKRecs]
  [('Day the Earth Stood Still, The (1951)', 6.302989890089658),
 ("It's a Wonderful Life (1946)", 5.782039583864358),
 ('Glory (1989)', 5.665266358968961),
 ('Fifth Element, The (1997)', 5.551256887914674),
 ('Shawshank Redemption, The (1994)', 5.5336980239740186),
 ('Rear Window (1954)', 5.468600343790217),
 ('In the Name of the Father (1993)', 5.442052952711695),
 ('North by Northwest (1959)', 5.414042111530209),
 ('Apocalypse Now (1979)', 5.413309515550101),
 ('Birds, The (1963)', 5.400024900653429)]


推荐模型效果的评估

均方差(Mean Squared Error,MSE)

定义为各平方误差的和与总数目的商,其中平方误差是指预测到的评级与真实评级的差值平方

直接度量模型的预测目标变量的好坏

均方根误差(Root Mean Squared Error,RMSE)

对MSE取其平方根,即预计评级和实际评级的差值的标准差
  # evaluation metric
usersProducts = ratings.map(lambda r:(r.user, r.product))
predictions = model.predictAll(usersProducts).map(lambda r: ((r.user, r.product),r.rating))
predictions.first()
  ((316, 1084), 4.006135662882842)



  ratingsAndPredictions = ratings.map(lambda r: ((r.user,r.product), r.rating)).join(predictions)
ratingsAndPredictions.first()
  ((186, 302), (3.0, 2.7544572973050236))



  # 使用MLlib内置的评估函数计算MSE,RMSE
from pyspark.mllib.evaluation import RegressionMetrics
predictionsAndTrue = ratingsAndPredictions.map(lambda line: (line[1][0],line[1][3]))
predictionsAndTrue.first()
  (3.0, 2.7544572973050236)



  # MSE
regressionMetrics = RegressionMetrics(predictionsAndTrue)
regressionMetrics.meanSquaredError
  0.08509832708963357



  # RMSE
regressionMetrics.rootMeanSquaredError
  0.2917161755707653


参考:

相关 [spark 推荐引擎 python] 推荐:

构建基于Spark的推荐引擎(Python)

- - SegmentFault 最新的文章
构建基于Spark的推荐引擎(Python). 推荐引擎背后的想法是预测人们可能喜好的物品并通过探寻物品之间的联系来辅助这个过程. 在学习Spark机器学习这本书时,书上用scala完成,自己不熟悉遂用pyshark完成,更深入的理解了spark对协同过滤的实现. 在这里我们的推荐模型选用协同过滤这种类型,使用Spark的MLlib中推荐模型库中基于矩阵分解(matrix factorization)的实现.

大数据-推荐引擎

- - 人月神话的BLOG
推荐引擎在当前电商平台用的相当多,本文简单理解下常见的几张推荐方式. 首先说明下大数据用户画像可以用于针对性营销和单品推荐,但是即使没做用户画像也可以进行商品推荐. 推荐引擎是不是为不同的用户推荐不同的数据根据这个指标,推荐引擎可以分为基于大众行为的推荐引擎和个性化推荐引擎. 大众行为的推荐引擎,对每个用户都给出同样的推荐,这些推荐可以是静态的由系统管理员人工设定的,或者基于系统所有用户的反馈统计计算出的当下比较流行的物品.

初识推荐机制、推荐引擎

- 山河之外 - 互联网的那点事...
随着互联网的发展 估计大多数的产品都会遇到推荐机制的策划,作为互联网产品人员也需要研究一下推荐机制的核心算法,这篇文章是我看到的言简意赅讲了一些基础的推荐机制的文章,转过来分享给大家. 如今已经进入了一个数据爆炸的时代,随着 Web 2.0 的发展, Web 已经变成数据分享的平台,那么,如何让人们在海量的数据中想要找到他们需要的信息将变得越来越难.

从Web 2.0到推荐引擎2.0

- Race forward! - 学而时嘻之
(《新知客》,2010年9月). 互联网应用的新概念似乎总是层出不穷,然而相对于2005年前后中国一下子冒出来的一大批 web 2.0 网站和最近几年出现的“云计算”,此时此刻的互联网业界似乎有点沉闷. 人们开始谈论,互联网下一个有趣的事情是什么. 百姓网 CEO 王建硕,最近在《中国企业家》杂志发表文章《2011年注定是中国互联网第三春》,提出一个五年周期理论,认为每隔五年左右就会有一批人出来创业,就会有一批风险投资周转完毕转而支持新的项目,这样经过这两年的沉闷,2011年必将有新东西爆发.

协同过滤和推荐引擎

- - 刘思喆@贝吉塔行星
推荐系统在个性化领域有着广泛的应用,从技术上讲涉及概率、抽样、最优化、机器学习、数据挖掘、搜索引擎、自然语言处理等多个领域. 东西太多,我也不准备写连载,今天仅从基本算法这个很小的切入点来聊聊推荐引擎的原理. 推荐引擎(系统)从不同的角度看有不同的划分,比如:. 按照数据的分类:协同过滤、内容过滤、社会化过滤.

推荐引擎:信息逆流

- - 《商业价值》杂志
信息时代用户链接内容的方式将再次产生深刻变化,而这一变化的驱动者,正是推荐引擎技术. 如果回到20世纪80年代,面对一台当时的电脑,你很可能会不知所措. 原因很简单,当时要访问电脑内的内容——不管是软件或者游戏,你起码必须掌握基本的Dos命令. 换句话说,当时用户与内容链接的方式,是输入大量电脑“听得懂”的命令,再让电脑将其执行出来.

Spotify推荐引擎Discover Weekly的故事

- - Solidot
Spotify的软件工程师Edward Newett说,赋权自下而上的创新,奇迹将会发生. 他在上周举行的@Scale 会议上分享了开发Discover Weekly推荐引擎的故事. Discover Weekly设计帮助用户发现他们从未听过的新音乐,于一年前上线,至今已积累了4000多万的用户. Newett最初的工作是开发个性化网页,其中包含了向用户推荐他们可能感兴趣的专辑的系统.

探索推荐引擎内部的秘密:推荐引擎初探

- adow - 互联网的那点事...
“探索推荐引擎内部的秘密”系列将带领读者从浅入深的学习探索推荐引擎的机制,实现方法,其中还涉及一些基本的优化方法,例如聚类和分类的应用. 同时在理论讲解的基础上,还会结合 Apache Mahout 介绍如何在大规模数据上实现各种推荐策略,进行策略优化,构建高效的推荐引擎的方法. 本文作为这个系列的第一篇文章,将深入介绍推荐引擎的工作原理,和其中涉及的各种推荐机制,以及它们各自的优缺点和适用场景,帮助用户清楚的了解和快速构建适合自己的推荐引擎.

Spark概览

- - 简单文本
Spark具有先进的DAG执行引擎,支持cyclic data flow和内存计算. 因此,它的运行速度,在内存中是Hadoop MapReduce的100倍,在磁盘中是10倍. 这样的性能指标,真的让人心动啊. Spark的API更为简单,提供了80个High Level的操作,可以很好地支持并行应用.

Spark与Mapreduce?

- - 崔永键的博客
我本人是类似Hive平台的系统工程师,我对MapReduce的熟悉程度是一般,它是我的底层框架. 我隔壁组在实验Spark,想将一部分计算迁移到Spark上. 年初的时候,看Spark的评价,几乎一致表示,Spark是小数据集上处理复杂迭代的交互系统,并不擅长大数据集,也没有稳定性. 但是最近的风评已经变化,尤其是14年10月他们完成了Peta sort的实验,这标志着Spark越来越接近替代Hadoop MapReduce了.