![cover](https://img-blog.csdnimg.cn/img_convert/77fcfea2a41749d7867f62f0e98b01ca.png)
基于用户的协同过滤推荐算法(整合)
基于用户的协同过滤推荐算法(整合)基本思想
基于用户的协同过滤推荐算法(整合)
基本思想
当一个用户A需要个性化推荐时,可以先找到和他有相似兴趣的其他用户,然后把那些用户喜欢的、而用户A没有听说过的物品推荐给A。这种方法称为基于用户的协同过滤算法。
![](https://i-blog.csdnimg.cn/blog_migrate/ab2e64dbfbe4e362331b9b57240eacdf.png)
原理
-
找到与目标用户兴趣相似的用户集合
-
找到这个集合中用户喜欢的、并且目标用户没有听说过的物品推荐给目标用户
(1)找到与目标用户兴趣相似的用户集合
利用行为的相似度计算兴趣的相似度。给定用户u和用户v,
令N(u)表示用户u曾经有过正反馈的物品集合
令N(v)为用户v曾经有过正反馈的物品集合
那么,我们可以通过如下公式简单地计算u和v的兴趣相似度:
Jaccard公式:
余弦相似度:
假设目前共有4个用户: A、B、C、D;共有5个物品:a、b、c、d、e。用户与物品的关系(用户喜欢物品)如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/a536e3ec5fe525b223678d4090e1ccbf.png)
直接计算,以用户A为例:
![](https://i-blog.csdnimg.cn/blog_migrate/95462dd49b440ecfcacf7a071f2e1a6f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4d45cd850b3c2a9d2b86057e10a40355.png)
这种方式对两两用户都利用余弦相似度计算相似度。这种方法的时间复杂度是O(|U|*|U|),这在用户数很大时非常耗时。事实上,很多用户相互之间并没有对同样的物品产生过行为,即相似度为0。这种方式将很多时间浪费在了计算这种用户之间的相似度上,,换一个思路,可以首先建立物品到用户的倒排表,对于每个物品都保存对该物品产生过行为的用户列表。
建立“物品—用户”的倒排表:
![](https://i-blog.csdnimg.cn/blog_migrate/99ab8ce93d51e27678997631d9fdbf8d.png)
对于每个物品,喜欢他的用户,两两之间相同物品加1。例如喜欢物品 a 的用户有 A 和 B,那么在矩阵中他们两两加1
![](https://i-blog.csdnimg.cn/blog_migrate/dc8ba363cec01fec0e851d44fb27acb9.png)
计算用户两两之间的相似度,上面的矩阵仅仅代表的是公式的分子部分。以余弦相似度为例,对上图进行进一步计算:
![](https://i-blog.csdnimg.cn/blog_migrate/82f55d8b703a0e45b7afe74b1d959de4.png)
(2)推荐商品
首先需要从矩阵中找出与目标用户 u 最相似的 K 个用户,用集合 S(u, K) 表示,将 S 中用户喜欢的物品全部提取出来,并去除 u 已经喜欢的物品。对于每个候选物品 i ,用户 u 对它感兴趣的程度用如下公式计算:
![](https://i-blog.csdnimg.cn/blog_migrate/a3dfe3bc6d6799bfe12719053984b506.png)
其中 rvi 表示用户 v 对 i 的喜欢程度,在本例中都是为 1,在一些需要用户给予评分的推荐系统中,则要代入用户评分。
设我们要给 A 推荐物品,选取 K = 3 个相似用户,相似用户则是:B、C、D,那么他们喜欢过并且 A 没有喜欢过的物品有:c、e,那么分别计算 p(A, c) 和 p(A, e):
![](https://i-blog.csdnimg.cn/blog_migrate/ec80d00d1bf0b4bef70d4eed4dea00bf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a33cbd390c52eb0438423837f0bf33ee.png)
在实际的操作中,就可以根据最后得到的p,推荐给用户rank前N的物品。
JAVA实现
源码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
/**
* 输入用户-->物品条目 一个用户对应多个物品
* 用户ID 物品ID集合
* A a b d
* B a c
* C b e
* D c d e
*/
Scanner scanner = new Scanner(System.in);
System.out.println("Input the total users number:");
//输入用户总量
int N = scanner.nextInt();
int[][] sparseMatrix = new int[N][N];//建立用户稀疏矩阵,用于用户相似度计算【相似度矩阵】
Map<String, Integer> userItemLength = new HashMap<>();//存储每一个用户对应的不同物品总数 eg: A 3
Map<String, Set<String>> itemUserCollection = new HashMap<>();//建立物品到用户的倒排表 eg: a A B
Set<String> items = new HashSet<>();//辅助存储物品集合
Map<String, Integer> userID = new HashMap<>();//辅助存储每一个用户的用户ID映射
Map<Integer, String> idUser = new HashMap<>();//辅助存储每一个ID对应的用户映射
System.out.println("Input user--items maping infermation:<eg:A a b d>");
scanner.nextLine();
for(int i = 0; i < N ; i++){//依次处理N个用户 输入数据 以空格间隔
String[] user_item = scanner.nextLine().split(" ");
int length = user_item.length;
userItemLength.put(user_item[0], length-1);//eg: A 3
userID.put(user_item[0], i);//用户ID与稀疏矩阵建立对应关系
idUser.put(i, user_item[0]);
//建立物品--用户倒排表
for(int j = 1; j < length; j ++){
if(items.contains(user_item[j])){//如果已经包含对应的物品--用户映射,直接添加对应的用户
itemUserCollection.get(user_item[j]).add(user_item[0]);
}else{//否则创建对应物品--用户集合映射
items.add(user_item[j]);
itemUserCollection.put(user_item[j], new HashSet<String>());//创建物品--用户倒排关系
itemUserCollection.get(user_item[j]).add(user_item[0]);
}
}
}
System.out.println(itemUserCollection.toString());
//计算相似度矩阵【稀疏】
Set<Entry<String, Set<String>>> entrySet = itemUserCollection.entrySet();
Iterator<Entry<String, Set<String>>> iterator = entrySet.iterator();
while(iterator.hasNext()){
Set<String> commonUsers = iterator.next().getValue();
for (String user_u : commonUsers) {
for (String user_v : commonUsers) {
if(user_u.equals(user_v)){
continue;
}
sparseMatrix[userID.get(user_u)][userID.get(user_v)] += 1;//计算用户u与用户v都有正反馈的物品总数
}
}
}
System.out.println(userItemLength.toString());
System.out.println("Input the user for recommendation:<eg:A>");
String recommendUser = scanner.nextLine();
System.out.println(userID.get(recommendUser));
//计算用户之间的相似度【余弦相似性】
int recommendUserId = userID.get(recommendUser);
for (int j = 0;j < sparseMatrix.length; j++) {
if(j != recommendUserId){
System.out.println(idUser.get(recommendUserId)+"--"+idUser.get(j)+"相似度:"+sparseMatrix[recommendUserId][j]/Math.sqrt(userItemLength.get(idUser.get(recommendUserId))*userItemLength.get(idUser.get(j))));
}
}
//计算指定用户recommendUser的物品推荐度
for(String item: items){//遍历每一件物品
Set<String> users = itemUserCollection.get(item);//得到购买当前物品的所有用户集合
if(!users.contains(recommendUser)){//如果被推荐用户没有购买当前物品,则进行推荐度计算
double itemRecommendDegree = 0.0;
for(String user: users){
itemRecommendDegree += sparseMatrix[userID.get(recommendUser)][userID.get(user)]/Math.sqrt(userItemLength.get(recommendUser)*userItemLength.get(user));//推荐度计算
}
System.out.println("The item "+item+" for "+recommendUser +"'s recommended degree:"+itemRecommendDegree);
}
}
scanner.close();
}
}
测试:
Input the total users number:
4
Input user--items maping infermation:<eg:A a b d>
A a b d
B a c
C b e
D c d e
{=[A, B, C, D], a=[A, B], b=[A, C], c=[B, D], d=[A, D], e=[C, D]}
{A=4, B=3, C=3, D=4}
Input the user for recommendation:<eg:A>
B
1
B--A相似度:0.5773502691896258
B--C相似度:0.3333333333333333
B--D相似度:0.5773502691896258
The item b for B's recommended degree:0.9106836025229592
The item d for B's recommended degree:1.1547005383792517
The item e for B's recommended degree:0.9106836025229592
参考链接
原理:https://blog.csdn.net/shixiaoguo90/article/details/80253567
原理:https://blog.csdn.net/jiangdongxiaobawang/article/details/104155673
代码:https://blog.csdn.net/zhang_09_11/article/details/104487109
扩展:https://www.cnblogs.com/wxisme/p/4856490.html
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)