基于用户的协同过滤推荐算法实现(Java电商平台)

在电商平台中,基于用户的协同过滤推荐算法是一种常见的推荐系统方法。它通过分析用户之间的相似性来推荐商品。以下是一个简单的实现思路和示例代码,使用Java语言。

实现思路

  1. 数据准备:收集用户的评分数据,通常以用户-商品评分矩阵的形式存储。
  2. 计算相似度:使用余弦相似度或皮尔逊相关系数等方法计算用户之间的相似度。
  3. 生成推荐:根据相似用户的评分,预测目标用户对未评分商品的评分,并进行推荐。

1. 算法核心思想

基于用户的协同过滤通过以下步骤工作:

  1. 计算用户之间的相似度

  2. 找到与目标用户最相似的K个用户

  3. 根据这些相似用户的喜好预测目标用户可能喜欢的商品

  4. 推荐预测评分最高的N个商品

 2.Java实现代码

import java.util.*;public class UserBasedCF {// 用户-商品评分矩阵private Map<Integer, Map<Integer, Double>> userItemRatingMatrix;// 用户相似度矩阵private Map<Integer, Map<Integer, Double>> userSimilarityMatrix;// 商品-用户倒排表private Map<Integer, Set<Integer>> itemUserInverseTable;public UserBasedCF() {userItemRatingMatrix = new HashMap<>();userSimilarityMatrix = new HashMap<>();itemUserInverseTable = new HashMap<>();}/*** 添加用户评分数据* @param userId 用户ID* @param itemId 商品ID* @param rating 评分*/public void addRating(int userId, int itemId, double rating) {// 添加到用户-商品矩阵userItemRatingMatrix.putIfAbsent(userId, new HashMap<>());userItemRatingMatrix.get(userId).put(itemId, rating);// 添加到商品-用户倒排表itemUserInverseTable.putIfAbsent(itemId, new HashSet<>());itemUserInverseTable.get(itemId).add(userId);}/*** 计算用户之间的相似度(使用皮尔逊相关系数)*/public void calculateUserSimilarities() {// 获取所有用户列表Set<Integer> users = userItemRatingMatrix.keySet();for (int u1 : users) {userSimilarityMatrix.putIfAbsent(u1, new HashMap<>());Map<Integer, Double> u1Ratings = userItemRatingMatrix.get(u1);for (int u2 : users) {if (u1 == u2) continue;Map<Integer, Double> u2Ratings = userItemRatingMatrix.get(u2);// 计算两个用户的共同评分商品Set<Integer> commonItems = new HashSet<>(u1Ratings.keySet());commonItems.retainAll(u2Ratings.keySet());if (commonItems.size() < 2) {// 共同评分商品太少,相似度为0userSimilarityMatrix.get(u1).put(u2, 0.0);continue;}// 计算皮尔逊相关系数double sum1 = 0, sum2 = 0;double sum1Sq = 0, sum2Sq = 0;double pSum = 0;for (int item : commonItems) {double r1 = u1Ratings.get(item);double r2 = u2Ratings.get(item);sum1 += r1;sum2 += r2;sum1Sq += Math.pow(r1, 2);sum2Sq += Math.pow(r2, 2);pSum += r1 * r2;}int n = commonItems.size();double num = pSum - (sum1 * sum2 / n);double den = Math.sqrt((sum1Sq - Math.pow(sum1, 2) / n) * (sum2Sq - Math.pow(sum2, 2) / n));double sim = (den == 0) ? 0 : num / den;userSimilarityMatrix.get(u1).put(u2, sim);}}}/*** 为目标用户推荐商品* @param userId 目标用户ID* @param k 相似用户数量* @param n 推荐商品数量* @return 推荐商品ID列表*/public List<Integer> recommendItems(int userId, int k, int n) {if (!userItemRatingMatrix.containsKey(userId)) {return Collections.emptyList();}// 获取目标用户已评分的商品Set<Integer> ratedItems = userItemRatingMatrix.get(userId).keySet();// 获取相似用户并按相似度排序List<Map.Entry<Integer, Double>> similarUsers = new ArrayList<>(userSimilarityMatrix.get(userId).entrySet());similarUsers.sort((a, b) -> b.getValue().compareTo(a.getValue()));// 取前k个相似用户if (similarUsers.size() > k) {similarUsers = similarUsers.subList(0, k);}// 计算推荐商品的预测评分Map<Integer, Double> itemPredictions = new HashMap<>();for (Map.Entry<Integer, Double> entry : similarUsers) {int similarUser = entry.getKey();double similarity = entry.getValue();// 获取相似用户评过但目标用户未评的商品Map<Integer, Double> similarUserRatings = userItemRatingMatrix.get(similarUser);for (Map.Entry<Integer, Double> ratingEntry : similarUserRatings.entrySet()) {int item = ratingEntry.getKey();if (!ratedItems.contains(item)) {double rating = ratingEntry.getValue();// 加权评分itemPredictions.merge(item, similarity * rating, Double::sum);}}}// 对预测评分进行归一化处理for (Map.Entry<Integer, Double> entry : similarUsers) {int similarUser = entry.getKey();double similarity = entry.getValue();Map<Integer, Double> similarUserRatings = userItemRatingMatrix.get(similarUser);for (int item : itemPredictions.keySet()) {if (similarUserRatings.containsKey(item)) {itemPredictions.put(item, itemPredictions.get(item) / Math.abs(similarity));}}}// 按预测评分排序并返回前n个商品List<Map.Entry<Integer, Double>> sortedItems = new ArrayList<>(itemPredictions.entrySet());sortedItems.sort((a, b) -> b.getValue().compareTo(a.getValue()));List<Integer> recommendations = new ArrayList<>();for (int i = 0; i < Math.min(n, sortedItems.size()); i++) {recommendations.add(sortedItems.get(i).getKey());}return recommendations;}// 测试代码public static void main(String[] args) {UserBasedCF recommender = new UserBasedCF();// 模拟用户评分数据recommender.addRating(1, 101, 5.0);recommender.addRating(1, 102, 3.0);recommender.addRating(1, 103, 2.5);recommender.addRating(2, 101, 2.0);recommender.addRating(2, 102, 2.5);recommender.addRating(2, 103, 5.0);recommender.addRating(2, 104, 2.0);recommender.addRating(3, 101, 2.5);recommender.addRating(3, 104, 4.0);recommender.addRating(3, 105, 4.5);recommender.addRating(3, 107, 5.0);recommender.addRating(4, 101, 5.0);recommender.addRating(4, 103, 3.0);recommender.addRating(4, 104, 4.5);recommender.addRating(4, 106, 4.0);recommender.addRating(4, 107, 2.0);// 计算用户相似度recommender.calculateUserSimilarities();// 为用户1推荐2个商品List<Integer> recommendations = recommender.recommendItems(1, 2, 2);System.out.println("为用户1推荐的商品: " + recommendations);}
}

 3. 代码说明

  1. 数据结构:

    • userItemRatingMatrix: 存储用户对商品的评分

    • userSimilarityMatrix: 存储用户之间的相似度

    • itemUserInverseTable: 商品到用户的倒排表,加速计算

  2. 核心方法:

    • addRating(): 添加用户评分数据

    • calculateUserSimilarities(): 计算用户相似度(使用皮尔逊相关系数)

    • recommendItems(): 为目标用户生成推荐列表

  3. 推荐过程:

    • 找到与目标用户最相似的K个用户

    • 收集这些相似用户评价过但目标用户未评价的商品

    • 计算这些商品的预测评分(加权平均)

    • 返回评分最高的N个商品作为推荐

