JavaWeb博客项目--推荐算法--完整代码及思路

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

因为我写的是博客项目,博客数量可能比用户数量还多

所以选择基于用户的协同过滤算法

重要思想

当要向用户u进行推荐时,我们先找出与用户u最相似的几个用户,再从这几个用户的喜欢的物品中预测出用户u最喜欢的几个物品并且用户u没有交互过的物品进行推荐

听起来好像很麻烦,实则不然,搞清楚思路后就是简单的套公式而已,我们就根据这个基本思想来进行所有的操作,就是说,这个思想会贯穿始终。

完整思路

步骤一:首先,我们要找出与用户u最相似的几个用户

那我们是不是要知道2个用户之间的相似度是怎么计算的,然后根据其他所有用户与用户u的相似度进行一个排序,这样最前面k位就是与u最相似的k个用户。

这里我给出相似度公式---Jaccard公式

解释

  • sim( u , v ) 是集合 u 和集合 v 的 Jaccard 相似度。
  • |Nu∩ Nv| 表示集合 u 和集合 v 的交集的大小。
  • |Nu∪ Nv| 表示集合 u 和集合 v 的并集的大小。

那么这些集合的含义又是什么?

这些集合表示的是用户所交互过的物品的集合

比如Nu就是用户u所交互过的物品的集合

什么是交互就不用我说了吧,比如我对某篇博客进行点赞,或者收藏,都是交互,其实点踩也是,但是我们是在做推荐系统,所以只要正反馈。

简单地说,这个公式的意思是:

用户u与用户v之间的相似度,是用户 u和用户 v 共同交互过的物品的数量

除以根号下(用户 u的交互过的物品总数*用户 v交互过的物品总数)

所以根据公式:我们需要得到2个东西:

  1.每2个用户之间共同交互过的物品数量(又叫做协同过滤矩阵)

  2.每个用户所交互过的物品总数量

1.先来求第一个条件--每2个用户之间共同交互过的物品数量

正常思路就是先得到每个用户交互过的物品的集合,再建立倒排表,表示每个博客被哪些用户交互过,这是很关键的一步。

  这是我的从数据库取数据的操作,你们根据自己的实际情况来获取数据即可,

我的用户id是账号是String类型,博客Id就是它在博客表中的主键id,是int

             //1.将user表里面所有用户查出来//2.遍历所有用户,将点赞表,收藏表里面该用户的记录中的博客id都找出来,放在一个Set//每遍历完一个用户就存Map里面List<User> users = userMapper.getAllUser();Map<String,Set<Integer>>userToBlogs = new HashMap<>();Map<String, Integer> num = new HashMap<>();for(User user:users){//这个Set存放当前遍历到的用户所交互过的所有博客的idSet<Integer> blogIds = new HashSet<>();//下面这个blogIdsFromUpvote是用户所有点赞过的博客idList<Integer> blogIdsFromUpvote = upvoteMapper.getBlogIdByUserId(user.getAccount());blogIds.addAll(blogIdsFromUpvote);//下面这个blogIdsFromCollect是用户所有收藏了的博客idList<Integer> blogIdsFromCollect = collectMapper.getAllBlogIdByUserId(user.getAccount());blogIds.addAll(blogIdsFromCollect);userToBlogs.put(user.getAccount(),blogIds);num.put(user.getAccount(),blogIds.size());}

不管过程怎么样,反正最终只需要得到2个Map:

 1.Map<String,Set<Integer>>userToBlogs = new HashMap<>();

这个Map存的是用户ID所对应的一个交互过的博客id的Set集合,Set有自动去重功能。


2.Map<String, Integer> num = new HashMap<>();

这个Map存的是每个用户ID对应的该用户交互过的物品总数。

 num到后面计算jaccard相似度的时候才用,现在只需要根据userToBlogs来建立倒排表,表示每个博客被哪些用户交互过。

也很简单,遍历userToBlogs这个Map的每个键值对,在嵌套内循环遍历每个键值对中的Set<Integer>,也就是用户交互过的物品集合,将每个遍历到的物品和当前对应的键(也就是当前遍历到的用户)存进倒排表,就是这样一个Map,表示每个物品所对应的交互过这个物品的用户的集合:

