当前位置: 首页 > news >正文

基于用户的协同过滤算法理解

基于用户的协同过滤算法详解

Date: October 29, 2025

Author: AI 算法助手

Tags: 推荐系统,协同过滤,机器学习,Python


目录

  1. 什么是协同过滤

  2. 基于用户的协同过滤原理

  3. 相似度计算方法

  4. 算法实现步骤

  5. 实验验证

  6. 性能评估

  7. 优缺点分析

  8. 总结与展望


什么是协同过滤

协同过滤(Collaborative Filtering)是推荐系统中最经典的算法之一,其核心思想是 “相似的用户喜欢相似的物品”。

协同过滤的两种主要类型

  • 基于用户的协同过滤(User-Based CF):找到与目标用户兴趣相似的其他用户,推荐这些相似用户喜欢的物品

  • 基于物品的协同过滤(Item-Based CF):找到与目标用户喜欢的物品相似的其他物品进行推荐

本文将详细介绍基于用户的协同过滤算法。


基于用户的协同过滤原理

核心假设

“如果用户 A 和用户 B 有相似的兴趣偏好,那么用户 A 喜欢的物品很可能也会被用户 B 喜欢”

算法流程

基于用户的协同过滤推荐主要包含两个关键步骤:

  1. 计算用户相似度:找到与目标用户兴趣相似的其他用户

  2. 生成推荐列表:根据相似用户的喜好为目标用户推荐物品


相似度计算方法

在无评分的二值数据场景下(只有物品是否被拥有的信息),常用的相似度计算方法有三种:

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


优缺点分析

优点

  1. 实现简单:算法原理直观,易于理解和实现

  2. 无需物品特征:只需要用户行为数据,不需要物品的内容特征

  3. 发现新兴趣:能够为用户推荐意想不到的兴趣物品

  4. 实时性好:当用户行为发生变化时,可以快速更新推荐结果

缺点

  1. 数据稀疏性:当用户 - 物品矩阵稀疏时,难以找到相似用户

  2. 冷启动问题:新用户或新物品缺乏行为数据,无法有效推荐

  3. 计算复杂度:随着用户数量增加,相似度计算复杂度呈 O (n²) 增长

  4. 推荐多样性:可能导致推荐结果缺乏多样性


总结与展望

实验结论

  1. 算法有效性:基于用户的协同过滤算法在无评分二值数据场景下表现良好

  2. 性能表现:用户 A 的 F1 分数达到 1.0,用户 D 达到 0.8,推荐效果理想

  3. 算法对比:三种相似度算法在小规模数据集上表现基本一致

  4. 参数影响:k 值(相似用户数量)对推荐结果影响较小

改进方向

  1. 混合推荐:结合基于物品的协同过滤或内容推荐,提高推荐效果

  2. 降维技术:使用 PCA、SVD 等降维技术降低计算复杂度

  3. 时间因素:考虑用户行为的时间衰减,近期行为给予更高权重

  4. 冷启动处理:结合物品特征信息处理新用户和新物品问题

  5. 多样性优化:在保证准确性的同时提高推荐结果的多样性

应用场景

基于用户的协同过滤算法适用于:

  • 电商平台的商品推荐

  • 音乐、视频、新闻等内容推荐

  • 社交网络的好友推荐

  • 在线教育的课程推荐


完整代码

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}")

参考资料

  1. Resnick, P., Iacovou, N., Suchak, M., Bergstrom, P., & Riedl, J. (1994). GroupLens: an open architecture for collaborative filtering of netnews.

  2. Sarwar, B., Karypis, G., Konstan, J., & Riedl, J. (2001). Item-based collaborative filtering recommendation algorithms.

  3. Su, X., & Khoshgoftaar, T. M. (2009). A survey of collaborative filtering techniques.


如果这篇文章对您有帮助,请点赞分享!如有疑问或建议,欢迎留言讨论。

http://www.dtcms.com/a/544645.html

相关文章:

  • jsp书城网站开发中国建设银行重庆网站首页
  • 郑州网站建设公司排名湖南省城乡住房建设厅网站
  • 蓝牙钥匙 第4次 蓝牙协议栈深度剖析:从物理层到应用层的完整架构解析
  • 口腔健康系统|口腔医疗|基于java和小程序的口腔健康系统小程序设计与实现(源码+数据库+文档)
  • FANUC发那科焊接机器人薄板焊接节气
  • 如何加强网站信息管理建设个人网站设计步骤
  • 调用API历史和未来气象数据获取
  • 机器人从设计到仿真到落地
  • 战略合作 | 深信科创携手北极雄芯、灵猴机器人共推国产智能机器人规模化落地
  • Rust 闭包的定义与捕获:从理论到实践的深度探索
  • 公司网站建设分录哪里的赣州网站建设
  • 各级院建设网站的通知网站建设的结论
  • 四种编程语言字符串函数及方法对比(python、Java、C#、C++)
  • 亲测好用:Chrome/Chromedriver一键下载工具(免费无广)
  • 基于Chrome140的TK账号自动化(关键词浏览)——脚本撰写(二)
  • C# SelectMany 完全指南:从入门到精通
  • 卡片式设计网站制作婚庆网站建设需求分析
  • RK3399 11.0关闭调试串口改为普通RS232通信串口
  • 手机网站弹窗大唐网站建设
  • 播放本地音频的代码
  • cefsharp139-H264-X86升级测试(MP4)-支持PDF预览-chromium7258定制浏览器
  • pandoc导出markdown为PDF,同时解决中文内容报乱码的错误
  • 【printpdf】生成PDF的全能Rust库printpdf
  • 小技巧:ipynb转pdf
  • 计算机网络自顶向下方法16——应用层 因特网视频 HTTP流和DASH
  • 摄像头选型与对应采集工具方案
  • 免费的行情软件下载安装佛山网站优化指导
  • 仓颉尾递归优化:从编译器实现到函数式编程实践
  • 小智机器人连接抖音直播间教程
  • webhooks