4. 实际应用中的优化建议

  1. 数据稀疏性问题:

    • 实现降维技术(如SVD)

    • 使用混合推荐方法(结合基于内容的推荐)

  2. 性能优化:

    • 使用稀疏矩阵存储数据

    • 实现增量更新机制,避免全量计算

    • 使用MapReduce或Spark进行分布式计算

  3. 冷启动问题:

    • 对于新用户,可以使用热门商品推荐

    • 对于新商品,可以使用基于内容的推荐

  4. 业务适配:

    • 考虑时间衰减因素(最近的评分权重更高)

    • 加入业务规则过滤(如库存、价格区间等)

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

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

相关文章

LeetCode - 904. 水果成篮

题目 904. 水果成篮 - 力扣&#xff08;LeetCode&#xff09; 思路 题目本质 你有一个整数数组&#xff0c;每个元素代表一种水果。你只能用两个篮子&#xff0c;每个篮子只能装一种水果。你要在数组中找一个最长的连续子数组&#xff0c;这个子数组里最多只包含两种不同的…

发现 Kotlin MultiPlatform 的一点小变化

最近发现 Kotlin 官方已经开始首推 Idea 的社区版的 KMP 插件了. 以前有网页创建 KMP 的项目的文档也消失了. 虽然有 Android Studio 的选项. 但是却不是在默认的位置上了. 足以说明官方是有意想让大家直接使用 Idea 社区版或者专业版 所以我直接在社区版上安装 KMP 插件. 尝试…

