推荐系统算法—协同过滤算法详解


协同过滤简单来说是利用某兴趣相投、拥有共同经验之群体的喜好来推荐用户感兴趣的信息。具体的又分为基于用户的协同过滤(User Collaboration Filter)和基于商品的协同过滤(Item Collaboration Filter)

基于用户的协同过滤(UserCF)

基本思想

基于用户的协同过滤推荐的基本原理是,根据所有用户对物品的偏好,发现与当前用户口味和偏好相似的‘“邻居” 用户群,并推荐近邻所偏好的物品。

在一般的应用中是采用计算“K近邻”的算法;基于这K个邻居的历史偏好信息,为当前用户进行推荐。

如下图所示:
在这里插入图片描述

用户c喜欢物品喜欢物品ACD,用户a喜欢物品喜欢物品AC,通过算法计算发现也用户a与用户c十分相似,于是猜测用户a也喜欢物品D,于是将D物品推送给用户a。

例子

(1)基本数据:假设用户对电影的评分情况如下,称之为评分矩阵

用户/电影电影1电影2电影3电影4电影5电影6
A153
B33
C510
D105
E51
F531

(2)根据评分矩阵计算用户相似度

我们采用最常见的余弦相似度进行计算相似度,设多维向量 a ^ = ( a 1 , a 2 , a 3 , a 4 … … ) , b ^ = ( b 1 , b 2 , b 3 , b 4 … … ) \hat a = (a_1,a_2,a_3,a_4……),\hat b = (b_1,b_2,b_3,b_4……) a^=(a1,a2,a3,a4)b^=(b1,b2,b3,b4),则其余弦相似度为:
c o s < a ^ , b ^ > = a 1 b 1 + a 2 b 2 + … + a n b n a 1 2 + a 2 2 + … a n 2 b 1 2 + b 2 2 + … b n 2 cos<\hat a, \hat b > = \frac{a_1b_1 + a_2 b_2 + \ldots + a_n b_n}{\sqrt{a_1^2 + a_2^2 + \ldots a_n^2} \sqrt{b_1^2 + b_2^2 + \ldots b_n^2}} cos<a^,b^>=a12+a22+an2 b12+b22+bn2 a1b1+a2b2++anbn
根据这个公式,可以计算出用户A 用户C,用户A、用户B 之间的相似度为:
c o s < A , C > = 0.08 c o s < A , B > = 0 cos<A,C> = 0.08 \\ cos<A,B> = 0 cos<A,C>=0.08cos<A,B>=0
计算所有的用户之间的相似度,进而得到用户相似度矩阵

ABCDEF
A100.080.150.930.43
B0100.3200.6
C0.08010.400.15
D0.150.320.4100
E0.9300010.5
F0.430.60.1500.51

(3)根据评分矩阵、用户相似度矩阵得到推荐列表(推荐未看过的电影)

UserCF算法会基于评分矩阵、用户相似度矩阵给用户推荐和他兴趣最相似的K个用户喜欢的物品。如下的公式度量了UserCF算法中用户 u u u对物品 i i i的感兴趣程度:
p ( u , i ) = ∑ v ∈ S ( u , K ) ∩ N ( i ) w u v r v i p(u,i) = \sum_{v\in{S(u,K)\cap N(i)}} w_{uv}r_{vi} p(u,i)=vS(u,K)N(i)wuvrvi
其中,S(u,K) 为和用户 u 兴趣最接近的 K 个用户, N( i ) 为对物品 i 有过行为的用户集合, w u v w_{uv} wuv 为用户 u 和用户 v 的兴趣相似度, r v i r_{vi} rvi为用户 v 对物品 i 的兴趣。

在电影推荐例子中,假设我们要给用户A推荐电影,我们首先找到 K K K个与用户A相似,并且对电影 i i i 评分的 用户集合 v v v。然后对这些用户集合中的每一个用户 v v v 进行如下计算: ( 用户 u 和相似用户 v 的相似程度 w u v w_{uv} wuv ) X ( 用户 v 对商品 i 的喜爱程度 r_{vi} ) 然后将乘积结果累加作为 u 对 i 的感兴趣程度。

如:我们要确定用户A对电影2的兴趣程度,先确定 v = { B , F } v=\{B,F\} v={B,F},所以:
p ( A , 电 影 2 ) = w A B r B 电 影 2 + w A F r F 电 影 2 = 0 ∗ 3 + 0.43 ∗ 5 = 2.15 p(A,电影2) = w_{AB}r_{B电影2} + w_{AF}r_{F电影2} = 0*3 + 0.43*5 = 2.15 p(A,2)=wABrB2+wAFrF2=03+0.435=2.15
不难发现,其数值就等于 相似度矩阵的第A行评分矩阵第 电影2 列 内积的结果。

推广一下,用户u对物品i的评分数值就等于 相似度矩阵的第u行评分矩阵第 i 列 内积的结果。

所以,推荐列表 = 相似度矩阵 X 评分矩阵

用户/电影电影1电影2电影3电影4电影5电影6
A2.92.211.03.90.81.2
B3.26.01.804.60.6
C9.10.80.90.22.010.2
D11.21.00.80.56.04.0
E0.92.511.23.800.5
F1.26.87.71.81.82.5

