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.pswp.cn/news/40142.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40142.shtml
英文地址,請注明出處:http://en.pswp.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…

Java 中 List 集合排序方法

方式一&#xff1a; 調用List接口自己的sort方法排序 public static void main(String[] args) {List<Integer> numListnew ArrayList<>();numList.add(999);numList.add(123);numList.add(456);numList.add(66);numList.add(9);Collections.sort(numList); //使…

在一小時內構建您的深度學習應用程序

一、說明 我已經做了將近十年的數據分析。有時&#xff0c;我使用機器學習技術從數據中獲取見解&#xff0c;并且我習慣于使用經典 ML。 雖然我已經通過了神經網絡和深度學習的一些MOOC&#xff0c;但我從未在我的工作中使用過它們&#xff0c;這個領域對我來說似乎很有挑戰性。…

【Leetcode】91.解碼方法

一、題目 1、題目描述 一條包含字母 A-Z 的消息通過以下映射進行了 編碼 : A -> "1" B -> "2" ... Z -> "26"要 解碼 已編碼的消息,所有數字必須基于上述映射的方法,反向映射回字母(可能有多種方法)。例如,"11106" …

智能數據建模軟件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;一些開源網站…

node.js內置模塊fs,path,http使用方法

NodeJs中分為兩部分 一是V8引擎為了解析和執行JS代碼。 二是內置API&#xff0c;讓JS能調用這些API完成一些后端操作。 內置API模塊(fs、path、http等) 第三方API模塊(express、mysql等) fs模塊 fs.readFile()方法&#xff0c;用于讀取指定文件中的內容。 fs.writeFile()方…

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

全新重構,探尋 24 歲 QQ 大重構背后的思考

在瞬息萬變的互聯網行業中,年過二十四的 QQ 堪稱超長壽的產品,見證了中國互聯網崛起的完整歷程。然而,如今這個元老級產品經歷了一次從內到外徹底的重構。 在這次重構中,QQ 選擇了 Electron 作為 UI 跨平臺開發框架。盡管 Electron 被 Slack、Visual Studio Code 和 Disco…

[Go版]算法通關村第十一關青銅——理解位運算的規則

目錄 數字在計算機中的表示&#xff1a;機器數、真值對機器數進一步細化&#xff1a;原碼、反碼、補碼為何會有原碼、反碼和補碼為何計算機中的按位運算使用的是補碼&#xff1f;位運算規則與、或、異或和取反移位運算移位運算與乘除法的關系位運算常用技巧?? 操作某個位的數…

Unity用NPOI創建Exect表,保存數據,和修改刪除數據。以及打包后的坑——無法打開新創建的Exect表

先說坑花了一下午才找到解決方法解決&#xff0c; 在Unity編輯模式下點擊物體創建對應的表&#xff0c;獲取物體名字與在InputText填寫的注釋數據。然后保存。創建Exect表可以打開&#xff0c;打包PC后&#xff0c;點擊物體創建的表&#xff0c;打不開文件破損 解決方法&#…

大數據培訓前景怎么樣?企業需求量大嗎

大數據行業對大家來說并不陌生&#xff0c;大數據行業市場人才需求量大&#xff0c;越早入行越有優勢&#xff0c;發展機會和上升空間等大。不少人通過大數據培訓來提升自己的經驗和自身技術能力&#xff0c;以此來獲得更好的就業機會。 2023大數據培訓就業前景怎么樣呢?企業需…