Spark ML协同过滤推荐算法

一.简介

  协同过滤算法【Collaborative Filtering Recommendation】算法是最经典、最经常使用的推荐算法。该算法经过分析用户兴趣,在用户群中找到指定用户的类似用户,综合这些类似用户对某一信息的评价,造成系统关于该指定用户对此信息的喜爱程度预测。算法

二.步骤

  1.收集用户偏好。apache

  2.找到类似的用户或物品。ide

  3.计算推荐。idea

三.用户评分

  从用户的行为和偏好中发现规律,并基于此进行推荐,因此收集用户的偏好信息成为系统推荐效果最基础的决定因素。spa

  数据预处理:日志

    1.减噪code

      由于用户数据在使用过程当中可能存在大量噪声和误操做,因此须要过滤掉这些噪声。blog

    2.归一化rem

      不一样行为数据的差异比较大,经过归一化,数据归于大体均衡,计算时才能减小异常数据产生的影响。文档

  组合不一样用户行为方式:

    1.将不一样的行为分组

    2.对不一样行为进行加权

四.类似度计算

  对用户的行为分析获得用户的偏好后,能够根据用户的偏好计算类似用户和物品,而后能够基于类似用户或类似物品进行推荐。咱们能够将用户对全部物品的偏好做为一个矩阵来计算用户之间的类似度,或者将全部用户对物品的偏好做为一个矩阵来计算物品之间的类似度。

  1.同现类似度

    指在喜好物品A的前提下,喜好物品B的几率。当物品B喜好率较高时可使用(A交B)/sqrt(A或B)。

  2.欧式距离

    1/(1+d(x,y))

    备注:d(x,y) 欧式距离

  3.皮尔逊相关系数

    皮尔逊相关系数通常用于计算两个定距变量间联系的紧密程度,它的取值为【-1~1】之间。

   4.Cosine类似度【余弦类似度】

    Cosine类似度普遍应用于计算文档数据的类似度。

  5.Tanimoto系数

    Tanimoto系数也被称为Jaccard系数,是Cosine类似度的扩展,也多用于计算文档数据的类似度。