由于用户已经对电影中的一些商品有过行为,所以还要把这些电影给滤除掉。

在这里插入图片描述
得到最终的推荐列表

123456
A2.20.81.2
B3.21.800.6
C0.80.90.22.0
D1.00.80.54.0
E0.92.500.5
F1.21.81.8

其数值代表的意义是用户对电影的感兴趣程度。

UserCF 改进

对于一些热门的商品例如《新华字典》,许多用户都可能会有购买行为,但是不能说明买过这本书的兴趣就相同。但是都买了相对冷门点的《统计学习方法》的人,就很可能有相似的兴趣。

为了改进这个问题,假设 N(i) 为喜欢物品 i 的用户数,则可以改用下面的公式计算相似度:
w u v = ∑ i ∈ N ( u ) ∩ N ( v ) 1 log ⁡ ( 1 + ∣ N ( i ) ∣ ) ∣ N ( u ) ∣ ∣ N ( v ) ∣ w_{uv} = \frac{\sum_{i\in{N(u)\cap N(v)}} \frac{1}{\log(1+|N(i)|)}}{\sqrt{|N(u)||N(v)|}} wuv=N(u)N(v) iN(u)N(v)log(1+N(i))1
上面的式子中 1 log ⁡ ( 1 + ∣ N ( i ) ∣ ) \frac{1}{\log(1+|N(i)|)} log(1+N(i))1 惩罚了用户 u 和用户 v 共同兴趣列表中热门物品对他们相似度的影响。

基于物品的协同过滤(ItemCF)

基本思想

基于物品的协同过滤推荐的基本原理与基于用户的类似,只是使用所有用户
对物品的偏好,发现物品和物品之间的相似度,然后根据用户的历史偏好信息,将类似的物品推荐给用户。

如下图所示:

在这里插入图片描述

用户c喜欢物品喜欢物品A,通过算法计算发现物品A与物品C十分相似,于是猜测用户c也喜欢物品C,于是将C物品推送给用户c。

例子

计算过程与UserCF非常相似,区别在于计算时把UserCF的评分矩阵转置

电影/用户ABCDEF
电影11510
电影235
电影3553
电影431
电影535
电影610

再计算商品与商品之间的相似度得到商品之间的相似度矩阵

最后的推荐列表 = 商品之间的相似度矩阵 X 评分矩阵转置

ItemCF 改进

由于活跃用户可能会广泛的购买各种类别商品,因此对物品相似度的贡献要小于不活跃用户。本节计算相似度的方法同样可以改用下面的方法:
w i j = ∑ u ∈ N ( i ) ⋂ N ( j ) 1 log ⁡ 1 + ∣ N ( u ) ∣ ∣ N ( i ) ∣ ∣ N ( j ) ∣ w_{ij} = \frac{\sum_{u \in N(i) \bigcap N(j)}\frac{1}{\log{1}+|N(u)|}}{\sqrt{|N(i)||N(j)|}} wij=N(i)N(j) uN(i)N(j)log1+N(u)1
这个公式只是对活跃用户做的一种软性惩罚,但对于很多过于活跃的用户,在实际计算中一般直接忽略他的兴趣列表,而不将其纳入到相似度计算的数据集中。

归一化

如果将 ItemCF 的相似度矩阵按最大值归一化,可以提高推荐的准确率。如果已经得到了物品相似度矩阵 w ,那么可以用如下公式得到归一化之后的相似度矩阵 w’ :
w i j ′ = w i j max ⁡ i w i j w_{ij}' = \frac{w_{ij}}{\max\limits_i w_{ij}} wij=imaxwijwij
归一化的好处不仅仅在于增加推荐的准确度,它还可以提高推荐的覆盖率和多样性。

UserCF 与 ItemCF 对比

同样是协同过滤,在基于用户和基于项目两个策略中应该如何选择呢?

在实际应用中,存在两种情况:(1) 电商、电影、音乐网站,用户数量远大于物品数量。(2)新闻网站,物品(新闻文本)数量可能大于用户数量。

角度ltem-CFUser-CF
应用场景物品的个数是远远小于用户的数量的,而且物品的个数和相似度相对比较稳定。适用于非社交推荐物品的个数大于用户的个数,且物品的更新程度很快,相似度依然不稳定。适用与社交推荐
精确度发现长尾物品,精度就会小于UserCF精度高与Item_CF
系统多样性多样性推荐较强多样性推荐较弱
推荐偏好UserCF注重社会化ItemCF注重个性化

