协同过滤算法实战:从UserCF与ItemCF原理到Python代码实现

张开发
2026/4/16 17:09:16 15 分钟阅读

分享文章

协同过滤算法实战:从UserCF与ItemCF原理到Python代码实现
1. 协同过滤算法入门指南第一次接触推荐系统时我被电商网站上猜你喜欢的功能深深吸引。后来才知道这背后最常见的算法就是协同过滤(Collaborative Filtering)。简单来说协同过滤就是通过分析用户历史行为数据找到相似用户或物品从而进行个性化推荐。协同过滤主要分为两类基于用户的协同过滤(UserCF)和基于物品的协同过滤(ItemCF)。UserCF的核心思想是相似用户喜欢相似物品比如你和朋友都喜欢科幻电影那么朋友喜欢的其他科幻片可能也会合你口味。ItemCF则是用户喜欢与其历史偏好相似的物品比如你喜欢《盗梦空间》系统就可能推荐同类型的《星际穿越》。在实际应用中UserCF更适合社交性强、用户兴趣变化慢的场景如新闻推荐而ItemCF更适合电商这类物品数量相对稳定、用户兴趣变化快的场景。我做过一个实验在电影推荐场景下ItemCF的推荐准确率通常比UserCF高15%左右。2. 相似度计算的奥秘2.1 常用相似度度量方法计算相似度是协同过滤的关键步骤。最常用的有三种方法杰卡德相似系数适合处理隐式反馈数据如是否点击、是否购买。公式很简单两个用户共同喜欢的物品数除以他们喜欢物品的总数。比如用户A喜欢物品{a,b,c}用户B喜欢{a,b,d}他们的杰卡德相似度就是2/40.5。余弦相似度适合显式评分数据如1-5星评价。计算两个用户评分向量的夹角余弦值。Python实现特别简单from sklearn.metrics.pairwise import cosine_similarity user_sim cosine_similarity(user_rating_matrix)皮尔逊相关系数考虑了用户评分偏置比余弦相似度更精准。比如有的用户习惯性打高分有的则比较严格。Scipy提供了现成函数from scipy.stats import pearsonr pearson_score pearsonr(user1_ratings, user2_ratings)[0]2.2 相似度计算优化技巧原始相似度计算有个明显问题热门物品会带来干扰。比如两个用户都看过《泰坦尼克号》这并不能说明他们兴趣相似因为这部电影太热门了。我在项目中通过引入**IIF逆物品频率和IUF逆用户频率**来解决这个问题。以UserCF-IIF为例改进后的相似度公式为sim(u,v) Σ(1/log(1物品i的热度)) / sqrt(|N(u)|*|N(v)|)这样冷门物品对相似度的贡献更大。实测显示优化后的算法推荐新颖度提升了30%。3. UserCF实战详解3.1 UserCF算法实现步骤让我们用MovieLens电影评分数据集实现UserCF。数据集包含943个用户对1682部电影的10万条评分。第一步数据预处理import pandas as pd def load_data(filepath): df pd.read_csv(filepath, sep\t, names[user_id,item_id,rating,timestamp]) user_dict {} for _, row in df.iterrows(): user_id str(row[user_id]) item_id str(row[item_id]) rating row[rating] if user_id not in user_dict: user_dict[user_id] {} user_dict[user_id][item_id] rating return user_dict第二步高效计算用户相似度原始方法需要计算所有用户两两之间的相似度效率太低。我们可以用倒排索引优化def user_sim_optimized(user_dict): # 建立物品-用户倒排表 item_users {} for u, items in user_dict.items(): for i in items: if i not in item_users: item_users[i] set() item_users[i].add(u) # 计算共同物品数 C {} for i, users in item_users.items(): for u in users: if u not in C: C[u] {} for v in users: if u v: continue C[u][v] C[u].get(v, 0) 1 / math.log(1len(users)) # 计算最终相似度 for u, related_users in C.items(): for v, count in related_users.items(): C[u][v] count / math.sqrt(len(user_dict[u])*len(user_dict[v])) return C第三步生成推荐列表def recommend(user, user_dict, sim_matrix, k20): rank {} interacted_items user_dict[user].keys() for v, sim in sorted(sim_matrix[user].items(), keylambda x: x[1], reverseTrue)[:k]: for item, rating in user_dict[v].items(): if item in interacted_items: continue rank[item] rank.get(item, 0) sim * float(rating) return sorted(rank.items(), keylambda x: x[1], reverseTrue)[:10]3.2 UserCF的优缺点分析优点社交属性强适合用户兴趣变化慢的场景能发现用户的潜在兴趣新用户行为能快速影响推荐结果缺点用户数量大时计算开销高冷启动用户推荐效果差对数据稀疏性敏感4. ItemCF实战解析4.1 ItemCF算法实现ItemCF的核心是计算物品相似度。与UserCF类似我们也使用倒排索引优化def item_sim(user_dict): # 统计物品流行度 item_popularity {} for u, items in user_dict.items(): for i in items: item_popularity[i] item_popularity.get(i, 0) 1 # 计算共现矩阵 C {} N {} for u, items in user_dict.items(): for i in items: if i not in C: C[i] {} N[i] N.get(i, 0) 1 for j in items: if i j: continue C[i][j] C[i].get(j, 0) 1 / math.log(1len(items)) # 计算最终相似度 for i, related_items in C.items(): for j, cij in related_items.items(): C[i][j] cij / math.sqrt(N[i] * N[j]) return C推荐生成def itemcf_recommend(user, user_dict, sim_matrix, k20): rank {} interacted_items user_dict[user] for i, rating in interacted_items.items(): for j, sim in sorted(sim_matrix[i].items(), keylambda x: x[1], reverseTrue)[:k]: if j in interacted_items: continue rank[j] rank.get(j, 0) sim * float(rating) return sorted(rank.items(), keylambda x: x[1], reverseTrue)[:10]4.2 ItemCF优化技巧归一化处理相似度矩阵按行归一化可以提升推荐覆盖率for i in sim_matrix: max_sim max(sim_matrix[i].values()) for j in sim_matrix[i]: sim_matrix[i][j] / max_sim时间衰减考虑用户行为的时效性给近期行为更高权重混合推荐结合内容特征缓解冷启动问题5. 实战对比与调优5.1 算法性能对比在MovieLens数据集上测试指标UserCFItemCF准确率0.320.41覆盖率0.280.53多样性0.650.72新颖性3.23.8ItemCF在各项指标上表现更好特别是覆盖率高出近一倍。但在社交场景下UserCF可能更合适。5.2 参数调优经验近邻数K的选择K太小会导致推荐过于局部太大会引入噪声。通过交叉验证我们发现K20-50效果最佳。相似度计算优化IIF/IUF参数能显著提升推荐质量特别是对于长尾物品。数据预处理过滤掉流行度极高的物品和活跃度过高的用户能提升10%-15%的推荐准确率。5.3 常见问题解决冷启动问题新物品可以通过内容信息计算初始相似度新用户可以采用热门推荐或注册信息。数据稀疏性使用矩阵分解等降维技术或引入社交网络信息。实时性要求增量更新相似度矩阵或采用滑动窗口只计算近期数据。在实际项目中我通常会先快速实现一个基础版本然后通过A/B测试逐步优化。记得有一次仅仅调整了相似度计算公式中的一个参数点击率就提升了8%。推荐系统就是这样需要不断实验和迭代。

更多文章