1,协同过滤算法的出现标志着推荐系统的产生,协同过滤算法包含基于用户的协同过滤算法和基于物品的协同过滤算法。
在探究推荐算法之前谈下向量之间的相似度,度量向量之间相似度的方法很多,可以用距离(各种距离)的倒数,向量夹角,Pearson相关系数等。
其中皮尔森相关系数的计算公式如下:
ρX,Y=cov(X,Y)/σxσy=E((X−μx)(Y−μy))/σxσy
分子是协方差,分母是两个变量标准差的乘积。显然要求X和Y的标准差都不能为0
因为μX=E(X),σ2X=E(X−μX)2=E(X2)−E2(X)
所以皮尔森相关系数计算公式还可以写成:
当两个变量的线性关系增强的时候,相关系数趋近于1或-1
Pearson 相关系数有个特点,它在计算两个数列的相似度的时候忽略平均值的差异。比如有的用户对商品评分普遍偏低,有的普遍偏高,而实际上他们爱好相同,他们的 Pearson相关系数会比较高,用户1对某三个个商品的评分为x=(1,2,3),用户2对这三个商品的评分是y=(4,5,6),则x和y的 Pearson相关系数是0.865,相关性还是挺高的
上面是用户评分数据矩阵
2,基于用户的协同过滤的探讨:
一:如果用户i对项目j没有评过分,就找到与用户i最相似的k个邻居(采用pearson相关系数)
二:然后用这个K个邻居对项目j的评分的加权平均来预测用户I对j的评分
U1=(r1,1,r1,2...r1,n)
U2=(r2,1,r2,2...r2,n)
要预测用户U对商品i的评分ru,i
用户u对所有商品的平均得分为ru
用户x评分的商品集合为Ix,用户y评分的商品集合为Iy,其并集为Ixy
采用Pearson相关系数可以求出用户x和y的相似度,然后根据相似度得出归一化因子
这各预测方法充分考虑了用户一向的评分习惯是偏高还是偏低,因为用户u的近邻对u产生影响时已经减去了各自的平均值。
计算用户U1和U2的相似度时并不是去拿原始的评分向量去计算,而是关注他们的评交集I,这是因为一个用户只对很少的物品有评分过,这样用户评分向量是个高度系数的矩阵向量,采用Pearson相关系数计算两个用户的相似度时很不准。
3,基于物品的协同过滤的探讨:
一:如果用户I对项目J没有评分过,就把对应的r设置为0,找到与物品j最相似的K个近邻(采用余弦距离)
二:然后用这K个邻居的评分的加权平均来预测用户I对项目J的评分
4,spark实现协同过滤:
- package test
- import akka.event.slf4j.Logger
- import com.sun.glass.ui.Window.Level
- import org.apache.spark.mllib.recommendation.Rating
- import org.apache.spark.streaming.{Seconds, StreamingContext}
- import org.apache.spark.{SparkConf, SparkContext}
- import org.apache.spark.mllib.recommendation.{ALS, Rating}
- import org.apache.spark.ml._
- import org.apache.spark.mllib.recommendation.ALS
- import org.apache.spark.mllib.recommendation.ALS
- import org.apache.spark.mllib.recommendation.MatrixFactorizationModel
- import org.apache.spark.mllib.recommendation.Rating
- /**
- * Created by zengxiaosen on 16/6/7.
- */
- object ALS_spark {
- def main(args: Array[String]) {
- val conf=new SparkConf()
- conf.setAppName("ALS")
- conf.setMaster("local")
- val sc=new SparkContext(conf)
- /*val data = sc.textFile( "/Users/zengxiaosen/test/xtgl.data" )
- /**
- * Product ratings are on a scale of 1-5:
- * 5: Must see
- * 4: Will enjoy
- * 3: It's okay
- * 2: Fairly bad
- * 1: Awful
- */
- val ratings=data.map(_.split(',') match {
- case Array(user,product,rate)=>Rating(user.toInt, product.toInt, rate.toDouble)
- })
- print(ratings.first())
- //使用ALC训练数据建立模型推荐
- val rank=12
- val numIterations=4
- val lambda = 0.01
- val users = ratings.map(_.user).distinct()
- val products = ratings.map(_.product).distinct()
- println( "Got " +ratings.count()+ " ratings from " +users.count+ " users on " +products.count+ " products." )
- val splits = ratings.randomSplit(Array( 0.8 , 0.2 ), seed = 111 )
- val training = splits( 0 )
- val test = splits( 1 )
- val model_test=*/
- //val model = ALS.train(ratings, rank, numIterations, 0.01)
- //(ratings, rank, numIterations, lambda)
- /*model.userFeatures
- model.userFeatures.count
- model.productFeatures
- model.productFeatures.count*/
- // Load and parse the data
- //val data = sc.textFile("data/mllib/als/test.data")
- val data = sc.textFile( "/Users/zengxiaosen/test/xtgl.data" )
- val ratings = data.map(_.split(',') match { case Array(user, item, rate) =>
- Rating(user.toInt, item.toInt, rate.toDouble)
- })
- // Build the recommendation model using ALS
- val rank = 10
- val numIterations = 10
- val model = ALS.train(ratings,rank,numIterations,0.01)
- // Evaluate the model on rating data
- val usersProducts = ratings.map { case Rating(user, product, rate) =>
- (user, product)
- }
- val predictions =
- model.predict(usersProducts).map { case Rating(user, product, rate) =>
- ((user, product), rate)
- }
- val ratesAndPreds = ratings.map { case Rating(user, product, rate) =>
- ((user, product), rate)
- }.join(predictions)
- val MSE = ratesAndPreds.map { case ((user, product), (r1, r2)) =>
- val err = (r1 - r2)
- err * err
- }.mean()
- println("Mean Squared Error = " + MSE)
- // Save and load model
- model.save(sc, "target/tmp/myCollaborativeFilter")
- //val sameModel = MatrixFactorizationModel.load(sc, "target/tmp/myCollaborativeFilter")
- }
- }
在调试spark的机器学习算法的时候,如果不是很熟悉spark,通常会遇到极大的阻力,而且sparksql目前作为一个查询计算引擎,还不具备丰富的机器学习功能,所以不太方便,下面来看协同过滤后产生的效果: