显式矩阵分解
当要处理的数据是由用户提供的自身的偏好数据,这些数据被称为显式偏好数据.包含用户ID,物品ID,评分.
将其转换为以用户为行,物品为列的二维矩阵,矩阵中的每个数据表示某个用户对某个物品的偏好值.通常用户看过或评价过的物品只有很少一部分,因此该矩阵是一个稀疏矩阵.
通过使用矩阵分解的方式进行降维,具体就是找出两个低纬度的矩阵,使其乘积是原有矩阵.
比如当前用户和物品的数目分别是U和I,对应的”用户-物品”矩阵为 U X I, 要找到和该矩阵近似的k维矩阵,最终要求出如下两个矩阵: 一个用于表示用户的 U X k维矩阵,一个用于表示物品的 I X k维矩阵.二者的乘积便是原始 “用户-物品”矩阵的近似,这两个矩阵称为因子矩阵,并且是稠密矩阵.
这类模型试图发现对应 “用户-物品” 矩阵内在行为结构的隐含特征(即因子矩阵),所以也被称为隐特征模型.隐含特征不能被直接解释,但他可能表示了某些含义,比如对某种物品的偏好.
由于是对”用户-物品”矩阵的直接建模,用这些模型进行预测也相对简单:要计算给定用户对某个物品的预计偏好值,就从用户因子矩阵和物品因子矩阵分别选取相应的行和列,然后计算两者点积.
物品之间相似度的计算,可以用近邻模型中用到的相似度计算,或者这里可以利用物品因子向量,将相似度计算转换为对两物品因子向量之间相似度的计算.
隐式矩阵分解
这类数据中,用户对物品的偏好值不会直接给出,而是隐含在用户与物品的交互中.比如二元数据(用户是否观看了电影)和计数数据(看了几次这部电影).
MLlib中实现的方法是,将输入的评级数据视为两个矩阵,一个二元偏好矩阵P,以及一个信心权重矩阵C.P中表示用户是否对该物品有偏好值,C中表示用户对该物品的偏好值程度(比如看了3次电影为3).
隐式模型仍然会创建一个用户因子矩阵和一个物品因子矩阵,但是模型所求解的是偏好矩阵而不是评级矩阵的近似.同样,此时用户因子向量和物品因子向量的点积得到的分数也不再是对一个评级的估值,而是某个用户对某个物品偏好值的估值.
最小二乘法(ALS)
是一种求解矩阵分解问题的最优方法,功能强大效果理想切利于并行化.其实现原理是迭代式求解一系列最小二乘回归问题,每一次迭代时,固定用户因子矩阵或物品因子矩阵中的一个,然后用固定的这个矩阵及评分数据来更新另一个矩阵,之后,被更新的矩阵被固定住,再更新另外一个矩阵.如此迭代,知道模型收敛(或是迭代到预设的次数).
提取有效特征
val rawData = sc.textFile("/PATH/ml-100k/u.data") // 加载数据
val rawRatings = rawData.map(_.split("\t").take(3)) // 提取需要的数据,用户,物品,偏好值
val ratings = rawRatings.map { // 将初始数据转化为 Rating对象构成的RDD
case Array(user, movie, rating) => Rating(user.toInt, movie.toInt, rating.toDouble)
}
训练推荐模型
训练模型时需要提供的参数:
- rank: 对应ALS模型中的因子参数,也就是在低阶近似矩阵中的隐含特征个数.一般越多越好,但会影响训练和保存时的内存开销,特表示用户物品量大,一般取10-200.
- iterations: 对应运行时的迭代次数.ALS能确保每次迭代都能降低评级矩阵的重建误差,但一般少数次迭代后ALS模型便已收敛为一个比较合理的好模型,一般为10次.
- lambda: 该参数控制模型的正则化过程.从而控制模型的过拟合情况,其值越高,正则化越厉害.参数大小与数据大小,特征和稀疏程度有关.一般通过非样本的测试数据进行交叉验证来调整.
训练模型:
val model = ALS.train(ratings, 50, 10, 0.01)
上述代码返回一个MatrixFactorizationModel对象,将对象因子和物品因子分别保存在一个(id,factor)对的RDD中,分别为userFeatures和productFeatures.
model.userFeatures
model.productFeatures
使用隐式反馈数据训练模型
训练隐式反馈数据时使用trainImplicit方法,调用方式多了一个可设置的alpha参数,是一个正则化参数.alpha参数指定了信心权重所应达到的基准线,该值越高则所训练出的模型越认为用户与他所没评级过的电影之间没有相关性.
使用推荐模型
MatrixFactorizationModel类提供了一个predict方法,以计算给定用户对物品的预计评分:
val predictedRating = model.predict(789, 123)
// predictedRating: Double = 3.128545693368485
predict方法同样可以使用(user,item)ID对类型的RDD对象作为输入,会得到对每一对的预测评分,以同时为多个用户和物品提供评分.
要为某个用户提供前K个物品的推荐,可以使用MatrixFactorizationModel类提供的recommendProducts方法.接收两个参数,user和num.
val userId = 789
val K = 10
val topKRecs = model.recommendProducts(userId, K)
Rating(789,715,5.931851273771102)
Rating(789,12,5.582301095666215)
Rating(789,959,5.516272981542168)
Rating(789,42,5.458065302395629)
Rating(789,584,5.449949837103569)
Rating(789,750,5.348768847643657)
Rating(789,663,5.30832117499004)
Rating(789,134,5.278933936827717)
Rating(789,156,5.250959077906759)
Rating(789,432,5.169863417126231)
同时根据用户原有的评分数据进行对比,以检验推荐结果.