Spark機器學習(11):協同過濾算法
協同過濾(Collaborative Filtering,CF)算法是一種常用的推薦算法,它的思想就是找出相似的用戶或產品,向用戶推薦相似的物品,或者把物品推薦給相似的用戶。怎樣評價用戶對商品的偏好?可以有很多方法,如用戶對商品的打分、購買、頁面停留時間、保存、轉發等等。得到了用戶對商品的偏好,就可以給用戶推薦商品。有兩種方法:用戶A喜歡物品1,商品2和物品1很相似,於是把物品2推薦給用戶A;或者用戶A和用戶B很類似,B喜歡商品2,就將商品2推薦給用戶A。所以協同過濾分為兩類:基於用戶的協同過濾和基於物品的協同過濾。
1. 相似度的計算
協同過濾算法一個重要的問題就是相似度的計算,相似度即衡量兩個用戶,或者兩個物品之間相似的程度。計算相似度有幾種方法:同現相似度(Cooccurrence Similarity)、歐氏距離(Euclidean Distance)、皮爾遜相關系數(Pearson Correlarion Coefficient)、Cosine相似度(Cosine Similarity)、Tanimoto系數(Tanimoto Coefficient)等。
1.1 同現相似度(Cooccurrence Similarity)
同現,即同時出現的意思,物品i和物品j的同現相似度的計算公式是:
N(i)是喜歡物品i的用戶集合,N(j)是喜歡物品j的用戶集合,可以理解為喜歡物品i的用戶中有多少喜歡物品j。但是這樣存在一個問題,如果物品j是熱門物品,喜歡它的用戶肯定很多,這樣不論i是什麽物品,wij的值就會很大。為了避免這個問題的出現,對公式進行了改進:
這樣如果j是熱門物品,分母會很大,從而懲罰了wij的值。
1.2 歐氏距離(Euclidean Distance)
n維空間中兩個點x和y的距離:
當n=2時,是平面上兩點之間的距離,當n=3時,是立體空間上兩點之間的距離。相似度計算公式:
即距離越大,相似度越低;距離越小,相似度越高。當計算兩個物品的相似度時,坐標軸是不同的用戶,如果所有用戶對這兩個物品的偏好都差不多,那麽這兩個物品之間的距離就近,相似度就低,說明這兩個物品很相似;反之,則說明這兩個物品相似度低。
2. 推薦計算
推薦計算分為兩類:基於用戶的協同過濾和基於物品的協同過濾。
2.1 基於用戶的協同過濾(User CF)
基於用戶的協同過濾的基本思想是,對於每一個個用戶,根據他對所有物品的偏好,計算他與所有其他用戶的相似度(可以使用同現相似度或歐式距離),得到一個用戶相似度矩陣Um×m。用戶對物品的偏好評分矩陣Pm×n,U×P得到一個m×n矩陣,即對每個用戶,每個物品的偏好,過濾掉已經存在的用戶對商品的偏好,剩下的數據降序排序,即得到了一個推薦列表。
2.2 基於物品的協同過濾(Item CF)
基於物品的協同過濾的基本思想是,對於每一個個物品,根據所有用戶對它的偏好,計算它與所有其他物品的相似度(可以使用同現相似度或歐式距離),得到一個物品相似度矩陣In×n。P×I得到一個m×n矩陣,即對每個用戶,每個物品的偏好,過濾掉已經存在的用戶對商品的偏好,剩下的數據降序排序,即得到了一個推薦列表。
3. 協同過濾算法的實現
MLlib並沒有實現協同過濾算法,可以自己實現。
程序代碼:
/** * Created by Administrator on 2017/7/21. */ import org.apache.log4j.{ Level, Logger } import org.apache.spark.{ SparkConf, SparkContext } object ALSTest02 { def main(args:Array[String]) = { // 設置運行環境 val conf = new SparkConf().setAppName("Decision Tree") .setMaster("spark://master:7077").setJars(Seq("E:\\Intellij\\Projects\\MachineLearning\\MachineLearning.jar")) val sc = new SparkContext(conf) Logger.getRootLogger.setLevel(Level.WARN) // 讀取樣本數據並解析 val dataRDD = sc.textFile("hdfs://master:9000/ml/data/sample_itemcf3.txt") val userDataRDD = dataRDD.map(_.split(",")).map(f => (ItemPref(f(0), f(1), f(2).toDouble))).cache() // 建立模型 val simModel = new ItemSimilarity() val itemRDD = simModel.Similarity(userDataRDD, "cooccurrence") val recomm = new RecommendedItem val recommRDD = recomm.Recommend(itemRDD, userDataRDD, 30) // 輸出結果 println("物品相似度矩陣:") itemRDD.sortBy(f => (f.itemid1, f.itemid2)).collect.foreach { simItem => println(simItem.itemid1 + ", " + simItem.itemid2 + ", " + simItem.similar) } println("用戶推薦列表:") recommRDD.sortBy(f => (f.pref)).collect.foreach { UserRecomm => println(UserRecomm.userid + ", " + UserRecomm.itemid + ", " + UserRecomm.pref) } } }
運行結果:
物品相似度矩陣:
1, 2, 0.6666666666666666
1, 3, 0.6666666666666666
1, 5, 0.4082482904638631
1, 6, 0.3333333333333333
2, 1, 0.6666666666666666
2, 3, 0.3333333333333333
2, 4, 0.3333333333333333
2, 6, 0.6666666666666666
3, 1, 0.6666666666666666
3, 2, 0.3333333333333333
3, 4, 0.3333333333333333
3, 5, 0.4082482904638631
4, 2, 0.3333333333333333
4, 3, 0.3333333333333333
4, 5, 0.4082482904638631
4, 6, 0.6666666666666666
5, 1, 0.4082482904638631
5, 3, 0.4082482904638631
5, 4, 0.4082482904638631
5, 6, 0.4082482904638631
6, 1, 0.3333333333333333
6, 2, 0.6666666666666666
6, 4, 0.6666666666666666
6, 5, 0.4082482904638631
用戶推薦列表:
3, 1, 1.3333333333333333
6, 3, 1.8164965809277263
2, 4, 2.7079081189859817
1, 3, 3.0
5, 4, 3.666666666666666
3, 2, 3.6666666666666665
5, 5, 3.6742346141747673
6, 1, 3.8164965809277263
1, 5, 4.08248290463863
4, 5, 4.4907311951024935
3, 5, 4.4907311951024935
4, 3, 5.0
2, 6, 5.041241452319316
1, 4, 5.666666666666666
4, 1, 5.666666666666666
3, 6, 6.0
5, 6, 6.333333333333332
2, 2, 6.666666666666667
6, 2, 7.0
Spark機器學習(11):協同過濾算法