基于Django的豆瓣电影推荐系统实现与优化
2026/7/28 11:57:37 网站建设 项目流程

1. 项目概述与核心价值

豆瓣电影推荐系统是一个典型的基于用户行为的个性化推荐应用,它融合了Python全栈开发与机器学习算法,最终通过可视化界面呈现结果。这个项目之所以值得深入探讨,是因为它完整覆盖了从数据采集、算法实现到前端展示的全流程技术栈,特别适合作为计算机专业毕业设计的选题。

我在实际开发中发现,这类系统最难的不是算法本身,而是如何将算法工程化落地。很多教程只讲协同过滤的数学原理,却很少展示如何将其整合到Web应用中。这正是本项目的独特价值——它演示了如何用Django框架搭建推荐系统的完整生产环境,包括数据库设计、API接口开发和前后端交互。

2. 技术栈选型解析

2.1 为什么选择Django而非Flask

Django的"开箱即用"特性使其成为毕业设计项目的理想选择:

  • 自带Admin后台,可快速管理电影数据和用户信息
  • ORM系统简化了MySQL操作,避免手写复杂SQL
  • 内置用户认证系统,节省开发时间

提示:对于需要快速迭代的学术项目,建议使用Django 3.2 LTS版本,它在稳定性和新特性之间取得了良好平衡。

2.2 MySQL的优化实践

电影推荐系统涉及大量用户行为数据,我们的数据库设计遵循了这些原则:

CREATE TABLE user_ratings ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, movie_id INT NOT NULL, rating FLOAT CHECK (rating BETWEEN 1 AND 5), timestamp DATETIME, INDEX idx_user (user_id), INDEX idx_movie (movie_id) ) ENGINE=InnoDB;

关键优化点:

  • 为user_id和movie_id建立联合索引
  • 使用InnoDB引擎支持事务
  • 添加CHECK约束保证评分范围合法

2.3 ECharts的可视化技巧

在展示推荐结果时,我们采用了这些可视化方案:

  1. 热力图展示用户-电影评分矩阵
  2. 雷达图对比用户偏好维度
  3. 关系图显示电影相似度网络

实现要点:

// 在Django模板中初始化ECharts var chart = echarts.init(document.getElementById('chart-container')); chart.setOption({ tooltip: {}, series: [{ type: 'graph', layout: 'force', data: [/* 从Django视图传递的JSON数据 */] }] });

3. 协同过滤算法实现细节

3.1 用户-物品矩阵构建

我们使用scipy的稀疏矩阵存储大规模评分数据:

from scipy.sparse import lil_matrix def build_rating_matrix(ratings): user_ids = {u: i for i, u in enumerate(ratings['user_id'].unique())} movie_ids = {m: i for i, m in enumerate(ratings['movie_id'].unique())} matrix = lil_matrix((len(user_ids), len(movie_ids))) for _, row in ratings.iterrows(): matrix[user_ids[row['user_id']], movie_ids[row['movie_id']]] = row['rating'] return matrix, user_ids, movie_ids

3.2 相似度计算优化

传统余弦相似度计算在Python中的高效实现:

from sklearn.metrics.pairwise import cosine_similarity from scipy.sparse import csr_matrix def calculate_similarity(matrix): # 转换为CSR格式提高计算效率 sparse_matrix = csr_matrix(matrix) return cosine_similarity(sparse_matrix, dense_output=False)

3.3 推荐生成策略

结合用户历史和相似度生成推荐:

def generate_recommendations(user_id, similarity, ratings, k=10): # 获取目标用户未评分的电影 user_ratings = ratings[ratings['user_id'] == user_id] rated_movies = set(user_ratings['movie_id']) all_movies = set(ratings['movie_id']) unrated = all_movies - rated_movies # 计算预测评分 recommendations = [] for movie in unrated: # 找到对当前电影评分的相似用户 similar_users = similarity[user_id].argsort()[-100:][::-1] weighted_sum = 0 sim_sum = 0 for sim_user in similar_users: if ratings[(ratings['user_id'] == sim_user) & (ratings['movie_id'] == movie)].any(): rating = ratings[(ratings['user_id'] == sim_user) & (ratings['movie_id'] == movie)].iloc[0]['rating'] weight = similarity[user_id, sim_user] weighted_sum += rating * weight sim_sum += weight if sim_sum > 0: predicted_rating = weighted_sum / sim_sum recommendations.append((movie, predicted_rating)) return sorted(recommendations, key=lambda x: x[1], reverse=True)[:k]

4. 系统架构设计

4.1 整体架构图

用户请求 → Django路由 → 视图处理 → ↓ ↑ 模型计算(协同过滤) 模板渲染 ↓ ↑ MySQL数据持久化 ECharts可视化

4.2 关键Django模型设计

from django.db import models class Movie(models.Model): title = models.CharField(max_length=200) genres = models.CharField(max_length=200) year = models.IntegerField() def __str__(self): return f"{self.title} ({self.year})" class Rating(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) movie = models.ForeignKey(Movie, on_delete=models.CASCADE) value = models.FloatField() timestamp = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('user', 'movie')

4.3 推荐API接口实现

