基於物品的協同過濾算法


輸入

  輸入:物品用戶行為矩陣,行為矩陣中的元素只有0和1,0代表行為的負類,1代表行為的正類。比如不喜歡與喜歡、不點贊與點贊、不收藏與收藏。

輸出

  輸出1:根據輸入可計算得到物品相似度矩陣;

  輸出2:根據輸入中物品用戶行為矩陣得到用戶喜歡的物品,用戶喜歡的物品結合輸出1得到的物品相似度矩陣,可以計算得到用戶喜歡度最高的k個物品,並推薦給用戶。

前言

  基於物品的協同過濾算法適用於物品數明顯小於用戶數的場景,適用於長尾物品豐富,用戶個性化需求強烈的領域。但是該算法不適用於物品變化較快的場景,比如新聞類的應用,如果物品一直在變化,那么會增加物品相似度更新的頻率,不夠穩定,此類場景下可以考慮選擇基於用戶的協同過濾算法。

原理

  基於物品的協同過濾誕生於1998年,是由亞馬遜首先提出,適用於用戶明顯多於物品的情況。基於物品的協同過濾算法的原始想法是:給用戶推薦用戶喜歡的物品相似的物品。問題在於“相似的物品”是如何度量的,基於內容的推薦系統中,物品相似是用內容的相似性計算出來的,但是實際上人的群體行為還是會有一些內容特征抓不到的相似性。

  在基於物品的協同過濾之前,最常用的是基於用戶的協同過濾。基於用戶的協同過濾首秀按計算相似用戶,然后再根據相似用戶的喜好推薦物品,但是基於用戶的協同過濾存在以下問題:

  1. 用戶的數量往往很多,用戶之間相似度計算起來工作量大;
  2. 用戶的興趣愛好變化較快,所以這個動態變化的過程很難被跟蹤和記錄。

  基於物品的協同過濾可以較好的解決上面的問題。物品的數量遠遠少於用戶的數量,而且物品之間的相似度不易改變,物品對應的消費者數量大,所以計算出來的物品相似度比較可靠。 

  協同過濾算法依賴於用戶物品之間的關系矩陣(如表1所示)。基於物品的協同過濾算法除了依賴用戶物品之間的關系矩陣,還依賴於物品之間的相似度矩陣(如表2所示)。

 

  計算物品的相似度有好幾種方法,比如余弦相似度、傑卡德(Jaccard)相似度,余弦相似度適用於評分數據,傑卡德(Jaccard)相似度適用於隱式反饋數據,由於這里使用的用戶戶物品矩陣是隱式反饋數據,所以介紹下Jaccard相似度的計算公式:

   

  式子表示的是物品M與N的相似度,其中表示喜歡物品M的用戶的集合,表示喜歡物品N的用戶的集合,分子為同時喜歡物品M,N的用戶集合,分母為喜歡物品M,N的用戶集合的並集。

  通過上面的公式計算得到物品相似度矩陣后,就可以結合用戶已經喜歡過的物品集合給用戶推薦物品了,可以通過下面的公式計算用戶對待推薦物品的評分:

  計算用戶u對物品i的評分,需要遍歷用戶喜歡過的物品集合A,對於集合A中的任意物品j,求用戶u對j評分與物品i、j的相似度sim(i,j)之積,然后累加得到用戶u對物品i的評分。

  可以依次求得用戶u對所有物品的評分,去掉用戶已經喜歡過的物品后,保留分數最高的N個結果推薦給用戶u。

python代碼實現

 1 #1、手動構造一個用戶物品行為矩陣,行為物品,列為用戶,矩陣元素值為(0,1),0代表不感興趣,1代表感興趣
 2 #2、根據用戶行為矩陣,計算出物品相似度矩陣
 3 #3、根據物品相似度矩陣以及用戶喜歡的物品推薦出TopN個物品
 4 import numpy as np
 5 # 100*200的物品用戶行為矩陣
 6 item_user_matrix = np.random.randint(0,2,size=(100, 200),dtype=np.int)
 7 
 8 # 計算物品的相似度矩陣sim,形狀為100*100
 9 # 對於隱式反饋數據,使用傑卡德(Jaccard)相似系數計算物品的相似度,sim(i,j)表示物品i與物品j的相似度,