【Photoshop】金属字体制作

新建一个空白项目&#xff0c;选择横排文字工具&#xff0c;输入想要的文件建立文字图层 选择横排文字工具选择出文字内容&#xff0c;在通知栏出点击’拾色器‘&#xff0c;设置好需要的文字颜色 图层面板右下角点击‘添加图层样式’&#xff0c;选择斜面和浮雕 样式设置为内斜…

centos 7.9 升级ssh版本 7.4p1 升级到 8.2p1

centos 7.9 升级ssh版本 7.4p1 升级到 8.2p1 1、安装包下载2、安装telnet3、安装openssl-OpenSSL_1_1_1f.tar.gz4、安装openssh-8.2p1.tar.gz5、修改ssh服务的相关配置文件6、确定可以ssh连接服务器后&#xff0c;卸载telnet&#xff0c;因为telnet不安全 本文是离线环境下升级…

stm32---dma串口发送+fifo队列框架

之前分享了一个关于gd32的fifo框架&#xff0c;这次就用stm32仿照写一个&#xff0c;其实几乎一样&#xff0c;这次说的更详细点&#xff0c;我全文都写上了注释&#xff0c;大家直接cv模仿我的调用方式即可 uasrt.c #include "stm32f10x.h" // D…

【生产就曲篇】让应用可观测:Actuator监控端点与日志最佳实践

摘要 本文是《Spring Boot 实战派》系列的终章&#xff0c;我们将探讨如何让应用真正达到**“生产就绪” (Production-Ready)** 的标准。文章的核心是可观测性 (Observability)&#xff0c;即从外部了解一个系统内部运行状态的能力。 我们将深度挖掘 Spring Boot Actuator 的…

操作系统知识(1)

操作系统的分类总结 1、批处理操作系统:单道批处理和多道批处理(主机与外设可并行) 2、分时操作系统:一个计算机系统与多个终端设备连接。将CPU的工作时间划分为许多很短的时间片&#xff0c;轮流为各个终端的用户服务。 3、实时操作系统:实时是指计算机对于外来信息能够以足…

一.Sharding分库分表-基因法+自定义多key分片实现多字段查询

前言 当下遇到这样一个场景&#xff0c;由于订单数据量达到千万级别&#xff0c;采用分库分表进行优化&#xff0c;根据订单的热查条件&#xff1a;order_no订单编号进行分表&#xff0c;但是这样带来一个问题&#xff0c;用户查询自己的订单怎么查&#xff1f;由于分片键使用…

【leetcode】543. 二叉树的直径

二叉树的直径 题目题解解释 题目 543. 二叉树的直径 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 题解 …

AI基础知识(07):基于 PyTorch 的手写体识别案例手册

目录 实验介绍 实验对象 实验时间 实验流程 实验介绍 随着人工智能技术的飞速发展&#xff0c;图像识别技术在众多领域得到了广泛应用。手写体识别作为图像 识别的一个重要分支&#xff0c;其在教育、金融、医疗等领域具有广泛的应用前景。本实验旨在利用深度 学习框架 PyTorc…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…

