最近在整理学生时代的项目资料时,翻到了这个基于Django框架开发的电影推荐系统。作为当年耗时两个月完成的课程设计,这个项目完整实现了从数据采集、算法设计到前端展示的全流程。现在回看这个项目,发现它特别适合作为大数据入门练手项目——既有推荐算法这样的核心技术点,又包含完整的Web开发流程。
这个系统最核心的价值在于:它用相对简单的技术栈(Python+Django)实现了工业级推荐系统的基础功能。通过协同过滤算法,系统能够分析用户的历史评分数据,找到相似用户群体,进而预测目标用户可能感兴趣的电影。我在实现过程中特别注重算法与工程实践的平衡,既保证了推荐效果的可解释性,又确保了系统能够处理万级数据量。
系统采用典型的三层架构:
这种架构设计的优势在于:
协同过滤算法选择
最终采用基于用户的协同过滤(UserCF)而非基于物品的(ItemCF),主要考虑:
算法核心公式:
code复制用户相似度计算(余弦相似度):
sim(u,v) = ∑(r_ui * r_vi) / (√∑r_ui² * √∑r_vi²)
预测评分:
p_ai = r̄_a + [∑sim(a,u)*(r_ui - r̄_u)] / ∑|sim(a,u)|
大数据处理方案
虽然名为"大数据"系统,但考虑到课程设计的实际规模,采用:
MySQL表结构
sql复制CREATE TABLE `user_ratings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`movie_id` varchar(20) NOT NULL,
`rating` decimal(3,1) NOT NULL,
`timestamp` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_user` (`user_id`),
KEY `idx_movie` (`movie_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
MongoDB文档示例
json复制{
"movie_id": "tt0111161",
"title": "The Shawshank Redemption",
"genres": ["Drama"],
"year": 1994,
"rating": 9.3,
"directors": ["Frank Darabont"],
"actors": ["Tim Robbins", "Morgan Freeman"],
"plot": "Two imprisoned men bond over..."
}
相似度矩阵计算
python复制def calculate_similarity(user_ratings):
# 构建用户-物品评分矩阵
rating_matrix = pd.DataFrame.from_dict(user_ratings, orient='index')
# 标准化评分(减去用户平均分)
user_means = rating_matrix.mean(axis=1)
normalized_ratings = rating_matrix.sub(user_means, axis=0)
# 计算余弦相似度
similarity = cosine_similarity(normalized_ratings.fillna(0))
return pd.DataFrame(similarity, index=user_means.index, columns=user_means.index)
推荐生成逻辑
python复制def generate_recommendations(target_user, similarity_df, user_ratings, n=10):
# 获取相似用户
similar_users = similarity_df[target_user].sort_values(ascending=False)[1:11]
# 收集相似用户评价过的电影
candidate_movies = set()
for user in similar_users.index:
candidate_movies.update(user_ratings[user].keys())
# 移除目标用户已评价的电影
rated_movies = set(user_ratings[target_user].keys())
candidate_movies -= rated_movies
# 计算预测评分
recommendations = []
for movie in candidate_movies:
weighted_sum = 0
sim_sum = 0
for user in similar_users.index:
if movie in user_ratings[user]:
weighted_sum += similar_users[user] * (user_ratings[user][movie] - user_means[user])
sim_sum += abs(similar_users[user])
if sim_sum > 0:
pred_rating = user_means[target_user] + weighted_sum / sim_sum
recommendations.append((movie, pred_rating))
return sorted(recommendations, key=lambda x: x[1], reverse=True)[:n]
推荐结果接口
python复制def get_recommendations(request):
user_id = request.session.get('user_id')
if not user_id:
return JsonResponse({'error': 'Not logged in'}, status=401)
# 从缓存获取推荐结果
cache_key = f'rec_{user_id}'
recommendations = cache.get(cache_key)
if not recommendations:
# 重新计算推荐
user_ratings = get_user_ratings_from_db()
similarity_matrix = calculate_similarity(user_ratings)
recommendations = generate_recommendations(
user_id, similarity_matrix, user_ratings)
# 缓存结果(有效期1天)
cache.set(cache_key, recommendations, 86400)
# 获取电影详情
movie_details = []
for movie_id, _ in recommendations:
movie = mongo_db.movies.find_one({'movie_id': movie_id})
if movie:
movie_details.append({
'title': movie['title'],
'year': movie['year'],
'rating': movie['rating'],
'poster': movie.get('poster', '')
})
return JsonResponse({'movies': movie_details})
相似度矩阵计算优化
缓存策略
python复制# settings.py配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'TIMEOUT': 86400, # 24小时
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
混合推荐策略
python复制def hybrid_recommendation(user_id):
# 协同过滤结果
cf_rec = get_cf_recommendations(user_id)
# 基于内容推荐(针对新用户)
if len(cf_rec) < 5:
cb_rec = get_content_based_rec(user_id)
cf_rec.extend(cb_rec)
# 时间衰减调整
weighted_rec = []
for movie_id, score in cf_rec:
last_rating_time = get_last_rating_time(user_id, movie_id)
time_factor = calculate_time_factor(last_rating_time)
weighted_rec.append((movie_id, score * time_factor))
# 多样性控制
return diversify_recommendations(weighted_rec)
生产环境配置
部署脚本示例
bash复制# 安装依赖
sudo apt-get install python3-pip redis-server mongodb-org
# 配置虚拟环境
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# 启动服务
gunicorn --bind 0.0.0.0:8000 movie_rec.wsgi:application \
--workers 4 \
--timeout 120 \
--access-logfile -
单元测试示例
python复制class RecommendationTests(TestCase):
@classmethod
def setUpTestData(cls):
# 初始化测试数据
test_users = {
'user1': {'movie1': 5, 'movie2': 3},
'user2': {'movie1': 4, 'movie3': 5}
}
cls.similarity = calculate_similarity(test_users)
def test_similarity_calculation(self):
sim = self.similarity.loc['user1', 'user2']
self.assertAlmostEqual(sim, 0.707, places=3)
def test_recommendation_generation(self):
rec = generate_recommendations('user1', self.similarity, test_users)
self.assertEqual(rec[0][0], 'movie3')
压力测试结果
在实际使用过程中,我发现这个基础系统有几个值得深入优化的方向:
python复制# 简单的神经协同过滤模型
def NCF_model(num_users, num_items, embedding_size=64):
user_input = Input(shape=(1,))
item_input = Input(shape=(1,))
user_embedding = Embedding(num_users, embedding_size)(user_input)
item_embedding = Embedding(num_items, embedding_size)(item_input)
user_vec = Flatten()(user_embedding)
item_vec = Flatten()(item_embedding)
concat = Concatenate()([user_vec, item_vec])
dense = Dense(128, activation='relu')(concat)
output = Dense(1, activation='sigmoid')(dense)
model = Model(inputs=[user_input, item_input], outputs=output)
model.compile(optimizer='adam', loss='binary_crossentropy')
return model
这个项目最让我满意的部分是它展示了一个推荐系统从理论到实践的完整闭环。虽然现在回头看代码有很多可以优化的地方,但这种"麻雀虽小五脏俱全"的特质,反而让它成为了非常好的教学案例。对于想入门推荐系统的同学,我的建议是先吃透这个基础版本,再逐步添加更复杂的特性。