Spark机器学习之协同过滤算法

    一)、协同过滤

      1.1 概念      

         协同过滤是一种借助"集体计算"的途径。它利用大量已有的用户偏好来估计用户对其未接触过的物品的喜好程度。其内在思想是相似度的定义

       1.2 分类

         1.在基于用户的方法的中,如果两个用户表现出相似的偏好(即对相同物品的偏好大体相同),那就认为他们的兴趣类似。要对他们中的一个用户推荐一个未知物品,

        便可选取若干与其类似的用户并根据他们的喜好计算出对各个物品的综合得分,再以得分来推荐物品。其整体的逻辑是,如果其他用户也偏好某些物品,那这些物品很可能值得推荐。

          2. 同样也可以借助基于物品的方法来做推荐。这种方法通常根据现有用户对物品的偏好或是评级情况,来计算物品之间的某种相似度。

               这时,相似用户评级相同的那些物品会被认为更相近。一旦有了物品之间的相似度,便可用用户接触过的物品来表示这个用户,然后找出和这些已知物品相似的那些物品,

               并将这些物品推荐给用户。同样,与已有物品相似的物品被用来生成一个综合得分,而该得分用于评估未知物品的相似度。

    二)、矩阵分解            

      Spark推荐模型库当前只包含基于矩阵分解(matrix factorization)的实现,由此我们也将重点关注这类模型。它们有吸引人的地方。首先,这些模型在协同过滤

      中的表现十分出色。而在Netflix Prize等知名比赛中的表现也很拔尖

      1,显式矩阵分解    

         要找到和“用户物品”矩阵近似的k维(低阶)矩阵,最终要求出如下两个矩阵:一个用于表示用户的U × k维矩阵,以及一个表征物品的I × k维矩阵。

         这两个矩阵也称作因子矩阵。它们的乘积便是原始评级矩阵的一个近似。值得注意的是,原始评级矩阵通常很稀疏,但因子矩阵却是稠密的。

         特点:

          因子分解类模型的好处在于,一旦建立了模型,对推荐的求解便相对容易。但也有弊端,即当用户和物品的数量很多时,其对应的物品或是用户的因子向量可能达到数以百万计。

          这将在存储和计算能力上带来挑战。另一个好处是,这类模型的表现通常都很出色。

       2,隐式矩阵分解(关联因子分确定,可能随时会变化)

        隐式模型仍然会创建一个用户因子矩阵和一个物品因子矩阵。但是,模型所求解的是偏好矩阵而非评级矩阵的近似。类似地,此时用户因子向量和物品因子向量的点积所得到的分数

        也不再是一个对评级的估值,而是对某个用户对某一物品偏好的估值(该值的取值虽并不严格地处于0到1之间,但十分趋近于这个区间)

       3,最小二乘法(Alternating Least Squares    ALS):解决矩阵分解的最优化方法

        ALS的实现原理是迭代式求解一系列最小二乘回归问题。在每一次迭代时,固定用户因子矩阵或是物品因子矩阵中的一个,然后用固定的这个矩阵以及评级数据来更新另一个矩阵。

        之后,被更新的矩阵被固定住,再更新另外一个矩阵。如此迭代,直到模型收敛(或是迭代了预设好的次数)。

    三)、Spark下ALS算法的应用

       1,数据来源电影集ml-100k

       2,代码实现

        基于用户相似度片段代码:       

val movieFile=sc.textFile(fileName)
val RatingDatas=movieFile.map(_.split("\t").take(3))
//转为Ratings数据
val ratings=RatingDatas.map(x =>Rating(x(0).toInt,x(1).toInt,x(2).toDouble))
//获取用户评价模型,设置k因子,和迭代次数,隐藏因子lambda,获取模型 val model=ALS.train(ratings,50,10,0.01)
//基于用户相似度推荐
println("userNumber:"+model.userFeatures.count()+"\t"+"productNum:"+model.productFeatures.count())
//指定用户及商品,输出预测值
println(model.predict(789,123))
//为指定用户推荐的前N商品
model.recommendProducts(789,11).foreach(println(_))
//为每个人推荐前十个商品
model.recommendProductsForUsers(10).take(1).foreach{
case(x,rating) =>println(rating(0))
}

       基于商品相似度代码:

    计算相似度的方法有相似度是通过某种方式比较表示两个物品的向量而得到的。常见的相似度衡量方法包括皮尔森相关系数(Pearson correlation)、针对实数向量的余弦相

似度(cosine similarity)和针对二元向量的杰卡德相似系数(Jaccard similarity)。