信号(瞬时)频率求解与仿真实践(2)

引言 本文是信号(瞬时)频率求解与仿真实践专题的第二篇文章&#xff0c;在上一篇博文 [1]信号(瞬时)频率求解与仿真实践(1)-CSDN博客中&#xff0c;我构建了信号瞬时频率求解的基本框架&#xff0c;并且比较详细地讨论了瞬时频率法。这篇博文探讨适用于信号瞬时频率求解的另一种…

Linux运行发布jar文件携带哪些参数

在 CentOS 8 上运行发布的 JAR 文件时,可以根据不同需求携带以下参数: 1. 基本运行方式 bash 复制 下载 java -jar your-application.jar 2. 常用 JVM 参数 参数说明-Xms256m初始堆内存大小(如 256MB)-Xmx1024m最大堆内存大小(如 1GB)-XX:MaxMetaspaceSize=256m元空间…

在GIS 工作流中实现数据处理(4)

结果输出与可视化 最后&#xff0c;我们将统计结果输出为一个 Excel 文件&#xff0c;并在 ArcMap 中对城市中心区域的土地利用情况进行可视化展示。 import pandas as pd# 将统计表格转换为 pandas DataFrame df pd.read_csv(statistics_table, sep"\t")# 输出为…

【术语解释】网络安全((SAST, DAST, SCA, IAST),Hadoop, Spark, Hive 的关系

## OWASP Top 10等 OWASP Top 10&#xff1a;OWASP (Open Worldwide Application Security Project&#xff0c;开放全球应用程序安全项目) Top 10 是一份由全球安全专家定期更新的报告&#xff0c;列出了当前 Web 应用程序面临的十大最关键安全风险。 它是一个广受认可的意识文…

NY197NY205美光闪存固态NY218NY226

NY197NY205美光闪存固态NY218NY226 美光科技作为全球领先的半导体存储解决方案供应商&#xff0c;其闪存固态硬盘&#xff08;SSD&#xff09;产品线一直备受业界关注。NY197、NY205、NY218和NY226是美光近期推出的几款重要固态硬盘型号&#xff0c;它们在性能、容量和适用场景…

MinHook 对.NET底层的 SendMessage 拦截真实案例反思

一&#xff1a;背景 1. 讲故事 上一篇我们说到了 minhook 的一个简单使用&#xff0c;这一篇给大家分享一个 minhook 在 dump 分析中的实战&#xff0c;先看下面的线程栈。 0:044> ~~[138c]s win32u!NtUserMessageCall0x14: 00007ffc5c891184 c3 ret 0:061&g…

qt配合海康工业相机取图开发

1.最近开发海康工业相机&#xff0c;做取图demo 2.在MVS运行目录下找到Development文件夹&#xff0c;找到下图两个文件夹一个是头文件一个是库文件 3.引用到qt项目中 4.下面是头文件跟源文件 头文件 #ifndef MVSCAMERA_H #define MVSCAMERA_H#include <QObject> #incl…

JavaScript基础学习与应用(后端了解部分)

JavaScript JavaScript原名liveScrip,由美国网景公司开发的一种用于对网页操作的脚本语言 脚本语言:(不需要编译 sql html css)由某种解释器直接解释运行的 JavaScript是一种解释性的脚本语言 JavaScript是网页的行为,可以为网页提供各种行为(图片操作) JavaScript一般一对…

Linux环境下安装和使用RAPIDS平台的cudf和cuml - pip 安装方法

‌ cuDF 和 cuML 是 RAPIDS平台 的两个核心组件&#xff0c;它们共同构成了RAPIDS平台的主要功能 1.linux环境下pip安装 pip install cuml-cu1224.6.0 --extra-index-urlhttps://pypi.nvidia.com 安装过程中可能会提示缺少包之类的&#xff0c;按提示进行包的缺失安装 2.安装…