从寒假开始接触推荐系统,前期也花了一定的时间去学习了一下python,推荐系统的书籍看的是比较出名的《推荐系统实践》项亮编著。写篇博客,以供日后的学习或使用。

转载请注明出处:点击打开链接 <http://blog.csdn.net/sinat_35866463/article/details/79428898>




《推荐系统实践》项亮编著PDF版资源:https://pan.baidu.com/s/1i7nIIZ7
<https://pan.baidu.com/s/1i7nIIZ7> 密码: 147t
  如果看完了本篇文章后,想要继续了解ItemCF,详情链接:点击打开链接
<http://blog.csdn.net/sinat_35866463/article/details/79437675>




推荐系统之基于用户的协同过滤算法(UserCF)





基于用户的协同过滤算法(User Based Collaborative Filtering),简称UserCF,

算法的核心思想很简单,




通俗的讲,要给A用户推荐物品,先从计算一下其他用户与A用户的用户相似度,比如说这里面B,C用户和A
用户的用户相似度最高(意思就是说,B,C与A的兴趣最相似),那么再从B,C用户中推荐一些B,C用户喜欢的东西,并且A用户没有浏览(没有购买等等)的物品给A用户,从而实现个性化推荐,这就是所谓的基于用户的协同过
滤算法。




步骤如下:




一、找到和目标用户兴趣相似的用户集合——计算两个用户的兴趣相似度

二、找到这个集合中的用户喜欢的,且目标用户没有听说过的物品推荐给目标用户







第一步:

利用行为的相似度计算兴趣的相似度,给定用户u和用户v,令N(u)表示用户u感兴趣的物品集合,N(v)表示
用户v感兴趣的物品集合,那么可以通过Jaccard公式或者通过余弦相似度公式计算:

Jaccard公式:




余弦相似度公式:





 ps:本文最后的DEMO代码最终采用的是余弦相似度公式




以《推荐系统时间》书上的案例为例:

A用户对物品{a,b,d}有过行为,B用户对物品{a,c}有过行为,利用余弦相似度公式计算用户A和用户B 的兴趣相似度:







同理我们可以得到A用户与其他几个用户的相似度:





利用这种方式我们就能得到所有用户两两之间的兴趣相似度,但是仔细思考的读者,也能发现,这个算法的时间复杂度已经达到了O(N^2),在用户量很大的时候,效率就很低了,并不是所有的用户之间都有过相同的购买记录,也就是说,当两个用户之间没有相同的购买记录时,我们就无需在计算他们两个的相似度(没有相同的行为,就视为相似度为0),这样就能减少我们的运算,因此,我们可以换一个思路:




建立物品到用户的倒查表C,表示该物品被哪些用户产生过行为;


根据倒查表C,建立用户相似度矩阵W:在C中,对于每一个物品i,设其对应的用户为u,v,在W中,更新相应的元素值,W[u][v]+=1,最终得到的W,就是用来计算余弦相似度的分子不为0的部分,最后,再除以分母即可得到最终的用户兴趣相似度。










第二步:

得到了用户之间的兴趣相似度之后,通过以下公式度量UserCF算法中用户u对物品的感兴趣程度:







根据上面所得到的东西,我们设定k=3,用户A对物品c,e没有过行为记录,因此可以把这两个物品推荐给用户A:




从而我们在实际的操作中,就可以根据最后得到的p,推荐给用户rank前N的物品







相信,读者看完之后,多多少少对于UserCF
有了一定的了解,小编也是在最近在根据书本上的伪代码用python进行了编写,不过,最近在github上寻到大牛已经写好的UserCF以及ItemCF,还有可供下载的数据,所以也是放在这里供大家学习。

代码来源:https://github.com/Lockvictor/MovieLens-RecSys
<https://github.com/Lockvictor/MovieLens-RecSys>







