news 2026/3/11 12:34:53

手把手教你实现简单的推荐系统算法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手教你实现简单的推荐系统算法

从零构建推荐系统:协同过滤与相似度计算实战

你有没有想过,为什么抖音总能“猜中”你喜欢的视频?为什么淘宝刚浏览过的商品,第二天就在首页弹出来?这背后不是魔法,而是推荐系统在默默工作。

在今天这个信息爆炸的时代,我们每天面对的是成千上万的内容选择。如果没有个性化筛选机制,用户很容易陷入“看得越多,越不知道看什么”的困境。而推荐系统,正是解决这一问题的核心技术。

它不靠人工分类,也不依赖关键词匹配,而是通过分析你的行为——比如点赞、收藏、停留时长——来推测你可能喜欢什么。其中最经典、最基础的方法之一,就是本文要带你手把手实现的:协同过滤(Collaborative Filtering)


推荐系统的“第一性原理”:人们喜欢和他们相似的人喜欢的东西

想象一下,你和朋友A都爱看科幻片,也都对悬疑剧无感。某天他突然给你推荐了一部新上映的太空歌剧电影,你会不会更愿意点开看看?

这就是协同过滤的底层逻辑:用群体的行为预测个体的偏好。它的核心假设很简单:

“如果过去你们喜欢的东西很像,那么未来你也可能会喜欢他现在喜欢的。”

这种方法完全不需要知道一部电影讲了什么、一首歌的旋律如何,只关心“谁对哪些内容表达了喜好”。因此,即使面对艺术品、音乐这类难以结构化的内容,它依然有效。

目前主流平台如Netflix、Spotify、京东等,其推荐引擎虽然已融合深度学习模型,但协同过滤依然是不可或缺的基础模块。尤其在冷启动或资源受限场景下,一个轻量级的CF系统足以支撑起初步的个性化体验。


协同过滤怎么做?两个方向任你选

协同过滤主要有两种实现方式:基于用户的基于物品的。它们思路不同,适用场景也各异。

用户 vs 物品:两条路径,同一个目标

  • User-based CF:找“和你口味相近的人”,把他们喜欢但你还没接触过的东西推给你。

比如你是影迷小李,系统发现小王和你在《盗梦空间》《星际穿越》上的评分几乎一致,而小王给《信条》打了5星,那你很可能也会感兴趣。

  • Item-based CF:找“和你喜欢过的物品相似的其他物品”,进行关联推荐。

比如你买了《三体》,系统发现买《三体》的人大多也买了《球状闪电》,于是后者就被推荐给你。

两者各有优劣:
- User-based 更适合动态兴趣变化明显的场景(如社交内容);
- Item-based 更稳定,常用于电商“看了又看”、“买了又买”等固定关联推荐。

实际工程中,Item-based 因其计算结果更稳定、易于缓存,应用更为广泛。


动手前先搞懂:用户-物品矩阵是起点

所有协同过滤的第一步,都是把原始行为数据整理成一个二维表格——用户-物品评分矩阵

import numpy as np # 示例:5个用户对5个物品的评分(0表示未评分) ratings_matrix = np.array([ [5, 4, 0, 0, 3], # 用户0 [0, 5, 4, 3, 0], # 用户1 [4, 0, 0, 5, 2], # 用户2 [3, 3, 4, 0, 5], # 用户3 [0, 0, 5, 4, 0] # 用户4 ])

每一行是一个用户的行为向量,每一列是一个物品被评价的历史。这个矩阵通常是高度稀疏的——大多数用户只接触过极少数物品。

我们的任务,就是从这些零散的数据中,“补全”那些空白的位置,预测出某个用户对某件商品可能打多少分。


如何判断“谁和谁像”?三种相似度算法详解

协同过滤的关键在于:怎么量化“相似”?以下是三种最常用的数学工具。

1. 余弦相似度:看方向,不看大小

余弦相似度衡量的是两个向量之间的夹角。公式如下:

$$
\text{sim}(u,v) = \frac{\mathbf{r}_u \cdot \mathbf{r}_v}{|\mathbf{r}_u| |\mathbf{r}_v|}
$$

它关注的是“共同评分项的方向一致性”,而不是绝对数值。例如:

  • 用户A给科幻片打高分,爱情片打低分;
  • 用户B也是同样的趋势;

哪怕A习惯打4~5星,B只打2~3星,只要趋势一致,他们的余弦相似度仍然很高。

✅ 优点:对评分尺度不敏感,适合稀疏数据
❌ 缺点:无法消除用户主观打分偏差(有人天生爱打高分)

from sklearn.metrics.pairwise import cosine_similarity user_similarities = cosine_similarity(ratings_matrix) print("用户间余弦相似度矩阵:\n", user_similarities)

2. 皮尔逊相关系数:去均值后的线性相关性

为了解决“打分习惯不同”的问题,我们可以使用皮尔逊相关系数