10 # 等於同時喜歡物品i和j的用戶數除以喜歡物品i和物品j的用戶總數
11 rowNum = item_user_matrix.shape[0]
12 columNum = item_user_matrix.shape[0]
13 sim_matrix = np.zeros((rowNum, columNum)).astype('float')
14 #同時喜歡下標為colum的物品和下標為row的物品的用戶數
15 columAndRow_NUM = 0
16 #喜歡下標為colum的物品的用戶數與喜歡下標為row的物品的用戶數之和
17 columOrRow_NUM = 0
18 for row in range(0, rowNum):
19     for colum in range(0, columNum):
20         if colum < row: # 只需要對矩陣下三角更新
21             # 因為矩陣元素只有0和1,求點積即為交集
22             columAndRow_NUM = np.dot(item_user_matrix[colum], item_user_matrix[row])
23             # 元素相加求和,就求得並集
24             columOrRow_NUM = item_user_matrix[colum].sum() + item_user_matrix[row].sum()
25             sim_matrix[row][colum] = columAndRow_NUM/columOrRow_NUM
26             print('columAndRow_NUM:{}, columOrRow_NUM:{}, sim_matrix[{}][{}]:{}'.
27                   format(columAndRow_NUM,columOrRow_NUM, row, colum, sim_matrix[row][colum]))
28 
29 # 根據物品相似度矩陣以及用戶喜歡的物品推薦出TopN個物品
30 # 欲求用戶user對物品i的喜歡度,首先求出用戶user喜歡的物品集合,根據物品相似度矩陣,求出物品i與用戶user喜歡的物品對應的相似度
31 # 相似度與喜歡度相乘求和,除以相似度之和,得到的商為用戶user對物品i的相似度
32 # 求得喜歡度之后,選擇topN個做推薦
33 def topNrecom(user, N):
34     # 字典的鍵為物品下標編號,值為喜歡度
35     result = {}
36     # user對應的物品向量
37     itemVec = item_user_matrix[:,user]
38     for item in range(0,rowNum):
39         # 直接做點積即可,因為用戶還沒有發生行為的物品喜歡度為0,與相似度相乘還是0,無影響
40         user_item_sim_sum = np.dot(itemVec, sim_matrix[item])
41         result[item] = user_item_sim_sum;
42     # 從result中去掉用戶已經發生過行為的物品,然后再推薦出預測喜歡度較高的top N個物品
43     for index in range(0, len(itemVec)):
44         if(1 == itemVec[index]):
45             result.pop(index)
46     return sorted(result.items() , key=lambda x: x[1], reverse=True)[:N]
47 
48 user = 122
49 N = 10
50 itemList = topNrecom(user, N)
51 print('user[{}] top [{}] recom result:{}'.format(user, N, itemList))

代碼運行結果

  本文代碼手動構造了一個100*200的物品用戶行為矩陣,實際工業環境中肯定不止這點數據量,本中重點在於講解原理和一種實現方法,對於某個用戶而言,推薦喜歡度最高的10個物品,代碼運行結果如下:

1 user[122] top [10] recom result:[(98, 13.734837466951667), (97, 13.534563830373337), (90, 12.351537112348055), (94, 12.194631579469013), (82, 11.25929195188074), (84, 10.662303442296619), (80, 10.60327372276929), (79, 10.570187047487309), (77, 9.94780886977415), (69, 8.431845325504977)]

  按照喜歡度從高到底排序,推薦的物品id為98、97、90、94、82、84、80、79、77、69。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM