1. 协同过滤推荐系统概述
中午打开外卖APP时,首页突然出现"糖醋里脊"的推荐——这背后其实是一套精密的推荐算法在运作。作为一名长期从事推荐系统开发的工程师,我想分享一个基于用户行为的简易点餐推荐系统实现方案。
这个系统采用协同过滤算法,通过分析用户历史点餐记录,找到口味相似的用户群体,然后根据相似用户的偏好来推荐菜品。这种方法特别适合餐饮场景,因为人们的饮食偏好往往具有群体性特征。比如喜欢川菜的用户群体,通常会有一系列相似的菜品选择。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心算法原理
2.1 协同过滤基础
协同过滤(Collaborative Filtering)是推荐系统中最经典的算法之一,其核心思想是"物以类聚,人以群分"。在餐饮场景中,可以理解为:如果用户A和用户B喜欢相似的菜品,那么A喜欢的其他菜品也可能适合B。
算法主要分为两个步骤:
- 计算用户之间的相似度
- 根据相似用户的偏好生成推荐
2.2 余弦相似度计算
我们使用余弦相似度来衡量用户之间的口味相似程度。这种方法特别适合处理稀疏的点击或购买数据。余弦相似度通过计算两个向量的夹角余弦值来确定它们的相似度,其值域为[-1,1],在推荐系统中通常取[0,1]范围。
计算公式为:
cosθ = (A·B) / (||A|| × ||B||)
其中:
- A·B表示向量A和B的点积
- ||A||表示向量A的模(欧几里得范数)
3. 数据准备与处理
3.1 原始数据结构
假设我们有以下五个用户的点餐记录:
python复制user_dishes = {
'张三': ['红烧肉', '清蒸鲈鱼', '麻婆豆腐'],
'李四': ['糖醋里脊', '地三鲜', '酸辣汤'],
'王五': ['红烧肉', '糖醋里脊', '蒜蓉西兰花'],
'赵六': ['清蒸鲈鱼', '麻婆豆腐', '酸辣汤'],
'周七': ['糖醋里脊', '红烧肉', '地三鲜']
}
3.2 数据向量化
为了计算相似度,我们需要将用户的点餐记录转换为向量形式。具体步骤如下:
- 获取所有菜品的全集
- 为每个用户创建一个与全集等长的向量
- 如果用户点过某菜品,对应位置置1,否则置0
实现代码:
python复制from itertools import chain
# 获取所有不重复的菜品列表
all_dishes = list(set(chain(*user_dishes.values())))
# 构建用户向量
user_vectors = {}
for user, dishes in user_dishes.items():
user_vectors[user] = [1 if dish in dishes else for dish in all_dishes]
4. 相似度计算实现
4.1 计算用户相似度矩阵
使用余弦相似度计算所有用户两两之间的相似度:
python复制from itertools import combinations
import numpy as np
def cosine_sim(vec_a, vec_b):
dot = np.dot(vec_a, vec_b)
norm_a = np.linalg.norm(vec_a)
norm_b = np.linalg.norm(vec_b)
return dot / (norm_a * norm_b) if norm_a and norm_b else
# 计算所有用户两两之间的相似度
similarity_matrix = {}
for (u1, v1), (u2, v2) in combinations(user_vectors.items(), 2):
sim = cosine_sim(v1, v2)
similarity_matrix[(u1, u2)] = sim
4.2 相似度结果解读
以用户"张三"为例,系统会计算他与所有其他用户的相似度:
- 张三和周七都点了"红烧肉",相似度会较高
- 张三和李四没有共同菜品,相似度为0
- 张三和赵六都点了"清蒸鲈鱼"和"麻婆豆腐",相似度会很高
5. 推荐生成策略
5.1 寻找相似用户
为目标用户找出相似度最高的几个用户:
python复制target_user = '张三'
# 取出所有包含目标用户的相似度对
user_similarities = {}
for (u1, u2), sim in similarity_matrix.items():
if u1 == target_user:
user_similarities[u2] = sim
elif u2 == target_user:
user_similarities[u1] = sim
# 按相似度降序排列
sorted_users = sorted(user_similarities.items(), key=lambda x: x[1], reverse=True)
5.2 生成推荐列表
从相似用户的点餐记录中提取目标用户未点过的菜品:
python复制recommend_dishes = []
for user, _ in sorted_users[:2]: # 取前两名相似用户
for dish in user_dishes[user]:
if dish not in user_dishes[target_user]:
recommend_dishes.append(dish)
# 去重后输出
print(f"给{target_user}的推荐:{list(set(recommend_dishes))}")
6. 系统优化与改进
6.1 冷启动问题解决方案
新用户没有历史数据时,可以采用以下策略:
- 热门推荐:推荐整体最受欢迎的菜品
- 基于内容的推荐:根据菜品特征(口味、品类等)推荐
- 混合推荐:结合多种推荐策略
6.2 算法性能优化
当用户和菜品数量增加时,可以采取以下优化措施:
- 使用稀疏矩阵存储用户-菜品关系
- 采用近似最近邻算法降低计算复杂度
- 使用分布式计算框架处理大数据量
7. 实际应用中的注意事项
-
数据稀疏性问题:实际场景中用户-菜品矩阵通常非常稀疏,可以考虑使用矩阵分解等降维技术
-
实时性要求:推荐系统需要平衡实时性和计算开销,可以采用离线计算+实时更新的策略
-
多样性保证:避免推荐结果过于集中,可以引入多样性控制机制
-
解释性增强:提供推荐理由(如"因为您喜欢红烧肉")可以提升用户体验
8. 扩展应用场景
这个基础框架不仅可以用于餐饮推荐,稍作调整还可应用于:
- 电影/音乐推荐
- 电商商品推荐
- 新闻内容推荐
- 社交好友推荐
关键是根据具体场景调整相似度计算方式和推荐策略。
9. 完整代码实现
以下是完整的Python实现代码:
python复制from itertools import chain, combinations
import numpy as np
# 原始数据
user_dishes = {
'张三': ['红烧肉', '清蒸鲈鱼', '麻婆豆腐'],
'李四': ['糖醋里脊', '地三鲜', '酸辣汤'],
'王五': ['红烧肉', '糖醋里脊', '蒜蓉西兰花'],
'赵六': ['清蒸鲈鱼', '麻婆豆腐', '酸辣汤'],
'周七': ['糖醋里脊', '红烧肉', '地三鲜']
}
# 数据预处理
all_dishes = list(set(chain(*user_dishes.values())))
user_vectors = {}
for user, dishes in user_dishes.items():
user_vectors[user] = [1 if dish in dishes else for dish in all_dishes]
# 相似度计算
def cosine_sim(vec_a, vec_b):
dot = np.dot(vec_a, vec_b)
norm_a = np.linalg.norm(vec_a)
norm_b = np.linalg.norm(vec_b)
return dot / (norm_a * norm_b) if norm_a and norm_b else
similarity_matrix = {}
for (u1, v1), (u2, v2) in combinations(user_vectors.items(), 2):
sim = cosine_sim(v1, v2)
similarity_matrix[(u1, u2)] = sim
# 推荐生成
def recommend(target_user, top_n=2):
user_similarities = {}
for (u1, u2), sim in similarity_matrix.items():
if u1 == target_user:
user_similarities[u2] = sim
elif u2 == target_user:
user_similarities[u1] = sim
sorted_users = sorted(user_similarities.items(), key=lambda x: x[1], reverse=True)
recommend_dishes = []
for user, _ in sorted_users[:top_n]:
for dish in user_dishes[user]:
if dish not in user_dishes[target_user]:
recommend_dishes.append(dish)
return list(set(recommend_dishes))
# 测试推荐
print("给张三的推荐:", recommend('张三'))
print("给李四的推荐:", recommend('李四'))
10. 评估与改进方向
10.1 评估指标
在实际应用中,我们需要量化推荐系统的效果,常用指标包括:
- 准确率:推荐结果中有多少是用户真正喜欢的
- 召回率:系统能够找出多少用户喜欢的物品
- 覆盖率:推荐系统能够推荐多少比例的物品
- 多样性:推荐结果是否具有足够的多样性
10.2 改进方向
- 引入用户评分数据而不仅仅是二元点击数据
- 结合时间因素,更重视近期行为
- 加入菜品特征信息,实现混合推荐
- 考虑用户的人口统计学特征
- 实现实时推荐更新机制
在实际项目中,我通常会先实现这样一个基础版本,然后根据业务需求和数据特点逐步优化。记住,推荐系统是一个需要持续迭代和改进的工程,没有一劳永逸的解决方案。