$$
\text{sim}(u,v) = \frac{\sum_{i \in I_{uv}} (r_{ui} - \bar{r}u)(r{vi} - \bar{r}v)}{\sqrt{\sum_i (r{ui} - \bar{r}u)^2} \sqrt{\sum_i (r{vi} - \bar{r}_v)^2}}
$$

它本质上是对每个用户的评分做“去中心化”处理(减去平均分),再计算相关性。这样就能识别出“虽然你打分严,我打分松,但我们偏好的相对顺序是一样的”。

✅ 强烈建议在用户评分风格差异大时使用!

from scipy.stats import pearsonr def compute_pearson_sim(matrix, u, v): common = (matrix[u] != 0) & (matrix[v] != 0) if not np.any(common) or len(matrix[u][common]) < 2: return 0.0 r_u = matrix[u][common] r_v = matrix[v][common] sim, _ = pearsonr(r_u, r_v) return sim if not np.isnan(sim) else 0.0 # 构建皮尔逊相似度矩阵 n_users = ratings_matrix.shape[0] pearson_sims = np.zeros((n_users, n_users)) for i in range(n_users): for j in range(n_users): pearson_sims[i][j] = compute_pearson_sim(ratings_matrix, i, j) print("皮尔逊用户相似度矩阵:\n", pearson_sims)

3. 欧氏距离:越近越相似

欧氏距离直接计算两个用户评分向量之间的直线距离:

$$
d(u,v) = \sqrt{\sum_i (r_{ui} - r_{vi})^2}
$$

通常我们会将其转换为相似度形式:$\text{sim} = \frac{1}{1 + d(u,v)}$,使其范围落在(0,1]之间。

⚠️ 注意:它对缺失值非常敏感,且要求数据密集均匀,一般较少用于真实稀疏场景。


实战:预测用户会为哪部电影打高分?

现在我们来完成最关键的一步:预测一个用户对未评分物品的喜好程度

以用户0为例,我们想预测他对物品2(当前评分为0)的打分。

使用基于用户的协同过滤思想:

  1. 找出所有对物品2有过评分的用户(这里是用户1、3、4);
  2. 查看这些用户与目标用户0的相似度;
  3. 用加权平均的方式,根据邻居用户的评分来预测。
target_user = 0 target_item = 2 # 找到对该物品有评分的用户 non_zero_mask = ratings_matrix[:, target_item] != 0 similar_users_weights = pearson_sims[target_user][non_zero_mask] neighbor_ratings = ratings_matrix[non_zero_mask, target_item] # 加权预测评分 if np.sum(np.abs(similar_users_weights)) > 0: predicted = np.dot(similar_users_weights, neighbor_ratings) / (np.sum(np.abs(similar_users_weights)) + 1e-8) else: predicted = 0 # 若无可参考邻居,则设为0 print(f"预测用户{target_user}对物品{target_item}的评分为: {predicted:.2f}")

输出可能是类似这样的结果:

预测用户0对物品2的评分为: 3.76

这意味着,尽管用户0还没接触过物品2,但系统认为他大概率会给出接近4星的好评,值得推荐。


工程落地要考虑什么?这些坑你得知道

别以为跑通代码就万事大吉了。真实世界中的推荐系统远比示例复杂,以下几个问题是必须面对的:

❗ 数据太稀疏怎么办?

现实中的用户-物品矩阵往往99%以上都是空的。这时候直接算相似度容易失真。

解决方案
- 使用修正余弦相似度(Adjusted Cosine),在计算时减去用户均值;
- 引入矩阵分解(如SVD、ALS),将高维稀疏矩阵降维到低维隐因子空间;
- 结合隐式反馈(点击、浏览时长)补充信号强度。

❗ 新用户/新物品没数据?这就是冷启动

新注册用户没有任何历史行为,系统根本找不到“相似的人”,推荐就成了瞎猜。

应对策略
- 冷启动期间采用热门推荐基于内容的推荐(Content-Based)作为兜底;
- 收集用户初始兴趣标签(如注册时选择偏好类别);
- 利用社交关系或设备信息辅助判断。

❗ 用户多了之后算不动?性能瓶颈来了

当用户数达到百万级,两两计算相似度的时间复杂度是 $O(N^2)$,根本没法实时响应。

优化手段
- 使用近似最近邻搜索(ANN),如 FAISS、Annoy 快速查找Top-K相似用户;
- 预计算并缓存相似度矩阵,定时更新;
- 迁移到分布式框架(如 Spark MLlib)进行批量处理。

❗ 推荐越来越窄?小心“信息茧房”

长期只推荐用户已知喜欢的内容,会导致视野受限,错失潜在兴趣。

破解方法
- 在推荐列表中加入一定比例的探索性内容(exploration);
- 引入多样性重排序策略(diversity-aware ranking);
- 加入时间衰减因子,让近期行为权重更高。