五.代码实现

 1 package big.data.analyse.ml  2 
 3 import _root_.breeze.numerics.sqrt  4 import org.apache.log4j.{Level, Logger}  5 import org.apache.spark.{SparkContext, SparkConf}  6 import org.apache.spark.rdd.RDD  7 
 8 /**
 9  * 用户评分  10  * @param userid 用户  11  * @param itemid 物品  12  * @param pref 评分  13   */
 14 case class ItemPref(val userid : String,val itemid : String, val pref : Double) extends Serializable  15 
 16 /**
 17  * 类似度  18  * @param itemid_1 物品  19  * @param itemid_2 物品  20  * @param similar 类似度  21   */
 22 case class ItemSimilar(val itemid_1 : String, val itemid_2 : String, val similar : Double) extends Serializable  23 
 24 /**
 25  * 给用户推荐物品  26  * @param userid 用户  27  * @param itemid 物品  28  * @param pref 推荐系数  29   */
 30 case class UserRecommend(val userid : String, val itemid : String, val pref : Double) extends Serializable  31 
 32 /**
 33  * 类似度计算  34   */
 35 class ItemSimilarity extends Serializable{  36   def Similarity(user : RDD[ItemPref], stype : String) : RDD[ItemSimilar] = {  37     val similar = stype match{  38       case "cooccurrence" => ItemSimilarity.CooccurenceSimilarity(user) // 同现类似度  39       //case "cosine" => // 余弦类似度  40       //case "euclidean" => // 欧式距离类似度
 41       case _ => ItemSimilarity.CooccurenceSimilarity(user)  42  }  43  similar  44  }  45 }  46 
 47 object ItemSimilarity{  48   def CooccurenceSimilarity(user : RDD[ItemPref]) : (RDD[ItemSimilar]) = {  49     val user_1 = user.map(r => (r.userid, r.itemid, r.pref)).map(r => (r._1, r._2))  50     /**
 51  * 内链接,默认根据第一个相同字段为链接条件,物品与物品的组合  52       */
 53     val user_2 = user_1.join(user_1)  54 
 55     /**
 56  * 统计  57       */
 58     val user_3 = user_2.map(r => (r._2, 1)).reduceByKey(_+_)  59 
 60     /**
 61  * 对角矩阵  62       */
 63     val user_4 = user_3.filter(r => r._1._1 == r._1._2)  64 
 65     /**
 66  * 非对角矩阵  67       */
 68     val user_5 = user_3.filter(r => r._1._1 != r._1._2)  69 
 70     /**
 71  * 计算类似度  72       */
 73     val user_6 = user_5.map(r => (r._1._1, (r._1._1,r._1._2,r._2)))  74       .join(user_4.map(r => (r._1._1, r._2)))  75 
 76     val user_7 = user_6.map(r => (r._2._1._2, (r._2._1._1, r._2._1._2, r._2._1._3, r._2._2)))  77       .join(user_4.map(r => (r._1._1, r._2)))  78 
 79     val user_8 = user_7.map(r => (r._2._1._1, r._2._1._2, r._2._1._3, r._2._1._4, r._2._2))  80       .map(r => (r._1, r._2, (r._3 / sqrt(r._4 * r._5))))  81 
 82     user_8.map(r => ItemSimilar(r._1, r._2, r._3))  83  }  84 }  85 
 86 class RecommendItem{  87   def Recommend(items : RDD[ItemSimilar], users : RDD[ItemPref], number : Int) : RDD[UserRecommend] = {  88     val items_1 = items.map(r => (r.itemid_1, r.itemid_2, r.similar))  89     val users_1 = users.map(r => (r.userid, r.itemid, r.pref))  90 
 91     /**
 92  * i行与j列join  93       */
 94     val items_2 = items_1.map(r => (r._1, (r._2, r._3))).join(users_1.map(r => (r._2, (r._1, r._3))))  95 
 96     /**
 97  * i行与j列相乘  98       */
 99     val items_3 = items_2.map(r => ((r._2._2._1, r._2._1._1), r._2._2._2 * r._2._1._2)) 100 
101     /**
102  * 累加求和 103       */
104     val items_4 = items_3.reduceByKey(_+_) 105 
106     /**
107  * 过滤已存在的物品 108       */
109     val items_5 = items_4.leftOuterJoin(users_1.map(r => ((r._1, r._2), 1))).filter(r => r._2._2.isEmpty) 110     .map(r => (r._1._1, (r._1._2, r._2._1))) 111 
112     /**
113  * 分组 114       */
115     val items_6 = items_5.groupByKey() 116 
117     val items_7 = items_6.map(r => { 118       val i_2 = r._2.toBuffer 119       val i_2_2 = i_2.sortBy(_._2) 120       if(i_2_2.length > number){ 121         i_2_2.remove(0, (i_2_2.length - number)) 122  } 123  (r._1, i_2_2.toIterable) 124  }) 125 
126     val items_8 = items_7.flatMap(r => { 127       val i_2 = r._2 128       for(v <- i_2) yield (r._1, v._1, v._2) 129  }) 130 
131     items_8.map(r => UserRecommend(r._1, r._2, r._3)) 132  } 133 } 134 
135 /**
136  * Created by zhen on 2019/8/9. 137   */
138 object ItemCF { 139  def main(args: Array[String]) { 140     val conf = new SparkConf() 141     conf.setAppName("ItemCF") 142     conf.setMaster("local[2]") 143 
144     val sc = new SparkContext(conf) 145 
146     /**
147  * 设置日志级别 148       */
149  Logger.getRootLogger.setLevel(Level.WARN) 150 
151     val array = Array("1,1,0", "1,2,1", "1,4,1", "2,1,0", "2,3,1", "2,4,0", "3,1,0", "3,2,1", "4,1,0", "4,3,1") 152     val cf = sc.parallelize(array) 153 
154     val user_data = cf.map(_.split(",")).map(r => (ItemPref(r(0), r(1), r(2).toDouble))) 155 
156     /**
157  * 创建模型 158       */
159     val mySimilarity = new ItemSimilarity() 160     val similarity = mySimilarity.Similarity(user_data, "cooccurrence") 161 
162     val recommend = new RecommendItem() 163     val recommend_rdd = recommend.Recommend(similarity, user_data, 30) 164 
165     /**
166  * 打印结果 167       */
168     println("物品类似度矩阵:" + similarity.count()) 169     similarity.collect().foreach(record => { 170       println(record.itemid_1 +","+ record.itemid_2 +","+ record.similar) 171  }) 172 
173     println("用户推荐列表:" + recommend_rdd.count()) 174     recommend_rdd.collect().foreach(record => { 175       println(record.userid +","+ record.itemid +","+ record.pref) 176  }) 177  } 178 }

六.结果

  

相关文章
相关标签/搜索