from rest_framework.decorators import api_view from rest_framework.response import Response @api_view(['GET']) def get_recommendations(request, user_id): try: ratings = Rating.objects.all().values() matrix, user_map, movie_map = build_rating_matrix(ratings) similarity = calculate_similarity(matrix) if user_id not in user_map: return Response({"error": "User not found"}, status=404) recommendations = generate_recommendations( user_map[user_id], similarity, ratings ) result = [{ 'movie_id': list(movie_map.keys())[list(movie_map.values()).index(mid)], 'score': float(score) } for mid, score in recommendations] return Response(result) except Exception as e: return Response({"error": str(e)}, status=500)

5. 部署与性能优化

5.1 生产环境部署方案

推荐使用Nginx + Gunicorn组合:

# 安装Gunicorn pip install gunicorn # 启动命令 gunicorn --workers 4 --bind 0.0.0.0:8000 project.wsgi:application

Nginx配置示例:

server { listen 80; server_name yourdomain.com; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /static/ { alias /path/to/your/static/files/; } }

5.2 缓存策略实现

使用Redis缓存推荐结果:

import redis from django.conf import settings r = redis.Redis( host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=settings.REDIS_DB ) def get_cached_recommendations(user_id): cache_key = f"recs:{user_id}" cached = r.get(cache_key) if cached: return json.loads(cached) # 计算推荐结果 result = generate_recommendations(user_id) # 缓存1小时 r.setex(cache_key, 3600, json.dumps(result)) return result

5.3 算法性能优化技巧

  1. 矩阵分块计算:对于大规模数据,将相似度矩阵分块计算
  2. 近似最近邻:使用Annoy或FAISS库加速相似度搜索
  3. 批处理预测:对多个用户同时生成推荐,减少IO开销

优化后的相似度计算:

from annoy import AnnoyIndex def build_annoy_index(matrix, n_trees=10): n_users, n_items = matrix.shape t = AnnoyIndex(n_items, 'angular') for i in range(n_users): t.add_item(i, matrix[i].toarray()[0]) t.build(n_trees) return t

6. 常见问题与解决方案

6.1 冷启动问题处理

对于新用户或新电影,采用混合策略:

  1. 基于内容的推荐(电影类型/导演相似性)
  2. 热门电影推荐
  3. 随机探索机制

实现代码:

def hybrid_recommendation(user_id, n=10): # 尝试协同过滤 try: cf_recs = get_recommendations(user_id) if len(cf_recs) >= n: return cf_recs[:n] except: pass # 冷启动后备方案 top_movies = Movie.objects.annotate( avg_rating=Avg('rating__value') ).order_by('-avg_rating')[:n] return [(m.id, m.avg_rating or 3.0) for m in top_movies]

6.2 数据稀疏性问题

采用这些方法改善推荐质量:

  1. 矩阵填充(使用全局平均分)
  2. 降维处理(SVD分解)
  3. 增加隐式反馈(浏览/点击数据)

SVD降维实现:

from scipy.sparse.linalg import svds def svd_recommend(matrix, k=50): u, s, vt = svds(matrix, k=k) sigma = np.diag(s) return np.dot(np.dot(u, sigma), vt)

6.3 实时性挑战

实现增量更新策略:

  1. 定时任务更新用户相似度矩阵
  2. 流式处理新评分数据
  3. 局部更新受影响用户的推荐结果

Celery定时任务示例:

from celery import shared_task @shared_task def update_similarity(): ratings = Rating.objects.all().values() matrix = build_rating_matrix(ratings) similarity = calculate_similarity(matrix) # 保存到Redis r.set('similarity_matrix', pickle.dumps(similarity))

7. 项目扩展方向

7.1 多算法融合

结合深度学习方法:

import tensorflow as tf from tensorflow.keras.layers import Embedding, Flatten, Dot def build_neural_cf(n_users, n_movies, embedding_size=50): user_input = tf.keras.Input(shape=(1,)) movie_input = tf.keras.Input(shape=(1,)) user_embedding = Embedding(n_users, embedding_size)(user_input) movie_embedding = Embedding(n_movies, embedding_size)(movie_input) dot_product = Dot(axes=2)([user_embedding, movie_embedding]) flattened = Flatten()(dot_product) model = tf.keras.Model( inputs=[user_input, movie_input], outputs=flattened ) model.compile(optimizer='adam', loss='mse') return model

7.2 上下文感知推荐

加入时间、地点等上下文信息:

class ContextualRating(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) movie = models.ForeignKey(Movie, on_delete=models.CASCADE) value = models.FloatField() location = models.CharField(max_length=100) device = models.CharField(max_length=50) timestamp = models.DateTimeField()

7.3 A/B测试框架

实现推荐算法对比:

def ab_test_recommendation(user_id): # 随机分配算法 if hash(user_id) % 2 == 0: return collaborative_filtering(user_id) else: return neural_cf_recommend(user_id)

在开发这个系统的过程中,我发现最大的挑战不是算法实现,而是如何平衡系统的实时性和计算开销。一个实用的技巧是采用分层缓存策略:高频访问用户的推荐结果缓存在Redis中,普通用户的结果按需计算。另外,为Admin后台添加推荐质量监控面板也很有必要,可以直观看到算法效果。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询