val itemFactory=model.productFeatures.lookup(567).head
val itemVector=new DoubleMatrix(itemFactory)
//求余弦相似度
val sim=model.productFeatures.map{
case(id,factory)=>
val factorVector=new DoubleMatrix(factory)
val sim=cosineSimilarity(factorVector,itemVector)
(id,sim)
}
val sortedsim=sim.top(11)(Ordering.by[(Int,Double),Double]{
case(id,sim)=>sim
})
println(sortedsim.take(10).mkString("\n"))
def cosineSimilarity(vec1:DoubleMatrix,vec2:DoubleMatrix):Double={
vec1.dot(vec2)/(vec1.norm2()*vec2.norm2())
}

     均方差评估模型代码:

//模型评估,通过均误差
//实际用户评估值
val actualRatings=ratings.map{
case Rating(user,item,rats) => ((user,item),rats)
}
val userItems=ratings.map{
case(Rating(user,item,rats)) => (user,item)
}
//模型的用户对商品的预测值
val predictRatings=model.predict(userItems).map{
case(Rating(user,item,rats)) =>((user,item),rats)
}
//联合获取rate值
val rates=actualRatings.join(predictRatings).map{
case x =>(x._2._1,x._2._2)
}
//求均方差
val regressionMetrics=new RegressionMetrics(rates)
//越接近0越佳
println(regressionMetrics.meanSquaredError)

      全局准确率评估(MAP)使用MLlib的 RankingMetrics 类来计算基于排名的评估指标。类似地,需要向我们之前的平均准确率函数传入一个键值对类型的RDD。

      其键为给定用户预测的推荐物品的ID数组,而值则是实际的物品ID数组。

//全局平均准确率(MAP)
val itemFactors = model.productFeatures.map { case (id, factor)
=> factor }.collect()
val itemMatrix = new DoubleMatrix(itemFactors)
//分布式广播商品的特征矩阵
val imBroadcast = sc.broadcast(itemMatrix)
//计算每一个用户的推荐,在这个操作里,会对用户因子矩阵和电影因子矩阵做乘积,其结果为一个表示各个电影预计评级的向量(长度为
//1682,即电影的总数目)
val allRecs = model.userFeatures.map{ case (userId, array) =>
val userVector = new DoubleMatrix(array)
val scores = imBroadcast.value.mmul(userVector)
val sortedWithId = scores.data.zipWithIndex.sortBy(-_._1)
val recommendedIds = sortedWithId.map(_._2 + 1).toSeq //+1,矩阵从0开始
(userId, recommendedIds)
}
//实际评分
val userMovies = ratings.map{ case Rating(user, product, rating) =>
(user, product)}.groupBy(_._1)
val predictedAndTrueForRanking = allRecs.join(userMovies).map{ case
(userId, (predicted, actualWithIds)) =>
val actual = actualWithIds.map(_._2)
(predicted.toArray, actual.toArray)
}
//求MAP,越大越好吧
val rankingMetrics = new RankingMetrics(predictedAndTrueForRanking)
println("Mean Average Precision = " + rankingMetrics.meanAveragePrecision)

    详细代码:

package com.spark.milb.study

