基于Spark构建推荐引擎之一:基于物品的协同过滤推荐

1、Spark构建推荐引擎之一:基于物品的协同过滤推荐

1.0 前言

目前SparkMLlib支持的推荐算法只有alternating least squares (ALS)这一种,相比较Mahout中的推荐算法,SparkMLlib目前不能支持目前的业务需求;因此,参照Mahout的推荐引擎,在Spark上构建同样一套推荐算法,以支持各种业务需求。

目前SparkMLlib官方网址:

http://spark.apache.org/docs/latest/mllib-guide.html


Mahout的推荐引擎的详细介绍参照:

http://blog.fens.me/mahout-recommend-engine/

 

1.1 数据输入模型

输入数据格式:

用户ID,物品ID,评分

用户输入数据模型:

 defUserData (

     sc:SparkContext,input:String,

     split:String

     ):(RDD[(String,String,Double)]) = {

     valuser_rdd1= sc.textFile(input,10)

     valuser_rdd2=user_rdd1.map(line=> {

     valfileds= line.split("split")

          (fileds(0),fileds(1),fileds(2).toDouble)

     })

     user_rdd2

  }

通过UserData可以获取用户评分RDD;

输入参数:sc是SparkContext,input就输入数据路径,split是数据分割符号。

 

1.2 相似度矩阵模型

 基于物品(ItemCF)的相似度算法:

1)同现相似度

2)欧氏距离相似度

3)余弦相似度

4)秩相关系数相似度

5)曼哈顿距离相似度

6)对数似然相似度

1.2.1 同现相似度矩阵

参照:《推荐系统实践》一书中的介绍:

公式定义:

基于Spark构建推荐引擎之一:基于物品的协同过滤推荐_第1张图片

实例:

基于Spark构建推荐引擎之一:基于物品的协同过滤推荐_第2张图片

同现相似度模型:根据用户评分数据表,生成物品的相似矩阵;

输入参数:user_rdd:用户评分表;

输出参数:余弦相似矩阵:物品1,物品2,相似度值;

同现相似度矩阵模型:

def Cooccurrence (

     user_rdd:RDD[(String,String,Double)]

     ) : (RDD[(String,String,Double)]) = {

   //  0 数据做准备

   valuser_rdd2=user_rdd.map(f => (f._1,f._2)).sortByKey()

   user_rdd2.cache  

   //  1 (用户:物品)笛卡尔积 (用户:物品) =>物品:物品组合    

   valuser_rdd3=user_rdd2joinuser_rdd2

   valuser_rdd4=user_rdd3.map(data=> (data._2,1))

   //  2 物品:物品:频次

   valuser_rdd5=user_rdd4.reduceByKey((x,y) => x + y)

   //  3 对角矩阵

   valuser_rdd6=user_rdd5.filter(f=> f._1._1 == f._1._2)

   //  4 非对角矩阵

   valuser_rdd7=user_rdd5.filter(f=> f._1._1 != f._1._2)

   //  5 计算同现相似度(物品1,物品2,同现频次)

   valuser_rdd8=user_rdd7.map(f=> (f._1._1, (f._1._1, f._1._2, f._2))).

   join(user_rdd6.map(f=> (f._1._1, f._2)))

   valuser_rdd9=user_rdd8.map(f=> (f._2._1._2, (f._2._1._1,

        f._2._1._2, f._2._1._3, f._2._2)))

   valuser_rdd10=user_rdd9.join(user_rdd6.map(f => (f._1._1, f._2)))

    val user_rdd11 = user_rdd10.map(f => (f._2._1._1,f._2._1._2,f._2._1._3,f._2._1._4,f._2._2))

   valuser_rdd12=user_rdd11.map(f=> (f._1, f._2, (f._3 / sqrt(f._4 * f._5)) ))

   //   6结果返回

   user_rdd12

  }

 

1.2.2 余弦相似度


原理:多维空间两点与所设定的点形成夹角的余弦值。

范围:[-1,1],值越大,说明夹角越大,两点相距就越远,相似度就越小。

余弦相似度模型:根据用户评分数据表,生成物品的相似矩阵;

输入参数:user_rdd:用户评分表;

输出参数:余弦相似矩阵:物品1,物品2,相似度值;

余弦相似度矩阵模型:

 defCosineSimilarity (

     user_rdd:RDD[(String,String,Double)]

     ) : (RDD[(String,String,Double)]) = {

   //  0 数据做准备

   valuser_rdd2=user_rdd.map(f => (f._1,(f._2,f._3))).sortByKey()

   user_rdd2.cache

   //  1 (用户,物品,评分)笛卡尔积 (用户,物品,评分) =>(物品1,物品2,评分1,评分2)组合      

   valuser_rdd3=user_rdd2joinuser_rdd2

   valuser_rdd4=user_rdd3.map(f=> ((f._2._1._1, f._2._2._1),(f._2._1._2, f._2._2._2)))

   //  2 (物品1,物品2,评分1,评分2)组合 => (物品1,物品2,评分1*评分2组合并累加      

   valuser_rdd5=user_rdd4.map(f=> (f._1,f._2._1*f._2._2 )).reduceByKey(_+_)

   //  3 对角矩阵

   valuser_rdd6=user_rdd5.filter(f=> f._1._1 == f._1._2)

   //  4 非对角矩阵

   valuser_rdd7=user_rdd5.filter(f=> f._1._1 != f._1._2)

   //  5 计算相似度

   valuser_rdd8=user_rdd7.map(f=> (f._1._1, (f._1._1, f._1._2, f._2))).

   join(user_rdd6.map(f=> (f._1._1, f._2)))

   valuser_rdd9=user_rdd8.map(f=> (f._2._1._2, (f._2._1._1,

        f._2._1._2, f._2._1._3, f._2._2)))

   valuser_rdd10=user_rdd9.join(user_rdd6.map(f => (f._1._1, f._2)))

    val user_rdd11 = user_rdd10.map(f => (f._2._1._1,f._2._1._2,f._2._1._3,f._2._1._4,f._2._2))

   valuser_rdd12=user_rdd11.map(f=> (f._1, f._2, (f._3 / sqrt(f._4 * f._5)) ))

   //  7 结果返回

   user_rdd12

  } 

 

