协同过滤原理&实现
🏅

协同过滤原理&实现

text
对协同过滤算法进行实现,包括原理,代码实现,工程应用细节等都进行考虑
Tags
机器学习
推荐系统
Created
Jul 13, 2022 08:00 AM

什么是协同过滤

“协同过滤”就是协同大家的反馈、评价和意见一起对海量的信息进行过滤,从中筛选出目标用户可能感兴趣的信息的推荐过程——《深度学习推荐系统》
notion image

优缺点

优点

  • 算法原理简单,思想朴素;
  • 算法易于分布式实现,可以处理海量数据集;
  • 能够为用户推荐多样性、新颖性的物品;

缺点:

  • 冷启动问题;
  • 稀疏性问题:用户/物品的行为矩阵非常稀疏;泛化能力不够;
  • 只利用了用户-物品的交互行为,没有利用更多信息;

应用场景

  • UserCF基于用户相似度进行推荐,有较强的社交特性,适用于新闻推荐场景,因为新闻本身的兴趣点是分散的,及时性、热点性更加重要;
  • ItemCF适用于兴趣变化比较稳定的应用,例如电影推荐;

代码实现

# ItemCF算法 # 统计所有电影之间相似度,存入数组中 def all_movies_sim(self): arr_movies = list(np.array(self.users_movies).transpose()) # 计算电影相似度时,将原数组行转列 dp = calculate_sim(arr_movies, self.t) return dp # 相似电影推荐 def rec_movies(self, user, k): m = self.users.index(user) # 用户user下标 looked = self.users_movies[m] # 用户m的电影队列 assert len(looked) == len(self.scores[m]), 'Unequal lengths' # candidate[1]需要是一个数值越大排名越前的数组,所以取负 candidate = [[self.movies[i], -round(self.scores[m][i], 3)] for i in range(len(looked)) if looked[i] == 0] res = top_k(candidate, k) return res # 输出电影列表
# UserCF算法 def all_users_sim(self): dp = calculate_sim(self.users_movies, self.t) return dp # 先输出最相似的k1个用户,再利用权重输出没看过电影的得分,输出前k2个电影作为推荐 def rec_movies(self, user, k1, k2): m = self.users.index(user) score = [0] * len(self.movies) # 初始分数为0 looked = self.users_movies[m] # 用户m的电影队列 tmp = [] if self.t == 'euc': # 输出top k1个用户 candidate_user = [[self.users[i], -round(self.scores[m][i], 3)] for i in range(len(self.users)) if self.users[i] != user] res_user = top_k(candidate_user, k1) # 权重计算为1/-res_user[i][0],结果为正数且数字越大排名越前 tmp = [[self.users.index(res_user[i][1]), 1 / -res_user[i][0]] for i in range(len(res_user))] if self.t == 'pea': candidate_user = [[self.users[i], round(self.scores[m][i], 3)] for i in range(len(self.users)) if self.users[i] != user] res_user = top_k(candidate_user, k1) # 因为结果为正数且数字越大排名越前,所以不做处理 tmp = [[self.users.index(res_user[i][1]), res_user[i][0]] for i in range(len(res_user))] for x in tmp: score = [score[i] + self.users_movies[x[0]][i] * x[1] for i in range(len(score))] # 利用权重计算总分数 candidate_score = [[self.movies[i], score[i]] for i in range(len(looked)) if looked[i] == 0] # 输出top k2个电影 res = top_k(candidate_score, k2) return res

实践考虑

  • 用户或物品相似度进行存储,空间复杂度为 ,当 过大时将难以存储,可以考虑分布式存储;
  • 相似度计算可以有多种计算方式,包括欧氏距离、皮尔逊相关系数等;
  • 当针对某一用户User进行推荐时,考虑输出top k的推荐,利用最小堆来进行实现,时间复杂度为 ;

参考