usercf代码java_基于用户的协同过滤算法(UserCF)原理以及代码实践

简介

协同过滤(collaborative filtering)是一种在推荐系统中广泛使用的技术。该技术通过分析用户或者事物之间的相似性,来预测用户可能感兴趣的内容并将此内容推荐给用户。这里的相似性可以是人口特征的相似性,也可以是历史浏览内容的相似性,还可以是个人通过一定机制给与某个事物的回应。比如,A和B是无话不谈的好朋友,并且都喜欢看电影,那么协同过滤会认为A和B的相似度很高,会将A喜欢但是B没有关注的电影推荐给B,反之亦然。

协同过滤推荐分为3种类型:

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

基于物品(item-based)的协同过滤(ItemCF算法)

基于模型(model-based)的协同过滤 (ModelCF算法)

本文主要讲述基于用户协同过滤算法的原理以及代码实现。

算法原理

UserCF算法主要是考虑用户与用户之间的相似度,给用户推荐和他兴趣相似的其他用户喜欢的物品。俗话说"物以群分,人以类聚",人们总是倾向于跟自己志同道合的人交朋友。同理,你朋友喜欢的东西你大概率也可能会喜欢,UserCF算法正是利用了这个原理。举个例子,如果要给一个用户A推荐物品,可以先找到与A最为相似的用户B,接着获取用户B最喜欢的且用户A没有听说过的物品,并预测用户A对这些物品的评分,从中选取评分最高的若干个物品推荐给用户A。

从上述描述可以知道,UserCF算法的主要步骤如下:

找到与目标用户兴趣相似的用户集合

找到这个集合中的用户最喜欢的,且目标用户还未接触过的物品推荐给目标用户

上述是UserCF算法的基本思路,方便读者形成对UserCF算法的整体印象。也许你看了上述文字依然没有思路,没关系,且继续往下看。

首先,根据算法的步骤1,我们自然而然就会提出一个问题,那就是如何度量两个用户之间的相似度?试想一下,我们在现实生活中如何判断两个人是否兴趣相似呢?比如你喜欢打LOL,恰巧你室友也喜欢,那显然你们的共同话题会比较多,因为你们有共同的兴趣爱好。我们刚好可以利用这一点来计算用户之间的相似度。

对于用户u和用户v,令N(u)代表用户u喜欢的物品合集,令N(v)代表用户v喜欢的物品合集。N(u)∩N(v)代表的是用户u和用户v都喜欢的物品,N(u)∪N(v)代表的是用户u和用户v喜欢的物品的合集,那么可以利用以下公式来简单计算相似度:

math?formula=W%5Cmu%5Cnu%20%3D%20%5Cfrac%20%7B%7CN(%5Cmu)%20%5Cbigcap%20N(%5Cnu)%7C%7D%7B%7CN(%5Cmu)%20%5Cbigcup%20N(%5Cnu)%7C%7D

上述公式叫做Jaccard公式,直观上理解就是,将用户u与用户v都喜欢的物品的数量除以他们喜欢物品的总和,如果u和v喜欢的物品是一模一样的,则u和v的相似度为1。

还有另外一种余弦相似度计算公式:

math?formula=W%5Cmu%5Cnu%20%3D%20%5Cfrac%20%7B%7CN(%5Cmu)%20%5Cbigcap%20N(%5Cnu)%7C%7D%20%7B%5Csqrt%7B%7CN(%5Cmu)%20%5C%7C%20N(%5Cnu)%7D%7C%7D

上述公式的分母部分代表的是u喜欢的物品的数量与v喜欢的物品的数量的乘积,而不再是他们之间的交集。

举个简单例子来表明如何计算用户u和v之间的相似度,假如用户u和用户v喜欢的游戏如下表:

用户

喜爱的游戏

u

{英雄联盟, 王者荣耀,绝地求生}

v

{英雄联盟,和平精英}

利用余弦相似度计算公式可以得到如下结果:

math?formula=W%5Cmu%5Cnu%20%3D%20%5Cfrac%20%7B%7C%5C%7B%E8%8B%B1%E9%9B%84%E8%81%94%E7%9B%9F%2C%E7%8E%8B%E8%80%85%E8%8D%A3%E8%80%80%2C%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F%5C%7D%20%5Cbigcap%20%5C%7B%E8%8B%B1%E9%9B%84%E8%81%94%E7%9B%9F%2C%E5%92%8C%E5%B9%B3%E7%B2%BE%E8%8B%B1%5C%7D%7C%7D%7B%5Csqrt%7B%5C%7B%E8%8B%B1%E9%9B%84%E8%81%94%E7%9B%9F%2C%E7%8E%8B%E8%80%85%E8%8D%A3%E8%80%80%2C%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F%5C%7D%20%7C%7C%20%5C%7B%E8%8B%B1%E9%9B%84%E8%81%94%E7%9B%9F%2C%20%E5%92%8C%E5%B9%B3%E7%B2%BE%E8%8B%B1%5C%7D%7D%7C%7D%20%3D%20%5Cfrac%20%7B1%7D%7B%5Csqrt%7B6%7D%7D

故,我们可以计算得到用户u和用户v之间的相似度为

math?formula=%5Cfrac%20%7B1%7D%7B%5Csqrt%7B6%7D%7D

至此,我们已经可以计算任意两个用户之间的相似度了,下一步要做的事情是建立一张用户相似度表,此表中保存了任意两个用户之间的相似度,方便后续挑选出与用户u最相似的若干个用户。

当用户相似度表建立起来了之后,UserCF算法就可以给用户推荐与他兴趣最相似的K个用户喜欢的物品了。那此时又会出现一个问题,假如我们要给用户w进行推荐,并且在用户相似度表中找到了与他最相似的K个用户ÿ

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值