1.2.3 欧氏距离相似度



原理:利用欧式距离d定义的相似度s,s=1 /(1+d)。

改进:

num = intersect(which(M[x,]!=0),which(M[y,]!=0))

d = sum((M[x,] - M[y,])^2,na.rm = T)

s = length(num)/(1 + sqrt(d))

范围:[0,1],值越大,说明d越小,也就是距离越近,则相似度越大。

欧式相似度模型:根据用户评分数据表,生成物品的相似矩阵;

输入参数:user_rdd:用户评分表;

输出参数:余弦相似矩阵:物品1,物品2,相似度值;

欧式相似度矩阵模型:

 def EuclideanDistanceSimilarity (

     user_rdd:RDD[(String,String,Double)]

     ) : (RDD[(String,String,Double)]) = {

   //  0 数据做准备

   valuser_rdd2=user_rdd.map(f => (f._1,(f._2,f._3))).sortByKey()

   user_rdd2.cache

   //  1 (用户,物品,评分)笛卡尔积 (用户,物品,评分) =>(物品1,物品2,评分1,评分2)组合      

   valuser_rdd3=user_rdd2joinuser_rdd2

   valuser_rdd4=user_rdd3.map(f=> ((f._2._1._1, f._2._2._1),(f._2._1._2, f._2._2._2)))

   //  2 (物品1,物品2,评分1,评分2)组合 => (物品1,物品2,评分1-评分2组合并累加      

   valuser_rdd5=user_rdd4.map(f=> (f._1,(f._2._1-f._2._2 )*(f._2._1-f._2._2 ))).reduceByKey(_+_)

   //  3 (物品1,物品2,评分1,评分2)组合 => (物品1,物品2,1组合并累加   计算重叠数

   valuser_rdd6=user_rdd4.map(f=> (f._1,1)).reduceByKey(_+_)

   //  4 非对角矩阵

   valuser_rdd7=user_rdd5.filter(f=> f._1._1 != f._1._2)

   //  5 计算相似度

   valuser_rdd8=user_rdd7.join(user_rdd6)

   valuser_rdd9=user_rdd8.map(f=> (f._1._1,f._1._2,f._2._2/(1+sqrt(f._2._1))))  

//   7 结果返回

user_rdd9

 } 

 

1.2.4 秩相关系数相似度

等待更新......

 

1.2.5 曼哈顿距离相似度

等待更新......

 

1.2.6 对数似然相似度

等待更新......

 

1.3 推荐算法模型

推荐模型:根据物品相似矩阵以及用户对物品的评分表,计算用户的推荐列表。

输入参数:items_similar物品相似矩阵,user_perf:用户评分表,r_number:推荐个数。

输出参数:用户推荐列表:用户ID,物品ID,得分。

 defRecommend (

     items_similar:RDD[(String,String,Double)],

     user_perf:RDD[(String,String,Double)],

     r_number:Int

     ) : (RDD[(String,String,Double)]) = {  

    //  1 矩阵计算——i行与jjoin

    valrdd_app1_R2=items_similar.map(f => (f._2, (f._1,f._3))).

    join(user_perf.map(f => (f._2,(f._1,f._3))))

    //  2 矩阵计算——i行与j列元素相乘

    valrdd_app1_R3=rdd_app1_R2.map(f=> ((f._2._2._1,f._2._1._1),f._2._2._2*f._2._1._2))

    //  3 矩阵计算——用户:元素累加求和

    valrdd_app1_R4=rdd_app1_R3.reduceByKey((x,y)=> x+y).map(f => (f._1._1,(f._1._2,f._2)))

    //  4 矩阵计算——用户:用户对结果排序,过滤

    valrdd_app1_R5=rdd_app1_R4.groupByKey()

    valrdd_app1_R6=rdd_app1_R5.map(f=> {

         val i2 = f._2.toBuffer

         val i2_2 = i2.sortBy(_._2)

         if (i2_2.length > r_number)i2_2.remove(0,(i2_2.length-r_number))

           (f._1,i2_2.toIterable)

    })

    valrdd_app1_R7=rdd_app1_R6.flatMap(f=> {

         val id2 = f._2     

         for (w <-id2)yield(f._1,w._1,w._2)

    })

    rdd_app1_R7

  }

 

1.4 评估算法模型

个性化推荐算法的通用评判标准:召回率(recall)与查准率(precision);

基于Spark构建推荐引擎之一:基于物品的协同过滤推荐_第3张图片

被检索到的越多越好,这是追求“查全率”,即A/(A+B),越大越好。被检索到的,越相关的越多越好,不相关的越少越好,这是追求“查准率”,即A/(A+C),越大越好。

评估算法模型

等待更新......

 

转载请注明出处:

http://blog.csdn.net/sunbow0/article/details/42737541


你可能感兴趣的:(spark,机器学习,协同过滤,个性推荐)