当前位置: 代码迷 >> 综合 >> 基于Spark3的个性化推荐系统——理论知识
  详细解决方案

基于Spark3的个性化推荐系统——理论知识

热度:76   发布时间:2023-12-14 11:51:53.0

本博客整理自慕课网实战《基于Spark2.x的个性化推荐系统》

目录

  • 一.推荐系统的生态介绍
    • 1.生态概述
    • 2.常见问题
    • 3.效果评测
  • 二.协同过滤推荐算法原理
    • 1.基于用户的协同过滤
    • 2.基于物品的协同过滤
    • 3.基于模型的协同过滤
    • 4.缺失值填充
  • 三.ALS算法原理

一.推荐系统的生态介绍

在这里插入图片描述

1.生态概述

数据
在这里插入图片描述
算法

  • 基于关联的推荐算法:如购买鞋子的顾客,会有10%的顾客会买袜子。有Apriori算法和FP-Growth算法。
  • 基于内容的推荐算法:打标签(效率不高),文本相似度(TF-IDF算法),分类算法(KNN,决策树,朴素贝叶斯)。
  • 基于协同过滤的推荐算法
    • 基于用户的协同过滤:兴趣相近的用户会对同样的物品感兴趣。
    • 基于物品的协同过滤:推荐给用户内容相似的物品。

在这里插入图片描述

  • 基于模型的推荐算法:深度学习(属于机器学习的范畴)。
  • 基于混合的推荐算法:将以上的各种推荐算法加权或者分层,用户能得到更全面的推荐。

领域知识

在这里插入图片描述
UI
在这里插入图片描述

2.常见问题

冷启动

  • 用户冷启动(一个新用户怎么推荐?)
    • 根据用户注册信息(邮箱类别,电话类别)
    • 推荐热门的排行榜(比较常用)
    • 基于深度学习语义分析(分析用户名来判断男女)
    • 引导用户将自己的爱好表达出来(注册账号时让用户勾选自己的爱好)
    • 利用用户在社交媒体的信息(QQ登录)
  • 物品冷启动(一个新物品怎么推荐?)
    • 文本分析(分析标题等文本信息)
    • 主题模型(预先训练一个模型,然后对新物品进行分类处理)
    • 给物品打标签(自己手动写)
    • 推荐排行榜单

数据稀疏

主要在协同过滤算法中,兴趣相近的用户会对同样的物品感兴趣。会构建用户-物品矩阵,但这个矩阵是稀疏矩阵。

  • 降维(奇异值分解)
  • 对感兴趣的相似物品也感兴趣(数据填充)
  • 基于深度学习的语义理解模型(基于物品本身的信息)

不断变化的用户喜好

  • 对用户行为的存储有实时性
  • 算法要考虑到近期行为和长期行为
  • 不断挖掘用户的新爱好(扩大推荐结果多样性)

3.效果评测

模型离线实验
在训练集上训练和在测试集上预测,评测预测的效果。

预测准确度:RMSE,MAE

TopN推荐:个性化推荐列表,预测准确度:准确率 / 召回率。
在这里插入图片描述
覆盖率:是不是能够将所有物品都推荐给用户,而不是只推送热门的商品。

多样性,新颖性,惊喜度,信任度,实时性,健壮性。

A/B Test在线实验
在这里插入图片描述

用户调研

二.协同过滤推荐算法原理

1.基于用户的协同过滤

基于用户的协同过滤有以下几个缺点:
1. 如果用户量很大,计算量就很大
2. 用户-物品打分矩阵是一个非常非常非常稀疏的矩阵,会面临大量的null值
很难得到两个用户的相似性
3. 会将整个用户-物品打分矩阵都载入到内存,而往往这个用户-物品打分矩阵是一个非常大的矩阵

所以通常不太建议使用基于用户的协同过滤。

在这里插入图片描述
通过余弦相似度计算用户的相似度
余弦相似度的公式 : (A * B) / (|A| * |B|)

  • |A|和|B|的求解(对于用户1和用户2):
    22+3.22+022=3.77\sqrt[2]{2^2+3.2^2+0^2} = 3.77222+3.22+02 ?=3.77
    02+1.12+022=1.1\sqrt[2]{0^2+1.1^2+0^2} = 1.1202+1.12+02 ?=1.1
