这个基于Python+Django的协同过滤算法电影推荐系统,是我在开发实践中总结的一套完整的推荐系统解决方案。不同于传统的电影评分网站,这个系统能够根据用户的历史行为和偏好,自动推荐可能感兴趣的电影,实现真正的个性化推荐。
推荐系统在当今互联网应用中扮演着越来越重要的角色。根据我的开发经验,一个好的推荐系统能够显著提升用户体验和平台粘性。以电影推荐为例,用户不再需要花费大量时间在茫茫片库中寻找自己喜欢的电影,系统会根据算法自动匹配适合的内容。
选择Django作为后端框架主要基于以下几个考虑:
在实际开发中,我发现Django的ORM特别适合快速构建数据模型,通过简单的Python类定义就能自动生成数据库表结构,大大减少了SQL编写的工作量。
系统使用MySQL作为主数据库,主要包含以下几张核心表:
用户表(User):
电影表(Movie):
评分表(Rating):
用户行为表(Behavior):
提示:在实际项目中,建议对频繁查询的字段建立索引,特别是用户ID和电影ID这类经常用于关联查询的字段。
虽然项目描述中提到Vue,但在实际电影推荐系统中,我建议采用以下技术组合:
这种组合的优势在于:
协同过滤算法主要分为两类:
基于用户的协同过滤(User-based CF):
基于物品的协同过滤(Item-based CF):
在实际应用中,我发现Item-based CF通常表现更好,因为:
相似度计算是协同过滤的核心,常用的方法有:
余弦相似度(Cosine Similarity):
python复制def cosine_similarity(vec1, vec2):
dot_product = np.dot(vec1, vec2)
norm1 = np.linalg.norm(vec1)
norm2 = np.linalg.norm(vec2)
return dot_product / (norm1 * norm2)
皮尔逊相关系数(Pearson Correlation):
python复制def pearson_similarity(vec1, vec2):
return np.corrcoef(vec1, vec2)[0, 1]
调整余弦相似度(Adjusted Cosine Similarity):
经过多次实验,我发现调整余弦相似度在实际应用中效果最好,因为它考虑了不同用户评分标准的差异。
在实际开发中,我总结了几点优化经验:
数据稀疏性问题:
冷启动问题:
实时性优化:
多样性保障:
python复制from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
('O', 'Other'),
)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True)
age = models.IntegerField(null=True, blank=True)
register_date = models.DateTimeField(auto_now_add=True)
class Movie(models.Model):
title = models.CharField(max_length=200)
genres = models.CharField(max_length=100)
year = models.IntegerField()
rating = models.FloatField(default=0)
poster_url = models.URLField(max_length=500, blank=True)
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)
rating = models.FloatField()
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ('user', 'movie')
python复制import numpy as np
from collections import defaultdict
from django.db.models import Count, Avg
from .models import Rating, Movie
class Recommender:
def __init__(self):
self.user_ratings = None
self.movie_similarity = None
def load_data(self):
"""加载评分数据并构建用户-电影评分矩阵"""
ratings = Rating.objects.all().values('user_id', 'movie_id', 'rating')
self.user_ratings = defaultdict(dict)
for r in ratings:
self.user_ratings[r['user_id']][r['movie_id']] = r['rating']
def calculate_similarity(self):
"""计算电影之间的相似度矩阵"""
# 构建倒排表:电影->用户评分
movie_users = defaultdict(dict)
for user, movies in self.user_ratings.items():
for movie, rating in movies.items():
movie_users[movie][user] = rating
# 计算电影相似度
self.movie_similarity = defaultdict(dict)
movies = list(movie_users.keys())
for i in range(len(movies)):
for j in range(i+1, len(movies)):
m1 = movies[i]
m2 = movies[j]
# 获取同时对两个电影评分的用户
common_users = set(movie_users[m1].keys()) & set(movie_users[m2].keys())
if len(common_users) < 5: # 共同评分用户太少则跳过
continue
# 计算调整余弦相似度
vec1 = []
vec2 = []
for u in common_users:
vec1.append(movie_users[m1][u])
vec2.append(movie_users[m2][u])
similarity = np.corrcoef(vec1, vec2)[0, 1]
if np.isnan(similarity):
similarity = 0
self.movie_similarity[m1][m2] = similarity
self.movie_similarity[m2][m1] = similarity
def recommend_for_user(self, user_id, top_n=10):
"""为用户生成推荐"""
if user_id not in self.user_ratings:
# 新用户,返回热门电影
return self.get_popular_movies(top_n)
user_ratings = self.user_ratings[user_id]
scores = defaultdict(float)
# 对用户评分过的每个电影
for movie_id, rating in user_ratings.items():
# 找到相似的电影
for similar_movie, similarity in self.movie_similarity.get(movie_id, {}).items():
if similar_movie not in user_ratings: # 用户没看过的
scores[similar_movie] += similarity * (rating - 2.5) # 减去中性评分
# 按得分排序
recommended = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:top_n]
return [movie_id for movie_id, score in recommended]
def get_popular_movies(self, top_n=10):
"""获取热门电影(用于冷启动)"""
return Movie.objects.annotate(
rating_count=Count('rating')
).order_by('-rating_count', '-rating')[:top_n]
python复制from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .recommender import Recommender
@login_required
def recommend_view(request):
recommender = Recommender()
recommender.load_data()
recommender.calculate_similarity()
user_id = request.user.id
movie_ids = recommender.recommend_for_user(user_id, top_n=10)
recommended_movies = Movie.objects.filter(id__in=movie_ids)
context = {
'recommended_movies': recommended_movies,
'user': request.user
}
return render(request, 'recommendations.html', context)
缓存策略:
异步计算:
数据库优化:
算法优化:
推荐的生产环境部署方案:
部署步骤示例:
bash复制# 安装依赖
pip install -r requirements.txt
# 数据库迁移
python manage.py migrate
# 收集静态文件
python manage.py collectstatic
# 启动Gunicorn
gunicorn --workers 4 --bind 0.0.0.0:8000 project.wsgi:application
# 启动Celery worker
celery -A project worker -l info
问题描述:新用户或新电影缺乏足够的行为数据,难以生成准确推荐。
解决方案:
对于新用户:
对于新电影:
问题描述:用户-电影评分矩阵非常稀疏,导致相似度计算不准确。
解决方案:
引入隐语义模型(LFM):
采用基于模型的协同过滤:
混合推荐策略:
问题描述:用户最新行为无法立即影响推荐结果。
解决方案:
分层推荐架构:
实时特征工程:
流式计算:
多算法融合:
上下文感知推荐:
可解释性推荐:
A/B测试框架:
跨域推荐:
在实际开发中,我发现推荐系统是一个需要持续迭代优化的工程。除了算法本身,数据质量、系统架构和用户体验都至关重要。建议从简单实现开始,逐步添加复杂功能,通过A/B测试验证效果,最终构建一个高效、稳定的推荐系统。