Map<Integer, Set<String>> itemToUsers

代码:

package com.mycsdn.util.UserCF;import com.mycsdn.pojo.Blog;import java.util.*;public class InvertedIndex {public static Map<Integer, Set<String>> getItemToUsers(Map<String, Set<Integer>> userToItems) {Map<Integer, Set<String>> ItemToUsers = new HashMap<>();for (Map.Entry<String, Set<Integer>> entry : userToItems.entrySet()) {String userId = entry.getKey();Set<Integer> blogs = entry.getValue();for (Integer blogId : blogs) {//如果当前博客对应的用户集合中没有用户,就新建一个Set再把当前用户加进去,如果有的话就之间加进去Set<String> users = ItemToUsers.getOrDefault(blogId, new HashSet<>());users.add(userId);ItemToUsers.put(blogId, users);}}return ItemToUsers;}
}

现在得到了倒排表,就是这样一个Map,表示每个物品所对应的交互过这个物品的用户的集合:

Map<Integer, Set<String>> itemToUsers

开始求协同过滤矩阵

我们需要根据这个倒排表来求出协同过滤矩阵,也就是一个表示每2个用户之间共同交互过的物品数量

Map<String, Map<String, Integer>> CFMatrix = new HashMap<>();

String表示当前用户,对应的 Map<String, Integer>表示其他各个用户以及与当前用户的共同交互过的物品的数量

1.遍历这个倒排表,嵌套内循环遍历每个物品对应的用户集合的每个用户

2.对于遍历到的每个用户,通过遍历其他所有用户,将当前用户与其他用户的共同交互物品数加1

代码:

package com.mycsdn.util.UserCF;import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class GetCFMatrix {//得到的协同过滤矩阵是对于用户A,其他与A有共同交互过的博客的用户ID和共同交互过的博客的数量public static Map<String, Map<String, Integer>> getCFMatrix( Map<Integer, Set<String>> itemToUsers) {Map<String, Map<String, Integer>> CFMatrix = new HashMap<>();System.out.println("开始构建协同过滤矩阵....");// 遍历所有的物品,统计用户两两之间交互的物品数for (Map.Entry<Integer, Set<String>> entry : itemToUsers.entrySet()) {Integer item = entry.getKey();Set<String> users = entry.getValue();// 首先统计每个用户交互的物品个数for (String u : users) {//遍历所有该博客对应的交互过的用户// 统计每个用户与其它用户共同交互的物品个数if (!CFMatrix.containsKey(u)) {CFMatrix.put(u, new HashMap<>());}for (String v : users) {//再次遍历所有用户,对不是u的其他用户进行操作if (!v.equals(u)) {if (!CFMatrix.get(u).containsKey(v)) {CFMatrix.get(u).put(v, 0);}CFMatrix.get(u).put(v, CFMatrix.get(u).get(v) + 1);}}}}//还要返回num这个Mapreturn CFMatrix;}}

现在得到了协同过滤矩阵,也就是每2个用户之间的共同交互物品数:

Map<String, Map<String, Integer>> CFMatrix 

2.再来求第二个条件--每个用户所交互过的物品总数量

这个已经在第一遍顺手得出来了,就是这个num。

Map<String, Integer> num = new HashMap<>();

有了这2个条件后,就可以使用jaccard公式了

步骤二:根据协同过滤矩阵和每个用户所交互的物品总数求相似度-jaccard公式

很简单,直接套公式

package com.mycsdn.util.UserCF;import java.util.HashMap;
import java.util.Map;public class SimMatrix {public static Map<String, Map<String, Double>> getSimMatrix(Map<String, Map<String, Integer>> CFMatrix, Map<String, Integer> num) {Map<String, Map<String, Double>> sim =new HashMap<>();System.out.println("构建用户相似度矩阵....");for (Map.Entry<String, Map<String, Integer>> entry : CFMatrix.entrySet()) {//遍历协同过滤矩阵,遍历每个键值对String u = entry.getKey();Map<String, Integer> otherUser = entry.getValue();for (Map.Entry<String, Integer> userScore : otherUser.entrySet()) {String v = userScore.getKey();int score = userScore.getValue();if(!sim.containsKey(u)){sim.put(u,new HashMap<>());}sim.get(u).put(v, CFMatrix.get(u).get(v) / Math.sqrt(num.get(u) * num.get(v)));}}return sim;}
}

现在得到了 Map<String, Map<String, Double>> sim =new HashMap<>();

表示当前用户对应的其他用户以及其他用户与当前用户的相似度

接下来我们只需要取前k位用户,遍历这些用户的交互过的物品但是被推荐用户还没有交互过的物品进行计分

分数就是(用户相似度 *物品分数),这个物品分数因为我们博客项目是隐式计分,也就是没有对哪篇博客进行过打分,所以交互过的博客都是1分。

也就是说,每篇博客的推荐指数就是被交互过的用户的相似度之和 

代码:

package com.mycsdn.util.UserCF;import java.util.*;public class Recommend {public static Set<Integer> recommendForUser(Map<String, Map<String, Double>> sim,Map<String, Set<Integer>> valUserItem,int K, int N, String targetUser) {System.out.println("给测试用户进行推荐....");Map<Integer, Double> itemRank = new HashMap<>();if (valUserItem.containsKey(targetUser)) {Set<Integer> items = valUserItem.get(targetUser);// sim[u] 的格式为 {user_id: similarity,....} // 按照相似度进行排序,然后取前 K 个List<Map.Entry<String, Double>> sortedSim = new ArrayList<>(sim.get(targetUser).entrySet());Collections.sort(sortedSim, new Comparator<Map.Entry<String, Double>>() {public int compare(Map.Entry<String, Double> o1, Map.Entry<String, Double> o2) {return Double.compare(o2.getValue(), o1.getValue());}});System.out.println("检查对相似度矩阵排序后的矩阵");for (Map.Entry<String, Double> entry : sortedSim) {String item = entry.getKey();Double similarity = entry.getValue();System.out.println("用户 " + item + ", 相似度: " + similarity);}for (int i = 0; i < K; i++) {//前k个相似度高的用户if (i >= sortedSim.size())break;String similarUser = sortedSim.get(i).getKey();double score = sortedSim.get(i).getValue();// 找出相似用户中有交互的物品,但当前用户并未交互过的物品进行推荐for (int item : valUserItem.get(similarUser)) {if (valUserItem.get(targetUser).contains(item))//如果用户已经对该物品交互过,就不用再推荐continue;itemRank.put(item, itemRank.getOrDefault(item, 0.0) + score);//这里就得到的推荐候选的一个集合}}}// 根据评分进行排序,取排名靠前的 N 个物品作为推荐列表List<Map.Entry<Integer, Double>> topNItems = new ArrayList<>(itemRank.entrySet());Collections.sort(topNItems, new Comparator<Map.Entry<Integer, Double>>() {public int compare(Map.Entry<Integer, Double> o1, Map.Entry<Integer, Double> o2) {return Double.compare(o2.getValue(), o1.getValue());}});Set<Integer> recommendedItems = new HashSet<>();for (int i = 0; i < Math.min(N, topNItems.size()); i++) {recommendedItems.add(topNItems.get(i).getKey());}return recommendedItems;}
}

至此,我们已经得到了被推荐的物品的id集合

Set<Integer>  recommendedItems;

只要根据id查出对应的物品再返回前端,前端进行渲染即可。

缺点:

项目建立之初,还未收集足够的用户信息,协同过滤算法不能为指定用户找到合适的邻居,从而无法向用户提供推荐预测。
对于新注册的用户由于系统里没有他们的历史数据信息,所以协同过滤算法也无法为新用户推荐商品。
对于冷门的商品,可能从未被评过分,比如新加进的商品或者是比较小众的商品,它们也是不可能会被推荐给用户的。
 

如果是在写音乐播放器或者电影播放器,请移步基于物品的协同过滤算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/40142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据可视化和数字孪生相互促进的关系

数据可视化和数字孪生是当今数字化时代中备受关注的两大领域&#xff0c;它们在不同层面和领域为我们提供了深入洞察和智能决策的机会&#xff0c;随着两种技术的不断融合发展&#xff0c;很多人会将他们联系在一起&#xff0c;本文就带大家浅谈一下二者之间相爱相杀的关系。 …

Springboot集成ip2region离线IP地名映射-修订版

title: Springboot集成ip2region离线IP地名映射 date: 2020-12-16 11:15:34 categories: springboot description: Springboot集成ip2region离线IP地名映射 1. 背景2. 集成 2.1. 步骤2.2. 样例2.3. 响应实例DataBlock2.4. 响应实例RegionAddress 3. 打开浏览器4. 源码地址&…

OpenShift 4 - 基于 MinIO 安装 Red Hat Quay 镜像仓库

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在 OpenShift 4.13 Quay 3.9 的环境中验证 本文适合在单机 OpenShift 环境安装 Red Hat Quay 镜像仓库。 另外《OpenShift 4 - 安装 ODF 并部署红帽 Quay (1 Worker)》也可以在单节点部署。 而《OpenShif…

前后端分离------后端创建笔记(11)用户删除

B站视频&#xff1a;30-用户删除&结束语_哔哩哔哩_bilibili 1、现在我们要做一个删除的功能 1.1 首先做一个删除的功能接口&#xff0c;第一步先来到后端&#xff0c;做一个删除的接口 2、删除我们用Delete请求 3、方法名我给他改一下 3.1这里给他调一下删除方法&#xf…

在一小时内构建您的深度学习应用程序

一、说明 我已经做了将近十年的数据分析。有时&#xff0c;我使用机器学习技术从数据中获取见解&#xff0c;并且我习惯于使用经典 ML。 虽然我已经通过了神经网络和深度学习的一些MOOC&#xff0c;但我从未在我的工作中使用过它们&#xff0c;这个领域对我来说似乎很有挑战性。…

智能数据建模软件DTEmpower 2023R2新版本功能介绍

DTEmpower是由天洑软件自主研发的一款通用的智能数据建模软件&#xff0c;致力于帮助工程师及工科专业学生&#xff0c;利用工业领域中的仿真、试验、测量等各类数据进行挖掘分析&#xff0c;建立高质量的数据模型&#xff0c;实现快速设计评估、实时仿真预测、系统参数预警、设…

机器学习深度学习——自注意力和位置编码(数学推导+代码实现)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——注意力分数&#xff08;详细数学推导代码实现&#xff09; &#x1f4da;订阅专栏&#xff1a;机器学习…

Cat(2):下载与安装

1 github源码下载 要安装CAT&#xff0c;首先需要从github上下载最新版本的源码。 官方给出的建议如下&#xff1a; 注意cat的3.0代码分支更新都发布在master上&#xff0c;包括最新文档也都是这个分支注意文档请用最新master里面的代码文档作为标准&#xff0c;一些开源网站…

MySQL— 基础语法大全及操作演示!!!(上)

MySQL—— 基础语法大全及操作演示&#xff08;上&#xff09; 一、MySQL概述1.1 、数据库相关概念1.1.1 MySQL启动和停止 1.2 、MySQL 客户端连接1.3 、数据模型 二、SQL2.1、SQL通用语法2.2、SQL分类2.3、DDL2.3.1 DDL — 数据库操作2.3.1 DDL — 表操作 2.4、DML2.4.1 DML—…

等保案例 5

用户简介 四川省人民代表大会常务委员会&#xff0c;作为省人民代表大会地常设机关&#xff0c;随着政府部门信息化程度地提高&#xff0c;对信息系统地依赖程度越来越高&#xff0c;同时由于网络安全形势日益严峻、新型攻击层出不穷&#xff0c;单位信息化所面临地各种风险也…

途乐证券-宁德时代发力超充赛道,高压快充概念强势拉升,泰永长征涨停

高压快充概念17日盘中强势拉升&#xff0c;到发稿&#xff0c;泰永长征涨停&#xff0c;万祥科技涨超9%&#xff0c;英可瑞涨逾8%&#xff0c;迦南智能涨超4%。 消息面上&#xff0c;8月16日&#xff0c;宁德时代举行线下新品发布会&#xff0c;正式发布全球首款磷酸铁锂4C超充…

Spark第二课RDD的详解

1.前言 RDD JAVA中的IO 1.小知识点穿插 1. 装饰者设计模式 装饰者设计模式:本身功能不变,扩展功能. 举例&#xff1a; 数据流的读取 一层一层的包装&#xff0c;进而将功能进行进一步的扩展 2.sleep和wait的区别 本质区别是字体不一样,sleep斜体,wait正常 斜体是静态方法…

经过几天的乱搞,已经搞出来第一次stm32点灯程序

看吧那个灯泡已经亮了 stm32跟51不同的地方是这里引脚一组16个&#xff0c;如PA0,PA1,PA2,,,,,,PA15 51一组8个 例如P00,P01,P02,,,,P07

[Go版]算法通关村第十一关青铜——理解位运算的规则

目录 数字在计算机中的表示&#xff1a;机器数、真值对机器数进一步细化&#xff1a;原码、反码、补码为何会有原码、反码和补码为何计算机中的按位运算使用的是补码&#xff1f;位运算规则与、或、异或和取反移位运算移位运算与乘除法的关系位运算常用技巧⭐️ 操作某个位的数…

Unity用NPOI创建Exect表,保存数据,和修改删除数据。以及打包后的坑——无法打开新创建的Exect表

先说坑花了一下午才找到解决方法解决&#xff0c; 在Unity编辑模式下点击物体创建对应的表&#xff0c;获取物体名字与在InputText填写的注释数据。然后保存。创建Exect表可以打开&#xff0c;打包PC后&#xff0c;点击物体创建的表&#xff0c;打不开文件破损 解决方法&#…

大数据培训前景怎么样?企业需求量大吗

大数据行业对大家来说并不陌生&#xff0c;大数据行业市场人才需求量大&#xff0c;越早入行越有优势&#xff0c;发展机会和上升空间等大。不少人通过大数据培训来提升自己的经验和自身技术能力&#xff0c;以此来获得更好的就业机会。 2023大数据培训就业前景怎么样呢?企业需…

从视觉装备到智能驾驶,天准科技能否打造第二增长极?

智能网联汽车已经成为了上市公司跨界布局的热门赛道。 天准科技是工业视觉智能装备领域的龙头企业&#xff0c;主要客户包括苹果、三星等企业。招股说明书显示&#xff0c;2016年至2018年&#xff0c;天准科技来源于苹果公司及其供应商的收入合计占比达到49.98%、67.99%及76.0…

JVS开源基础框架:平台基本信息介绍

JVS是面向软件开发团队可以快速实现应用的基础开发脚手架&#xff0c;主要定位于企业信息化通用底座&#xff0c;采用微服务分布式框架&#xff0c;提供丰富的基础功能&#xff0c;集成众多业务引擎&#xff0c;它灵活性强&#xff0c;界面化配置对开发者友好&#xff0c;底层容…

互联网账号被封禁解决办法,以qq为例

百度搜索&#xff1a;互联网信息服务投诉平台 电脑端浏览器&#xff1a;打开 ts.isc.org.cn 推荐使用360极速浏览器 谷歌浏览器 提交完成后&#xff0c;将投诉码保存&#xff0c;可以在“查询评价”处用投诉码查询进度

windows安装go,以及配置工作区,配置vscode开发环境

下载安装go 我安装在D:\go路径下配置环境变量 添加GOROOT value为D:\go修改path 添加%GOROOT%\bin添加GOPATH value为%USERPROFILE%\go 其中GOPATH 是我们自己开发的工作区&#xff0c;其中包含三个folder bin,pkg,以及src&#xff0c;其中src为我们编写代码的位置 配置vscod…