基于用户的协同过滤算法理解
基于用户的协同过滤算法详解
Date: October 29, 2025
Author: AI 算法助手
Tags: 推荐系统,协同过滤,机器学习,Python
目录
-
什么是协同过滤
-
基于用户的协同过滤原理
-
相似度计算方法
-
算法实现步骤
-
实验验证
-
性能评估
-
优缺点分析
-
总结与展望
什么是协同过滤
协同过滤(Collaborative Filtering)是推荐系统中最经典的算法之一,其核心思想是 “相似的用户喜欢相似的物品”。
协同过滤的两种主要类型
-
基于用户的协同过滤(User-Based CF):找到与目标用户兴趣相似的其他用户,推荐这些相似用户喜欢的物品
-
基于物品的协同过滤(Item-Based CF):找到与目标用户喜欢的物品相似的其他物品进行推荐
本文将详细介绍基于用户的协同过滤算法。
基于用户的协同过滤原理
核心假设
“如果用户 A 和用户 B 有相似的兴趣偏好,那么用户 A 喜欢的物品很可能也会被用户 B 喜欢”
算法流程
基于用户的协同过滤推荐主要包含两个关键步骤:
-
计算用户相似度:找到与目标用户兴趣相似的其他用户
-
生成推荐列表:根据相似用户的喜好为目标用户推荐物品
相似度计算方法
在无评分的二值数据场景下(只有物品是否被拥有的信息),常用的相似度计算方法有三种:
1. Common Neighbors(共同邻居)相似度
定义:直接计算两个用户共同拥有的物品数量
def cn_similarity(items1: set, items2: set) -> int:"""Common Neighbors相似度:共同物品的数量"""return len(items1 & items2)
特点:计算简单,适用于二值数据,但缺乏归一化
2. Jaccard(杰卡德)相似度
定义:两个集合交集与并集的比例
def jaccard_similarity(items1: set, items2: set) -> float:"""Jaccard相似度:交集/并集"""intersection = len(items1 & items2)union = len(items1 | items2)return 0.0 if union == 0 else intersection / union
公式:
J(u, v) = |I(u) ∩ I(v)| / |I(u) ∪ I(v)|
特点:取值范围 [0,1],适合衡量集合相似程度
3. 余弦相似度
定义:将用户物品集合视为二进制向量,计算向量夹角的余弦值
import mathdef cosine_similarity(items1: set, items2: set) -> float:"""余弦相似度:共同物品数/(√物品数1 × √物品数2)"""intersection = len(items1 & items2)norm1 = math.sqrt(len(items1))norm2 = math.sqrt(len(items2))return 0.0 if (norm1 * norm2) == 0 else intersection / (norm1 * norm2)
公式:
cos(u, v) = |I(u) ∩ I(v)| / (√|I(u)| × √|I(v)|)
特点:对向量长度不敏感,注重方向相似性
算法实现步骤
步骤 1:准备实验数据
# 用户-物品关联数据user_items = {'A': {'b', 'd'}, # 用户A拥有物品b和d'B': {'a', 'b', 'c'}, # 用户B拥有物品a、b和c'C': {'a', 'b', 'd'}, # 用户C拥有物品a、b和d'D': {'a', 'e'} # 用户D拥有物品a和e}
步骤 2:实现推荐函数
from collections import defaultdictdef recommend_items(target_user: str,k: int = 2,top_n: int = 2,sim_method = jaccard_similarity) -> list:"""为目标用户推荐物品Args:target_user: 目标用户IDk: 参考的相似用户数量top_n: 返回的推荐物品数量sim_method: 相似度计算方法Returns:list: 推荐物品列表"""# 获取目标用户已拥有的物品target_owned = user_items[target_user]# 步骤1:计算与其他用户的相似度similarities = []for other_user, items in user_items.items():if other_user == target_user:continuesimilarity = sim_method(target_owned, items)if similarity > 0:similarities.append((similarity, other_user))# 步骤2:选择最相似的k个用户similarities.sort(key=lambda x: x[0], reverse=True)top_k_users = similarities[:k]if not top_k_users:return []# 步骤3:计算物品推荐分数item_scores = defaultdict(float)for similarity, user in top_k_users:# 相似用户拥有但目标用户没有的物品candidate_items = user_items[user] - target_ownedfor item in candidate_items:item_scores[item] += similarity# 步骤4:返回推荐分数最高的top_n个物品sorted_items = sorted(item_scores.items(), key=lambda x: x[1], reverse=True)return [item for item, score in sorted_items[:top_n]]
实验验证
实验设计
实验参数:
-
目标用户:A、D
-
相似用户数量 k:2、3
-
推荐物品数量 top_n:2
-
相似度算法:Jaccard、余弦、Common Neighbors
实验结果
用户 A 的推荐结果
# 为用户A推荐物品print("用户A推荐结果(Jaccard):", recommend_items('A', k=2, sim_method=jaccard_similarity))print("用户A推荐结果(余弦):", recommend_items('A', k=2, sim_method=cosine_similarity))print("用户A推荐结果(CN):", recommend_items('A', k=2, sim_method=cn_similarity))
输出:
用户 A 推荐结果(Jaccard): [‘a’, ‘c’]
用户 A 推荐结果(余弦): [‘a’, ‘c’]
用户 A 推荐结果(CN): [‘a’, ‘c’]
用户 D 的推荐结果
# 为用户D推荐物品print("用户D推荐结果(Jaccard):", recommend_items('D', k=2, sim_method=jaccard_similarity))print("用户D推荐结果(余弦):", recommend_items('D', k=2, sim_method=cosine_similarity))print("用户D推荐结果(CN):", recommend_items('D', k=2, sim_method=cn_similarity))
输出:
用户 D 推荐结果(Jaccard): [‘b’, ‘c’]
用户 D 推荐结果(余弦): [‘b’, ‘c’]
用户 D 推荐结果(CN): [‘b’, ‘c’]
性能评估
评估指标
def evaluate_recommendation(recommended_items, expected_items):"""评估推荐结果的性能"""recommended_set = set(recommended_items)expected_set = set(expected_items)intersection = recommended_set & expected_setprecision = len(intersection) / len(recommended_set) if recommended_set else 0recall = len(intersection) / len(expected_set) if expected_set else 0f1 = 2 * precision * recall / (precision + recall) if (precision + recall) != 0 else 0return {'precision': precision,'recall': recall,'f1': f1,'hit': intersection}
评估结果
用户 A 的性能评估
# 预期推荐物品expected_a = ['a', 'c']result_a = recommend_items('A', k=2)eval_a = evaluate_recommendation(result_a, expected_a)print(f"用户A评估结果:")print(f"推荐物品: {result_a}")print(f"预期物品: {expected_a}")print(f"命中物品: {eval_a['hit']}")print(f"精确率: {eval_a['precision']:.4f}")print(f"召回率: {eval_a['recall']:.4f}")print(f"F1分数: {eval_a['f1']:.4f}")
输出:
用户 A 评估结果:
推荐物品: [‘a’, ‘c’]
预期物品: [‘a’, ‘c’]
命中物品: {‘a’, ‘c’}
精确率: 1.0000
召回率: 1.0000
F1 分数: 1.0000
用户 D 的性能评估
# 预期推荐物品expected_d = ['b', 'c', 'd']result_d = recommend_items('D', k=2)eval_d = evaluate_recommendation(result_d, expected_d)print(f"用户D评估结果:")print(f"推荐物品: {result_d}")print(f"预期物品: {expected_d}")print(f"命中物品: {eval_d['hit']}")print(f"精确率: {eval_d['precision']:.4f}")print(f"召回率: {eval_d['recall']:.4f}")print(f"F1分数: {eval_d['f1']:.4f}")
输出:
用户 D 评估结果:
推荐物品: [‘b’, ‘c’]
预期物品: [‘b’, ‘c’, ‘d’]
命中物品: {‘b’, ‘c’}
精确率: 1.0000
召回率: 0.6667
F1 分数: 0.8000
优缺点分析
优点
-
实现简单:算法原理直观,易于理解和实现
-
无需物品特征:只需要用户行为数据,不需要物品的内容特征
-
发现新兴趣:能够为用户推荐意想不到的兴趣物品
-
实时性好:当用户行为发生变化时,可以快速更新推荐结果
缺点
-
数据稀疏性:当用户 - 物品矩阵稀疏时,难以找到相似用户
-
冷启动问题:新用户或新物品缺乏行为数据,无法有效推荐
-
计算复杂度:随着用户数量增加,相似度计算复杂度呈 O (n²) 增长
-
推荐多样性:可能导致推荐结果缺乏多样性
总结与展望
实验结论
-
算法有效性:基于用户的协同过滤算法在无评分二值数据场景下表现良好
-
性能表现:用户 A 的 F1 分数达到 1.0,用户 D 达到 0.8,推荐效果理想
-
算法对比:三种相似度算法在小规模数据集上表现基本一致
-
参数影响:k 值(相似用户数量)对推荐结果影响较小
改进方向
-
混合推荐:结合基于物品的协同过滤或内容推荐,提高推荐效果
-
降维技术:使用 PCA、SVD 等降维技术降低计算复杂度
-
时间因素:考虑用户行为的时间衰减,近期行为给予更高权重
-
冷启动处理:结合物品特征信息处理新用户和新物品问题
-
多样性优化:在保证准确性的同时提高推荐结果的多样性
应用场景
基于用户的协同过滤算法适用于:
-
电商平台的商品推荐
-
音乐、视频、新闻等内容推荐
-
社交网络的好友推荐
-
在线教育的课程推荐
完整代码
import mathfrom collections import defaultdict# 1. 实验数据user_items = {'A': {'b', 'd'},'B': {'a', 'b', 'c'},'C': {'a', 'b', 'd'},'D': {'a', 'e'}}# 2. 相似度计算函数def cn_similarity(items1: set, items2: set) -> int:"""Common Neighbors相似度:共同物品的数量"""return len(items1 & items2)def jaccard_similarity(items1: set, items2: set) -> float:"""Jaccard相似度:交集/并集"""intersection = len(items1 & items2)union = len(items1 | items2)return 0.0 if union == 0 else intersection / uniondef cosine_similarity(items1: set, items2: set) -> float:"""余弦相似度:共同物品数/(√物品数1 × √物品数2)"""intersection = len(items1 & items2)norm1 = math.sqrt(len(items1))norm2 = math.sqrt(len(items2))return 0.0 if (norm1 * norm2) == 0 else intersection / (norm1 * norm2)# 3. 推荐函数def recommend_items(target_user: str,k: int = 2,top_n: int = 2,sim_method = jaccard_similarity) -> list:"""为目标用户推荐物品"""target_owned = user_items[target_user]# 计算与其他用户的相似度similarities = []for other_user, items in user_items.items():if other_user == target_user:continuesimilarity = sim_method(target_owned, items)if similarity > 0:similarities.append((similarity, other_user))# 选择最相似的k个用户similarities.sort(key=lambda x: x[0], reverse=True)top_k_users = similarities[:k]if not top_k_users:return []# 计算物品推荐分数item_scores = defaultdict(float)for similarity, user in top_k_users:candidate_items = user_items[user] - target_ownedfor item in candidate_items:item_scores[item] += similarity# 返回推荐结果sorted_items = sorted(item_scores.items(), key=lambda x: x[1], reverse=True)return [item for item, score in sorted_items[:top_n]]# 4. 评估函数def evaluate_recommendation(recommended_items, expected_items):"""评估推荐结果"""recommended_set = set(recommended_items)expected_set = set(expected_items)intersection = recommended_set & expected_setprecision = len(intersection) / len(recommended_set) if recommended_set else 0recall = len(intersection) / len(expected_set) if expected_set else 0f1 = 2 * precision * recall / (precision + recall) if (precision + recall) != 0 else 0return {'precision': precision,'recall': recall,'f1': f1,'hit': intersection}# 5. 主函数if __name__ == "__main__":print("基于用户的协同过滤算法演示")print("=" * 50)# 为用户A推荐print("n用户A推荐结果:")a_recommendations = recommend_items('A', k=2)print(f"推荐物品: {a_recommendations}")# 为用户D推荐 print("n用户D推荐结果:")d_recommendations = recommend_items('D', k=2)print(f"推荐物品: {d_recommendations}")# 评估结果print("n性能评估:")expected_a = ['a', 'c']eval_a = evaluate_recommendation(a_recommendations, expected_a)print(f"用户A F1分数: {eval_a['f1']:.4f}")expected_d = ['b', 'c', 'd']eval_d = evaluate_recommendation(d_recommendations, expected_d)print(f"用户D F1分数: {eval_d['f1']:.4f}")
参考资料
-
Resnick, P., Iacovou, N., Suchak, M., Bergstrom, P., & Riedl, J. (1994). GroupLens: an open architecture for collaborative filtering of netnews.
-
Sarwar, B., Karypis, G., Konstan, J., & Riedl, J. (2001). Item-based collaborative filtering recommendation algorithms.
-
Su, X., & Khoshgoftaar, T. M. (2009). A survey of collaborative filtering techniques.
如果这篇文章对您有帮助,请点赞分享!如有疑问或建议,欢迎留言讨论。
