前言
一般来说,协同过滤推荐算法分为三种类型。
- 基于物品(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都用了杰卡德相似系数来计算相似度矩阵,所以两者最终的推荐结果有三部电影是相同的