1. 项目概述与核心价值
这个基于Python+Django的协同过滤商品推荐系统,是我在指导本科生毕业设计时反复打磨的实战项目。不同于市面上简单的Demo,它完整实现了从数据采集、算法优化到前后端交互的全流程,特别适合需要高质量毕设源码的计算机专业学生,或是计划快速搭建推荐系统原型的开发者。
系统最核心的价值在于三点:首先,采用改进的协同过滤算法解决传统推荐中的冷启动和数据稀疏问题;其次,提供完整的远程调试方案,解决学生部署环境不一致的痛点;最后,配套的文档包含20+页的详细设计说明和答辩技巧,这些都是普通开源项目不会提供的"隐形知识"。
2. 系统架构设计解析
2.1 技术栈选型依据
选择Django作为后端框架主要考虑三点:一是其自带的Admin后台能快速构建商品管理系统,二是ORM层简化了数据库操作(对不熟悉SQL的学生特别友好),三是成熟的中间件机制便于实现用户行为日志采集。前端采用Bootstrap+jQuery组合而非Vue/React,是为了降低学习曲线,让学生更专注于推荐算法本身。
数据库选用MySQL而非Django默认的SQLite,原因在于:
- 需要处理用户行为大数据(实测支持10万级评分记录)
- 便于实现读写分离优化查询性能
- 更贴近企业真实环境
2.2 协同过滤算法实现方案
系统实现了两种经典协同过滤:
-
用户基(User-Based):通过皮尔逊相关系数计算用户相似度
python复制def pearson_sim(user1, user2): # 获取共同评分项 common_items = {item for item in user1.ratings if item in user2.ratings} n = len(common_items) if n == 0: return 0 # 计算分子分母 sum1 = sum(user1.ratings[item] for item in common_items) sum2 = sum(user2.ratings[item] for item in common_items) sum1_sq = sum(pow(user1.ratings[item],2) for item in common_items) sum2_sq = sum(pow(user2.ratings[item],2) for item in common_items) p_sum = sum(user1.ratings[item] * user2.ratings[item] for item in common_items) # 计算皮尔逊值 num = p_sum - (sum1*sum2/n) den = sqrt((sum1_sq - pow(sum1,2)/n) * (sum2_sq - pow(sum2,2)/n)) return num/den if den !=0 else 0 -
物品基(Item-Based):采用余弦相似度矩阵预计算
通过定时任务每天凌晨更新相似度矩阵,平衡计算开销和实时性
关键优化:引入评分时间衰减因子,使近期行为权重更高
python复制weight = 0.5 + 0.5 * (current_time - rating_time) / (24*3600)
3. 核心功能实现细节
3.1 用户行为采集模块
设计埋点方案时特别注意了以下字段:
json复制{
"user_id": "1024",
"item_id": "789",
"behavior_type": "click/purchase/cart",
"timestamp": "2023-07-25 14:30:21",
"session_id": "a1b2c3d4",
"page_url": "/product/789",
"device_fingerprint": "PC-Chrome-1920x1080"
}
通过Django中间件自动捕获关键事件:
python复制class UserBehaviorMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_authenticated and request.path.startswith('/product/'):
log_data = {
'user_id': request.user.id,
'item_id': request.path.split('/')[-2],
'behavior_type': 'view',
'timestamp': timezone.now()
}
UserBehavior.objects.create(**log_data)
response = self.get_response(request)
return response
3.2 推荐结果生成流程
-
冷启动处理:
- 新用户:采用热门商品+品类分布的策略
- 新商品:基于内容相似度推荐(TF-IDF提取标题关键词)
-
混合推荐策略:
mermaid复制graph TD A[用户请求] --> B{新用户?} B -->|是| C[热门推荐] B -->|否| D[协同过滤] D --> E{结果数>5?} E -->|否| F[补充内容推荐] E -->|是| G[返回结果] -
缓存优化:
使用Redis缓存两类数据:- 用户最近推荐结果(有效期2小时)
- 商品相似度矩阵(每日更新)
4. 项目部署与调试方案
4.1 远程开发环境配置
为解决学生电脑环境差异问题,提供两种方案:
-
Docker Compose方案(推荐):
yaml复制version: '3' services: web: build: . ports: - "8000:8000" volumes: - .:/code depends_on: - redis - db redis: image: redis:alpine ports: - "6379:6379" db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: recsys MYSQL_USER: django MYSQL_PASSWORD: django123 ports: - "3306:3306" -
传统部署checklist:
- [ ] Python 3.8+环境
- [ ] MySQL 5.7+创建recsys数据库
- [ ] 安装requirements.txt依赖
- [ ] 配置settings.py中的数据库连接
- [ ] 执行migrations
4.2 常见调试问题解决
-
推荐结果不稳定:
- 检查Redis缓存是否生效
- 确认行为数据量是否足够(至少50条有效记录)
-
性能瓶颈排查:
python复制# 在视图函数中添加性能日志 import time from django.db import connection def recommend_view(request): start_time = time.time() # ...业务逻辑... queries = len(connection.queries) duration = time.time() - start_time logger.info(f"Recommend took {duration:.2f}s with {queries} queries") -
内存泄漏处理:
使用memory_profiler定位问题:bash复制
python -m memory_profiler manage.py runserver
5. 毕设答辩专项优化
5.1 技术亮点提炼建议
建议学生重点展示三个创新点:
- 混合推荐策略:对比纯协同过滤的准确率提升(提供测试数据)
- 实时性优化:引入时间衰减因子后的推荐新颖度提升
- 工程化实践:Django中间件实现的无侵入式数据采集
5.2 答辩演示技巧
-
数据准备:
- 预生成1000个模拟用户行为数据
- 准备3组对比实验(新用户/老用户/商品冷启动)
-
演示脚本示例:
python复制# 在Django shell中执行演示 from recsys.utils import * # 新用户案例 new_user = User.objects.create(username="demo_user") print(get_recommendation(new_user.id)) # 应返回热门商品 # 模拟用户行为 simulate_behavior(new_user.id, 20) # 随机生成20条行为记录 print(get_recommendation(new_user.id)) # 显示个性化推荐 -
问题应对预案:
- 如果算法效果不理想:强调数据量影响,展示随着数据增加的准确率变化曲线
- 如果被问及商业应用:讨论AB测试框架的扩展方案
6. 项目扩展方向
对于想深入研究的同学,建议从以下方向扩展:
- 实时推荐:集成Kafka处理用户实时行为流
- 深度学习:用TensorFlow实现神经协同过滤
- 可视化分析:用Echarts展示用户兴趣图谱
这个项目经过5次迭代,已在12所高校的毕设中成功应用。特别提醒:在实现商品相似度计算时,务必对标题进行分词和停用词过滤,否则会出现"手机"和"手机壳"被误判为相似的情况——这是我们踩过的最典型的坑。