前言
一般來說,協同過濾推薦算法分為三種類型。
- 基于物品(item-based)的協同過濾
- 基于使用者(user-based)的協同過濾
- 基于内容(content-based)的協同過濾
本文基于相關的電影訂閱資料對上述協同過濾推薦算法進行實作,每種算法都針對指定的第500位使用者對其推薦5部電影
相關電影資料可到個人百度雲上進行下載下傳,資料集包含了9000多位使用者的563部電影的訂閱資訊(1表示訂閱,0表示不訂閱)
連結:https://pan.baidu.com/s/1LZz58htPOq4F–_9RIJtOg
提取碼:ne3o
算法流程
基于物品(item-based)的協同過濾
- 利用傑卡德相似系數對使用者物品矩陣的轉置和使用者物品矩陣求物品相似度矩陣
- 使用者物品矩陣 * 物品相似度矩陣 = 推薦矩陣
- 根據推薦矩陣選取相關使用者的推薦清單
- 把推薦清單中使用者已訂閱過的電影的推薦權重置為0,按權重大小進行排序
- 選取推薦清單前5項電影作為推薦結果
基于使用者(user-based)的協同過濾
- 利用傑卡德相似系數對使用者物品矩陣和使用者物品矩陣的轉置求使用者相似度矩陣
- 使用者相似度矩陣 * 使用者物品矩陣 = 推薦矩陣
- 根據推薦矩陣選取相關使用者的推薦清單
- 把推薦清單中使用者已訂閱過的電影的推薦權重置為0,按權重大小進行排序
- 選取推薦清單前5項電影作為推薦結果
基于内容(content-based)的協同過濾
- 使用者物品矩陣進行SVD分解,得到相關的使用者特征矩陣和物品特征矩陣
- 使用者特征矩陣和物品特征矩陣求餘弦相似度,得到使用者物品相似度矩陣
- 根據使用者物品相似度矩陣選取相關使用者的使用者物品相似度清單
- 把使用者物品相似度清單中使用者已訂閱過的電影的相似度權重置為0,按權重大小進行排序
- 選取使用者物品相似度清單中前5項電影作為結果
代碼實作
對上述算法流程的代碼實作如下
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import pairwise_distances,cosine_similarity
from scipy.sparse.linalg import svds
class RecommendMovie:
def __init__(self):
self.data = self.loadData()
self.movie_names = self.loadMovieName()
self.user_log = self.getUserLog()
def loadData(self):
"""加載資料集"""
data = pd.read_csv("data/user-shows.txt",sep = " ",header = None)
return data
def loadMovieName(self):
"""加載電影名字資料"""
movie_names = pd.read_csv("data/shows.txt",header=None).values.flatten()
return movie_names
def getUserLog(self):
"""擷取使用者曆史訂閱資訊"""
user_log = list(self.data.iloc[499,:][self.data.iloc[499,:] == 1].index)
return user_log
def getSimilarMatrix(self,a,s1,s2):
"""計算相似度矩陣(傑卡德相似系數)"""
similar_matrix = 1 - pairwise_distances(a,metric = 'jaccard')
for i in range(len(similar_matrix)): # 将對角線值處理為零
similar_matrix[i, i] = 0
similar_matrix = pd.DataFrame(data=similar_matrix,index=s1,columns=s2)
return similar_matrix
def getRecommendMatrix(self,a1,a2):
"""計算推薦矩陣,并得到相關使用者的推薦清單"""
recommend_matrix = np.dot(a1,a2)[499]
recommend_matrix = pd.Series(recommend_matrix,index = self.movie_names).sort_values(ascending = False)
#将使用者訂閱過的電影推薦度置為0,不推薦使用者訂閱過的電影
for i in recommend_matrix:
if i in self.user_log:
recommend_matrix[i] = 0
return recommend_matrix
def itemBaseRecommend(self):
"""基于物品的協同過濾實作"""
item_cor = self.getSimilarMatrix(self.data.values.T,self.movie_names,self.movie_names)
recommend_matrix = self.getRecommendMatrix(self.data.values,item_cor)
recommend_movies = recommend_matrix.head().index.tolist()
print("基于物品推薦的五部電影是",recommend_movies)
def userBaseRecommend(self):
"""基于使用者的協同過濾實作"""
user_cor = self.getSimilarMatrix(self.data.values,self.data.index,self.data.index)
#獲得第500個使用者的推薦清單
recommend_matrix = self.getRecommendMatrix(user_cor,self.data.values)
recommend_movies = recommend_matrix.head().index.tolist()
print("基于使用者推薦的五部電影是",recommend_movies)
def contentBaseRecommend(self):
"""基于内容的協同過濾實作"""
U, s, V = svds(self.data.values.astype('float64'), k = 10)
V = V.T
user_U = U[499:500,:]
feature_similar = cosine_similarity(user_U,V).flatten()
#某使用者喜好和電影特征的相似度矩陣
recommend_matrix = pd.Series(feature_similar,index = self.movie_names).sort_values(ascending = False)
for i in recommend_matrix:
if i in self.user_log:
recommend_matrix[i] = 0
recommend_movies = recommend_matrix.head().index.tolist()
print("基于内容推薦的五部電影是",recommend_movies)
if __name__=="__main__":
recommendMovie = RecommendMovie()
recommendMovie.itemBaseRecommend()
recommendMovie.userBaseRecommend()
recommendMovie.contentBaseRecommend()
最終得到的推薦結果為

由于item-based和user-based都用了傑卡德相似系數來計算相似度矩陣,是以兩者最終的推薦結果有三部電影是相同的