推荐系统ALS矩阵分解

来源:互联网 发布:软件开发考试培训 编辑:程序博客网 时间:2024/04/20 06:42

思想类似线性回归做预测,大致如下

定义一个预测模型(数学公式),

然后确定一个损失函数,

将已有数据作为训练集,

不断迭代来最小化损失函数的值,

最终确定参数,把参数套到预测模型中做预测。

 

矩阵分解的预测模型是:

技术分享

损失函数是:

技术分享
我们就是要最小化损失函数,从而求得参数q和p。

 

矩阵分解模型的物理意义

技术分享

我们希望学习到一个P代表user的特征,Q代表item的特征。特征的每一个维度代表一个隐性因子,比如对电影来说,这些隐性因子可能是导演,演员等。当然,这些隐性因子是机器学习到的,具体是什么含义我们不确定。

学习到P和Q之后,我们就可以直接P乘以Q就可以预测所有user对item的评分了。



讲完矩阵分解推荐模型,下面到als了(全称Alternatingleast squares)。其实als就是上面损失函数最小化的一个求解方法,当然还有其他方法比如SGD等。

als论文中的损失函数是(跟上面那个稍微有点不同)

技术分享

每次迭代,

         固定M,逐个更新每个user的特征u(对u求偏导,令偏导为0求解)。

         固定U,逐个更新每个item的特征m(对m求偏导,令偏导为0求解)。

论文中是这样推导的

技术分享

这是每次迭代求u的公式。求m的类似。

 

为了更清晰的理解,这里结合spark的als代码讲解。

spark源码中实现als有三个版本,一个是LocalALS.scala(没有用spark),一个是SparkALS.scala(用了spark做并行优化),一个是mllib中的ALS。

 

本来LocalALS.scala和SparkALS.scala这个两个实现是官方为了开发者学习使用spark展示的,

mllib中的ALS可以用于实际的推荐。

但是mllib中的ALS做了很多优化,不适合初学者研究来理解als算法。

因此,下面我拿LocalALS.scala和SparkALS.scala来讲解als算法。

 

LocalALS.scala

    // Iteratively update movies then users    for (iter <- 1 to ITERATIONS) {      println(s"Iteration $iter:")      ms = (0 until M).map(i => updateMovie(i, ms(i), us, R)).toArray  //固定用户,逐个更新所有电影的特征      us = (0 until U).map(j => updateUser(j, us(j), ms, R)).toArray   //固定电影,逐个更新所有用户的特征      println("RMSE = " + rmse(R, ms, us))      println()    }

  //更新第j个user的特征向量  def updateUser(j: Int, u: RealVector, ms: Array[RealVector], R: RealMatrix) : RealVector = {    var XtX: RealMatrix = new Array2DRowRealMatrix(F, F) //F是隐性因子的数量    var Xty: RealVector = new ArrayRealVector(F)    // For each movie that the user rated 遍历该user评分过的movie.显然,这里默认该用户评分过所有电影,所以是0-M.实际应用求解,只需要遍历该用户评分过的电影.    for (i <- 0 until M) {      val m = ms(i)      // Add m * m^t to XtX 外积后 累加到XtX      XtX = XtX.add(m.outerProduct(m)) //向量与向量的外积:一个当作列向量,一个当作行向量,做矩阵乘法,结果是一个矩阵      // Add m * rating to Xty      Xty = Xty.add(m.mapMultiply(R.getEntry(i, j)))    }    // Add regularization coefficients to diagonal terms    for (d <- 0 until F) {      XtX.addToEntry(d, d, LAMBDA * M)    }    // Solve it with Cholesky 其实是解一个A*x=b的方程    new CholeskyDecomposition(XtX).getSolver.solve(Xty)  }

再结合论文中的公式

技术分享

其实代码中的XtX就是公式中左边红圈的部分,Xty就是右边红圈的部分。

同理,更新每个电影的特征m类似,这里不再重复。

SparkALS.scala

    for (iter <- 1 to ITERATIONS) {      println(s"Iteration $iter:")      ms = sc.parallelize(0 until M, slices)                .map(i => update(i, msb.value(i), usb.value, Rc.value))                .collect()      msb = sc.broadcast(ms) // Re-broadcast ms because it was updated      us = sc.parallelize(0 until U, slices)                .map(i => update(i, usb.value(i), msb.value, Rc.value.transpose()))                .collect()      usb = sc.broadcast(us) // Re-broadcast us because it was updated      println("RMSE = " + rmse(R, ms, us))      println()    }

SparkALS版本相对于LocalALS的亮点时,做了并行优化。LocalALS中,每个user的特征是串行更新的。而SparkALS中,是并行更新的。

 

 

参考资料:

《Large-scale Parallel Collaborative Filtering for the Netflix Prize》(als-wr原论文)

《Matrix Factorization Techniques for Recommender Systems》(矩阵分解模型的好材料)

https://github.com/apache/spark/blob/master/examples/src/main/scala/org/apache/spark/examples/LocalALS.scala

https://github.com/apache/spark/blob/master/examples/src/main/scala/org/apache/spark/examples/SparkALS.scala


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 皮包上有火锅味怎么办 芝士年糕裂开了怎么办 制作牛肉酱咸了怎么办 腌牛肉太咸了怎么办 八宝粥的拉环断了怎么办 八宝粥易拉罐拉环断了怎么办 吃完辣的胃难受怎么办 天天呆在家很烦怎么办 吃多了荔枝上火怎么办 猛犸牙牌子裂了怎么办 玩游戏电脑卡了怎么办 电脑打开卡在选项界面怎么办? 红警突然卡死怎么办 柯基不吃狗粮怎么办 貔貅嘴巴磕破了怎么办 开光貔貅牙磕了怎么办 玉貔貅鼻子碎了怎么办 开光的貔貅摔坏了怎么办 貔貅摔坏了耳朵怎么办? 貔貅摔坏了一点点怎么办 天猫删评价扣4分怎么办 暴风影音下载电视剧下载不了怎么办 fm2017引援电脑买了怎么办 退休时医保不够二十年怎么办 和的面迟迟不发怎么办 做面条的面发了怎么办 发不起来的面团怎么办 如果婚后买房离婚后财产怎么办 空腹体检前喝水了怎么办 莆田市风俗婴儿死了怎么办后事 上司给你换不好岗位怎么办 领导要把我调走怎么办 美国上庭遇法官退休案子怎么办 夫妻一套房离婚户囗怎么办 正营生不了副团怎么办 浅色衣服被染色了怎么办 解大便解不出来怎么办 强拆挖掘机被村民扣押怎么办 小孩哭的时候接不上气怎么办 昆明市长信箱发不出去怎么办 中国公民在香港想去澳门怎么办