import org.apache.log4j.{Level, Logger}
import org.apache.spark.mllib.evaluation.{RankingMetrics, RegressionMetrics}
import org.apache.spark.mllib.recommendation.{ALS, Rating}
import org.apache.spark.{SparkConf, SparkContext}
import org.jblas.DoubleMatrix /**
* Created by hadoop on 17-5-3.
* 协同过滤(处理对象movie,使用算法ALS:最小二乘法(实现用户推荐)
* 余弦相似度实现商品相似度推荐
*/
object cfTest {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
val conf=new SparkConf().setMaster("local").setAppName("AlsTest")
val sc=new SparkContext(conf)
CF(sc,"ml-100k/u.data")
}
def CF(sc:SparkContext,fileName:String): Unit ={
val movieFile=sc.textFile(fileName)
val RatingDatas=movieFile.map(_.split("\t").take(3))
//转为Ratings数据
val ratings=RatingDatas.map(x =>Rating(x(0).toInt,x(1).toInt,x(2).toDouble))
//获取用户评价模型,设置k因子,和迭代次数,隐藏因子lambda,获取模型
/*
*  rank :对应ALS模型中的因子个数,也就是在低阶近似矩阵中的隐含特征个数。因子个
数一般越多越好。但它也会直接影响模型训练和保存时所需的内存开销,尤其是在用户
和物品很多的时候。因此实践中该参数常作为训练效果与系统开销之间的调节参数。通
常,其合理取值为10到200。
iterations :对应运行时的迭代次数。ALS能确保每次迭代都能降低评级矩阵的重建误
差,但一般经少数次迭代后ALS模型便已能收敛为一个比较合理的好模型。这样,大部分
情况下都没必要迭代太多次(10次左右一般就挺好)。
lambda :该参数控制模型的正则化过程,从而控制模型的过拟合情况。其值越高,正则
化越严厉。该参数的赋值与实际数据的大小、特征和稀疏程度有关。和其他的机器学习
模型一样,正则参数应该通过用非样本的测试数据进行交叉验证来调整。
* */
val model=ALS.train(ratings,50,10,0.01)
//基于用户相似度推荐
println("userNumber:"+model.userFeatures.count()+"\t"+"productNum:"+model.productFeatures.count())
//指定用户及商品,输出预测值
println(model.predict(789,123))
//为指定用户推荐的前N商品
model.recommendProducts(789,11).foreach(println(_))
//为每个人推荐前十个商品
model.recommendProductsForUsers(10).take(1).foreach{
case(x,rating) =>println(rating(0))
}
//基于商品相似度(使用余弦相似度)进行推荐,获取某个商品的特征值
val itemFactory=model.productFeatures.lookup(567).head
val itemVector=new DoubleMatrix(itemFactory)
//求余弦相似度
val sim=model.productFeatures.map{
case(id,factory)=>
val factorVector=new DoubleMatrix(factory)
val sim=cosineSimilarity(factorVector,itemVector)
(id,sim)
}
val sortedsim=sim.top(11)(Ordering.by[(Int,Double),Double]{
case(id,sim)=>sim
})
println(sortedsim.take(10).mkString("\n"))
//模型评估,通过均误差
//实际用户评估值
val actualRatings=ratings.map{
case Rating(user,item,rats) => ((user,item),rats)
}
val userItems=ratings.map{
case(Rating(user,item,rats)) => (user,item)
}
//模型的用户对商品的预测值
val predictRatings=model.predict(userItems).map{
case(Rating(user,item,rats)) =>((user,item),rats)
}
//联合获取rate值
val rates=actualRatings.join(predictRatings).map{
case x =>(x._2._1,x._2._2)
}
//求均方差
val regressionMetrics=new RegressionMetrics(rates)
//越接近0越佳
println(regressionMetrics.meanSquaredError)
//全局平均准确率(MAP)
val itemFactors = model.productFeatures.map { case (id, factor)
=> factor }.collect()
val itemMatrix = new DoubleMatrix(itemFactors)
//分布式广播商品的特征矩阵
val imBroadcast = sc.broadcast(itemMatrix)
//计算每一个用户的推荐,在这个操作里,会对用户因子矩阵和电影因子矩阵做乘积,其结果为一个表示各个电影预计评级的向量(长度为
//1682,即电影的总数目)
val allRecs = model.userFeatures.map{ case (userId, array) =>
val userVector = new DoubleMatrix(array)
val scores = imBroadcast.value.mmul(userVector)
val sortedWithId = scores.data.zipWithIndex.sortBy(-_._1)
val recommendedIds = sortedWithId.map(_._2 + 1).toSeq //+1,矩阵从0开始
(userId, recommendedIds)
}
//实际评分
val userMovies = ratings.map{ case Rating(user, product, rating) =>
(user, product)}.groupBy(_._1)
val predictedAndTrueForRanking = allRecs.join(userMovies).map{ case
(userId, (predicted, actualWithIds)) =>
val actual = actualWithIds.map(_._2)
(predicted.toArray, actual.toArray)
}
//求MAP,越大越好吧
val rankingMetrics = new RankingMetrics(predictedAndTrueForRanking)
println("Mean Average Precision = " + rankingMetrics.meanAveragePrecision)
}
//余弦相似度计算
def cosineSimilarity(vec1:DoubleMatrix,vec2:DoubleMatrix):Double={
vec1.dot(vec2)/(vec1.norm2()*vec2.norm2())
}
}

Spark机器学习之协同过滤算法的更多相关文章

  1. 【机器学习笔记一】协同过滤算法 - ALS

    参考资料 [1]<Spark MLlib 机器学习实践> [2]http://blog.csdn.net/u011239443/article/details/51752904 [3]线性 ...

  2. Spark 基于物品的协同过滤算法实现

    J由于 Spark MLlib 中协同过滤算法只提供了基于模型的协同过滤算法,在网上也没有找到有很好的实现,所以尝试自己实现基于物品的协同过滤算法(使用余弦相似度距离) 算法介绍 基于物品的协同过滤算 ...

  3. Spark机器学习(11):协同过滤算法

    协同过滤(Collaborative Filtering,CF)算法是一种常用的推荐算法,它的思想就是找出相似的用户或产品,向用户推荐相似的物品,或者把物品推荐给相似的用户.怎样评价用户对商品的偏好? ...

  4. spark机器学习从0到1协同过滤算法 (九)

      一.概念 协同过滤算法主要分为基于用户的协同过滤算法和基于项目的协同过滤算法.   基于用户的协同过滤算法和基于项目的协同过滤算法 1.1.以用户为基础(User-based)的协同过滤 用相似统 ...

  5. Spark MLlib协同过滤算法

    算法说明 协同过滤(Collaborative Filtering,简称CF,WIKI上的定义是:简单来说是利用某个兴趣相投.拥有共同经验之群体的喜好来推荐感兴趣的资讯给使用者,个人透过合作的机制给予 ...

  6. 机器学习 | 简介推荐场景中的协同过滤算法,以及SVD的使用

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第29篇文章,我们来聊聊SVD在上古时期的推荐场景当中的应用. 推荐的背后逻辑 有没有思考过一个问题,当我们在淘宝或者是 ...

  7. Collaborative Filtering(协同过滤)算法详解

    基本思想 基于用户的协同过滤算法是通过用户的历史行为数据发现用户对商品或内容的喜欢(如商品购买,收藏,内容评论或分享),并对这些喜好进行度量和打分.根据不同用户对相同商品或内容的态度和偏好程度计算用户 ...

  8. 吴裕雄--天生自然HADOOP操作实验学习笔记:协同过滤算法

    实验目的 初步认识推荐系统 学会用mapreduce实现复杂的算法 学会系统过滤算法的基本步骤 实验原理 前面我们说过了qq的好友推荐,其实推荐算法是所有机器学习算法中最重要.最基础.最复杂的算法,一 ...

  9. GBDT(Gradient Boosting Decision Tree)算法&协同过滤算法

    GBDT(Gradient Boosting Decision Tree)算法参考:http://blog.csdn.net/dark_scope/article/details/24863289 理 ...

随机推荐

  1. Java基础一:面向对象的特征

    经过16年校招,自己在Java基础方面也算有了一个质的飞跃,从原来知其然,到现在知其所以然,现将学习心得总结于此. 首先需要知道类和对象是什么? 维基百科定义类为: an extensible pro ...

  2. JVM中GC浅解:垃圾回收的了解

    1.为什么要有GC 没有GC的世界,我们需要手动进行内存管理,但是内存管理是纯技术活,又容易出错.但是我们写码的目的是为了解决业务问题,所以可以把这种纯技术活自动化,当然自动化也是有代价的. 2.垃圾 ...

  3. iOS开发之应用沙盒

    1.应用沙盒概述 每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离.应用必须待在自己的沙盒里,其他应用不能访问该沙盒. 应用沙盒的文件系统目录,如下图所示(假设应用的名 ...

  4. MySql Table错误:is marked as crashed and last (automatic?) 和 Error: Table "mysql"."innodb_table_stats" not found

    一.mysql 执行select 的时候报Table错误:is marked as crashed and last (automatic?) 解决方法如下: 找到mysql的安装目录的bin/myi ...

  5. CSS -- 练习(待续优化)

    啊啊啊  错误百出啊 错点总结: 字符全角半角.清楚浮动.结尾</div>有点乱找不到对应的了.注释要写好. <!DOCTYPE html> <html lang=&qu ...

  6. javascript重修之书(一):如何判断变量的数据类型

    javascript重修之书(一):如何判断变量的数据类型 一:检测值类型 基本类型:(Undefined.Null.Boolean.Number和String) javascript之所以被称为一门 ...

  7. php中奖算法逻辑

    最近公司有两个活动, 一个是砸蛋活动, 另一个是转盘活动. 后台这边需要做接口进行对接,当用户在前台点击进行抽奖的时候,发送AJAX请求给后台,后台进行业务处理包括记录用户中奖信息,然后返回json格 ...

  8. 数位dp初步——数位dp的两种方式

    数位dp:一类统计区间[L,R]内某种符合规定的数字个数的题目.特征是R的范围会很大,O(N)范围内无法完成. 一般而言,解决这类题目有两种方式,一种是递推,另一种是记忆化搜索. 递推: 1)利用dp ...

  9. [转]android4.0.3 修改启动动画和开机声音

    本文转自:http://www.cnblogs.com/jqyp/archive/2012/03/07/2383973.html 1. Linux 系统启动,出现Linux小企鹅画面(reboot)( ...

  10. 静态数据的初始化(Chapter5.7.2)

    先初始化主类中的静态数据,如果要用其他类来定义对象,则初始化对应的其他类. 实例化对象时,先初始化定义为static的数据,接着调用父类的构造函数(如果有父类),再初始化定义为非static的数据,最 ...