#-*- coding: utf-8 -*- ''' Created on 2015-06-22 @author: Lockvictor '''
import sys import random import math import os from operator import itemgetter
random.seed(0) class UserBasedCF(object): ''' TopN recommendation - User Based
Collaborative Filtering ''' def __init__(self): self.trainset = {} self.testset
= {} self.n_sim_user = 20 self.n_rec_movie = 10 self.user_sim_mat = {}
self.movie_popular = {} self.movie_count = 0 print ('Similar user number = %d'
% self.n_sim_user, file=sys.stderr) print ('recommended movie number = %d' %
self.n_rec_movie, file=sys.stderr) @staticmethod def loadfile(filename): '''
load a file, return a generator. ''' fp = open(filename, 'r') for i, line in
enumerate(fp): yield line.strip('\r\n') if i % 100000 == 0: print ('loading
%s(%s)' % (filename, i), file=sys.stderr) fp.close() print ('load %s succ' %
filename, file=sys.stderr) def generate_dataset(self, filename, pivot=0.7): '''
load rating data and split it to training set and test set ''' trainset_len = 0
testset_len = 0 for line in self.loadfile(filename): user, movie, rating, _ =
line.split('::') # split the data by pivot if random.random() < pivot:
self.trainset.setdefault(user, {}) self.trainset[user][movie] = int(rating)
trainset_len += 1 else: self.testset.setdefault(user, {})
self.testset[user][movie] = int(rating) testset_len += 1 print ('split training
set and test set succ', file=sys.stderr) print ('train set = %s' %
trainset_len, file=sys.stderr) print ('test set = %s' % testset_len,
file=sys.stderr) def calc_user_sim(self): ''' calculate user similarity matrix
''' # build inverse table for item-users # key=movieID, value=list of userIDs
who have seen this movie print ('building movie-users inverse table...',
file=sys.stderr) movie2users = dict() for user, movies in
self.trainset.items(): for movie in movies: # inverse table for item-users if
movie not in movie2users: movie2users[movie] = set()
movie2users[movie].add(user) # count item popularity at the same time if movie
not in self.movie_popular: self.movie_popular[movie] = 0
self.movie_popular[movie] += 1 print ('build movie-users inverse table succ',
file=sys.stderr) # save the total movie number, which will be used in
evaluation self.movie_count = len(movie2users) print ('total movie number = %d'
% self.movie_count, file=sys.stderr) # count co-rated items between users
usersim_mat = self.user_sim_mat print ('building user co-rated movies
matrix...', file=sys.stderr) for movie, users in movie2users.items(): for u in
users: for v in users: if u == v: continue usersim_mat.setdefault(u, {})
usersim_mat[u].setdefault(v, 0) usersim_mat[u][v] += 1 print ('build user
co-rated movies matrix succ', file=sys.stderr) # calculate similarity matrix
print ('calculating user similarity matrix...', file=sys.stderr)
simfactor_count = 0 PRINT_STEP = 2000000 for u, related_users in
usersim_mat.items(): for v, count in related_users.items(): usersim_mat[u][v] =
count / math.sqrt( len(self.trainset[u]) * len(self.trainset[v]))
simfactor_count += 1 if simfactor_count % PRINT_STEP == 0: print ('calculating
user similarity factor(%d)' % simfactor_count, file=sys.stderr) print
('calculate user similarity matrix(similarity factor) succ', file=sys.stderr)
print ('Total similarity factor number = %d' % simfactor_count,
file=sys.stderr) def recommend(self, user): ''' Find K similar users and
recommend N movies. ''' K = self.n_sim_user N = self.n_rec_movie rank = dict()
watched_movies = self.trainset[user] for similar_user, similarity_factor in
sorted(self.user_sim_mat[user].items(), key=itemgetter(1), reverse=True)[0:K]:
for movie in self.trainset[similar_user]: if movie in watched_movies: continue
# predict the user's "interest" for each movie rank.setdefault(movie, 0)
rank[movie] += similarity_factor # return the N best movies return
sorted(rank.items(), key=itemgetter(1), reverse=True)[0:N] def evaluate(self):
''' print evaluation result: precision, recall, coverage and popularity '''
print ('Evaluation start...', file=sys.stderr) N = self.n_rec_movie # varables
for precision and recall hit = 0 rec_count = 0 test_count = 0 # varables for
coverage all_rec_movies = set() # varables for popularity popular_sum = 0 for
i, user in enumerate(self.trainset): if i % 500 == 0: print ('recommended for
%d users' % i, file=sys.stderr) test_movies = self.testset.get(user, {})
rec_movies = self.recommend(user) for movie, _ in rec_movies: if movie in
test_movies: hit += 1 all_rec_movies.add(movie) popular_sum += math.log(1 +
self.movie_popular[movie]) rec_count += N test_count += len(test_movies)
precision = hit / (1.0 * rec_count) recall = hit / (1.0 * test_count) coverage
= len(all_rec_movies) / (1.0 * self.movie_count) popularity = popular_sum /
(1.0 * rec_count) print
('precision=%.4f\trecall=%.4f\tcoverage=%.4f\tpopularity=%.4f' % (precision,
recall, coverage, popularity), file=sys.stderr) if __name__ == '__main__':
ratingfile = os.path.join('ml-1m', 'ratings.dat') usercf = UserBasedCF()
usercf.generate_dataset(ratingfile) usercf.calc_user_sim() usercf.evaluate()

文章的开头也给出了项亮编著《推荐系统实践》pdf的资源,如果在阅读此文章时,有很多疑惑,建议先读读书上的代码,小编也是刚接触这本书不久,看完了协同过滤的部分,再读大牛写的UserCF,都还是能看懂的。


友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信