一套最小可行架构:如何部署一个可用的推荐服务?

即使只是做个原型,也需要清晰的流程设计。以下是一个轻量级推荐系统的典型结构:

[原始日志] ↓ 清洗与聚合 [用户-物品行为表] ↓ 构建矩阵 [评分矩阵] ↓ 算法处理 [相似度计算] → [预测打分] ↓ 排序过滤 [Top-N 推荐列表] ↓ 缓存加速 [API接口] ← Redis 存储预计算结果

开发建议
- 初期可用 Python 脚本离线生成推荐结果;
- 上线后封装为 Flask/Django 接口,支持按用户ID查询推荐;
- 使用 Redis 缓存每日更新的Top-K推荐列表,提升响应速度至毫秒级。


为什么你还应该学协同过滤?哪怕现在都在卷大模型

有人说:“现在都用图神经网络、双塔DNN做推荐了,还学这种老古董干嘛?”

但事实是:几乎所有工业级推荐系统,都保留了协同过滤的影子

原因很简单:
- 它逻辑清晰、解释性强;
- 不依赖内容特征,通用性极强;
- 计算简单,可在边缘设备或低配服务器运行;
- 是理解现代推荐模型演进的基石。

你可以把它当作“推荐系统的Hello World”。掌握了它,再去学矩阵分解、深度协同过滤(NeuMF)、图推荐系统,才能真正明白每一步改进解决了什么问题。


下一步可以怎么走?

如果你已经跑通上面的例子,恭喜你迈出了第一步。接下来不妨尝试这些进阶玩法:

  1. 引入时间因素:给最近的行为更高权重,体现兴趣漂移;
  2. 混合推荐:将协同过滤与内容推荐结合,提升覆盖率;
  3. 使用MovieLens数据集:在真实数据上训练,评估RMSE、Precision@K等指标;
  4. 实现Item-based版本:转置矩阵后计算物品相似度,试试效果差异;
  5. 部署为Web服务:用Flask暴露API,前端调用获取推荐结果。

推荐系统不是黑箱,也不是只有大厂才能玩的技术游戏。从一行代码开始,你也能搭建属于自己的智能推荐引擎。

当你第一次看到系统准确猜出用户喜好时,那种“机器真的懂我”的震撼感,会让你忍不住继续深入探索。

而这趟旅程的起点,也许就是你现在读的这篇文章。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/11 7:32:21

WebSocket实现实时进度推送:提升DDColor用户体验

WebSocket实现实时进度推送&#xff1a;提升DDColor用户体验 在处理一张泛黄的老照片时&#xff0c;用户最怕什么&#xff1f;不是修不好&#xff0c;而是“不知道它到底还在不在修”。 这正是许多AI图像修复工具面临的尴尬——用户点击“开始”后&#xff0c;界面一片静默。十…

作者头像 李华
网站建设 2026/2/25 7:13:50

GitHub镜像健康检查:定时检测DDColor仓库是否可正常拉取

GitHub镜像健康检查&#xff1a;保障DDColor仓库稳定拉取的实践方案 在数字影像修复领域&#xff0c;老照片的智能上色正变得越来越普及。尤其是像 DDColor 这类专注于黑白图像色彩还原的开源项目&#xff0c;凭借其出色的细节表现力和易用性&#xff0c;迅速成为家庭用户、档案…

作者头像 李华
网站建设 2026/3/4 3:07:37

从零实现:基于LVGL的自定义控件渲染逻辑

从零打造专属控件&#xff1a;深入LVGL的渲染内核与自定义实践你有没有遇到过这样的场景&#xff1f;项目需要一个环形滑动条&#xff0c;或者带呼吸光效的智能音箱音量指示器&#xff0c;又或是工业HMI中那种动态仪表盘。翻遍LVGL的标准控件库&#xff0c;却发现——没有一个能…

作者头像 李华
网站建设 2026/2/27 22:55:02

飞书文档批量导出终极指南:3步搞定全平台文档迁移

飞书文档批量导出终极指南&#xff1a;3步搞定全平台文档迁移 【免费下载链接】feishu-doc-export 项目地址: https://gitcode.com/gh_mirrors/fe/feishu-doc-export 还在为成百上千的飞书文档迁移而头疼吗&#xff1f;&#x1f62b; 手动一个个下载不仅效率低下&#…

作者头像 李华
网站建设 2026/3/9 10:15:56

大模型Token余额提醒:当剩余不足时推送消息引导续费

大模型Token余额提醒&#xff1a;当剩余不足时推送消息引导续费 在AI服务日益普及的今天&#xff0c;越来越多企业与个人用户依赖大模型完成内容生成、图像修复、语音处理等高价值任务。然而一个看似微小却频繁发生的问题正悄然影响着用户体验——Token用尽导致的服务中断。 设…

作者头像 李华