参考文献:
推荐系统(一)】协同过滤之基于领域的方法(UserCF,ItemCF)
推荐系统UserCF和ItemCF

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的基于用户协同过滤算法的 Java 代码示例: ```java public class UserBasedCF { private Map<Integer, Map<Integer, Double>> userItemRatingMatrix; // 用户-物品评分矩阵 private Map<Integer, List<Integer>> userItemMap; // 用户-物品列表映射 private Map<Integer, Double> userAverageRatingMap; // 用户平均评分映射 public UserBasedCF(Map<Integer, Map<Integer, Double>> userItemRatingMatrix) { this.userItemRatingMatrix = userItemRatingMatrix; this.userItemMap = new HashMap<>(); this.userAverageRatingMap = new HashMap<>(); initialize(); } // 初始化用户-物品列表映射和用户平均评分映射 private void initialize() { for (Map.Entry<Integer, Map<Integer, Double>> entry : userItemRatingMatrix.entrySet()) { int userId = entry.getKey(); Map<Integer, Double> itemRatingMap = entry.getValue(); double sum = 0.0; for (Map.Entry<Integer, Double> itemRatingEntry : itemRatingMap.entrySet()) { int itemId = itemRatingEntry.getKey(); double rating = itemRatingEntry.getValue(); sum += rating; if (userItemMap.containsKey(userId)) { userItemMap.get(userId).add(itemId); } else { List<Integer> itemList = new ArrayList<>(); itemList.add(itemId); userItemMap.put(userId, itemList); } } userAverageRatingMap.put(userId, sum / itemRatingMap.size()); } } // 计算两个用户之间的皮尔逊相关系数 private double pearsonCorrelation(int userId1, int userId2) { List<Integer> commonItemList = getCommonItems(userId1, userId2); if (commonItemList.isEmpty()) { return 0.0; } double sum1 = 0.0, sum2 = 0.0, sum1Sq = 0.0, sum2Sq = 0.0, pSum = 0.0; for (int itemId : commonItemList) { double rating1 = userItemRatingMatrix.get(userId1).get(itemId); double rating2 = userItemRatingMatrix.get(userId2).get(itemId); sum1 += rating1; sum2 += rating2; sum1Sq += Math.pow(rating1, 2); sum2Sq += Math.pow(rating2, 2); pSum += rating1 * rating2; } int n = commonItemList.size(); double numerator = pSum - (sum1 * sum2 / n); double denominator = Math.sqrt((sum1Sq - Math.pow(sum1, 2) / n) * (sum2Sq - Math.pow(sum2, 2) / n)); if (denominator == 0.0) { return 0.0; } return numerator / denominator; } // 获取两个用户共同评分的物品列表 private List<Integer> getCommonItems(int userId1, int userId2) { List<Integer> itemList1 = userItemMap.get(userId1); List<Integer> itemList2 = userItemMap.get(userId2); List<Integer> commonItemList = new ArrayList<>(itemList1); commonItemList.retainAll(itemList2); return commonItemList; } // 获取与指定用户最相似的前K个用户 private List<Integer> getTopKSimilarUsers(int userId, int k) { Map<Integer, Double> similarityMap = new HashMap<>(); for (int otherUserId : userItemMap.keySet()) { if (otherUserId != userId) { double similarity = pearsonCorrelation(userId, otherUserId); similarityMap.put(otherUserId, similarity); } } List<Integer> similarUserList = new ArrayList<>(similarityMap.keySet()); Collections.sort(similarUserList, new Comparator<Integer>() { @Override public int compare(Integer userId1, Integer userId2) { return Double.compare(similarityMap.get(userId2), similarityMap.get(userId1)); } }); return similarUserList.subList(0, Math.min(k, similarUserList.size())); } // 预测指定用户对指定物品的评分 public double predict(int userId, int itemId, int k) { List<Integer> similarUserList = getTopKSimilarUsers(userId, k); double numerator = 0.0, denominator = 0.0; for (int otherUserId : similarUserList) { if (userItemRatingMatrix.get(otherUserId).containsKey(itemId)) { double similarity = pearsonCorrelation(userId, otherUserId); double rating = userItemRatingMatrix.get(otherUserId).get(itemId); double averageRating = userAverageRatingMap.get(otherUserId); numerator += similarity * (rating - averageRating); denominator += Math.abs(similarity); } } if (denominator == 0.0) { return userAverageRatingMap.get(userId); } return userAverageRatingMap.get(userId) + numerator / denominator; } } ``` 使用示例: ```java Map<Integer, Map<Integer, Double>> userItemRatingMatrix = new HashMap<>(); // 假设有4个用户和5个物品,评分矩阵如下: // 1 2 3 0 0 // 4 5 0 0 0 // 0 3 0 5 0 // 0 0 4 0 5 userItemRatingMatrix.put(1, new HashMap<Integer, Double>() {{ put(1, 1.0); put(2, 2.0); put(3, 3.0); }}); userItemRatingMatrix.put(2, new HashMap<Integer, Double>() {{ put(1, 4.0); put(2, 5.0); }}); userItemRatingMatrix.put(3, new HashMap<Integer, Double>() {{ put(2, 3.0); put(4, 5.0); }}); userItemRatingMatrix.put(4, new HashMap<Integer, Double>() {{ put(3, 4.0); put(5, 5.0); }}); UserBasedCF userBasedCF = new UserBasedCF(userItemRatingMatrix); double predictedRating = userBasedCF.predict(1, 4, 2); // 预测用户1对物品4的评分,使用最相似的2个用户 System.out.println(predictedRating); // 输出预测评分 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值