val dfScoreMod = df.rdd.map(x=>(x(0).toString,x(2).toString)).groupByKey() //按照用户id进行分组.mapValues(score=>math.sqrt(score.toArray.map(itemScore=>math.pow(itemScore.toDouble,2)).reduce(_+_) // ((物品a的打分)**2 + (物品b的打分)**2 .. (物品n的打分)**2))** 1/2)).toDF("userId","mod")
  • 不同用户对同一个物品的score情况表:
//这里目的是把两两用户都放到了同一张表里
val _df = df.join(_dfTmp,df("itemId") === _dfTmp("itemId")).where(df("userId") =!= _dfTmp("_userId")).select(df("itemId"),df("userId"),_dfTmp("_userId"),df("score"),_dfTmp("_score"))
  • A * B的求解(用户1和2的维度乘积 ):
    2×0+3.2×1.1+0×0=3.522\times 0 + 3.2\times1.1+0\times0 = 3.522×0+3.2×1.1+0×0=3.52
itemId   userId    _userId     score    _score
1        1         2           2        0
2        1         2           3.2      1.1
3        1         2           0        0// 两两向量的维度乘积并加总
import org.apache.spark.sql.functions._
val df_mol = _df.select(col("userId"),col("_userId"),(col("score") * col("_score")).as("score_mol") //用户a和用户b对各自对同一个物品打分的乘积
).groupBy(col("userId"),col("_userId"))
.agg(sum("score_mol"))  //加总
.withColumnRenamed("sum(score_mol)","mol"
)
  • 用户1和2的相似度:
    3.52/(3.77×1.1)=0.843.52 / (3.77\times 1.1) = 0.843.52/(3.77×1.1)=0.84
// 分子 / 分母
val cos_sim = sim.select(col("userId"),col("_userId"),(col("mol") /(col("mod") * col("_mod"))).as("cos_sim")
)

2.基于物品的协同过滤

算法步骤:

  • 计算用户物品打分矩阵
    在这里插入图片描述
    上方是原始表,通过将 itemId 这一列转成行,变成 用户-物品 的矩阵。

  • 计算物品相似度矩阵(两个物品同时被买的次数越多,相似度越高)
    在这里插入图片描述

  • 用户物品打分矩阵 * 物品相似度矩阵 = 推荐列表

在这里插入图片描述
原始表转化为 用户-物品 的矩阵:

val userItemTmp = userItemData.groupBy(col("userId")).pivot(col("itemId")).sum("vote")

物品相似度矩阵:

val rddTmp = userItemData.rdd.filter(x=>x.getFloat(2) > 0).map(x=>{
    (x.getString(0),x.getString(1))})

3.基于模型的协同过滤

在这里插入图片描述SVD分解(分成3个矩阵):
在这里插入图片描述
U和V都是正交矩阵,中间的是奇异值的对角矩阵。

作用:

  • 数据降维,解决数据稀疏(SVD的前提是基于稠密矩阵的,所以稀疏矩阵先进行缺值填充,再进行SVD分解)
  • 减少特征空间,去除数据噪声。

PMF分解(分成2个矩阵):
在这里插入图片描述

4.缺失值填充

固定值,均值,中位数,众数填充。

import org.apache.spark.ml.feature.Imputerval imputer = new Imputer().setInputCols(Array("rating")).setOutputCols(Array("out_rating")).setMissingValue(Float.NaN).setStrategy("mean")

三.ALS算法原理

特征值分解只适用于方阵。

奇异值分解适用于其他矩阵,但是计算复杂度高。

ALS算法是PMF算法在数值计算方面的应用。

在这里插入图片描述
误差 = 观察的评分矩阵 - 预测的评分矩阵

问题就转化成了求最优解。

在这里插入图片描述
使误差最小,加入了正则项,避免过拟合。

在迭代过程中,交替优化U和V,最小交替二乘法。

ALS算法的缺点:

  • 离线算法
  • 不能解决冷启动