资讯动态

基于Django与协同过滤的电影推荐系统毕设实战解析

发布时间:2026/10/19 4:25:30 来源:尧图企业网站定制
1. 毕设选题的正确姿势为什么这个题目值得做先说结论电影个性化推荐系统这个题目在计算机类毕业设计里属于“稳中带秀”的类型。稳在于推荐系统是数据挖掘方向最经典的落地场景网上公开数据集多、参考资料充足秀在于它天然需要串联前端页面、后端服务、数据库、算法模型四条线一个项目做下来答辩时能讲的东西非常丰富不至于被评委追问几句就卡壳。从技术组合来看django负责业务层和接口层大数据技术负责数据处理和特征统计协同过滤算法负责核心的推荐逻辑三层各司其职。这个搭配的好处是每一层都有独立的考点但又不至于像微服务那一套动辄几百个文件让人撑不住。适合的人群也很明确已经学过Python基础对Web框架有一点概念但没独立做过完整系统的同学。如果你属于“上课都听得懂一动手就发怵”的类型这个题目几乎是为你量身定做的因为它把难度拆解成了一个个可以单独攻克的模块——先跑通页面再打通数据库最后再碰算法每一步都有明确的完成标准。但我也要泼一盆冷水如果你指望“拿到源码就算完事”那这题不适合你。一个没有系统设计过程的推荐系统就算交上去答辩三分钟就会被问出破绽——协同过滤原理是什么、相似度怎么算的、数据量大了怎么办。所以这篇文章不只是拆解项目更重要的是帮你把原理讲明白让你在答辩时能扛得住追问。2. 技术选型背后的门道为什么是django、大数据和协同过滤2.1 django的优势与适用边界选择django作为Web框架很多人会觉得“老气”但毕设场景下恰恰需要“老气”。django自带Admin后台、ORM、模板引擎、表单校验、认证系统这些内置能力意味着你不用从零写登录注册、不用手动拼SQL省出来的时间可以全部砸在推荐算法和前端页面上。更重要的是django的MTV架构Model-Template-View和推荐系统的天然分层非常契合。Model层管理用户、电影、评分的数据模型View层处理业务逻辑比如调用推荐服务、返回JSON或渲染模板Template层负责展示推荐结果。这种结构在写论文的时候也特别好描述架构图一画逻辑清清楚楚。有人会问用Flask行不行当然可以但Flask太自由了什么都要自己选自己配对毕设来说自由度越高反而越容易迷失。django把很多最佳实践已经固化在框架里你说“我用了django的类视图减少重复代码”“我用ORM避免了SQL注入风险”这些都是实打实的答辩加分项。2.2 大数据技术在毕设里的正确打开方式“大数据技术”这个词在毕设题目里看起来很唬人但千万别理解成非要搭一套Hadoop集群。真实场景下一个课程级别的项目数据处理的核心痛点无非是数据量过万之后怎么快速统计、怎么清洗异常评分、怎么给用户和电影打特征标签。我在实践中最务实的做法是两步走。第一步用Pandas做离线数据清洗和特征工程比如把用户ID和电影ID做编码映射、把时间戳拆成时间段特征、统计每个电影的平均分和评分人数第二步把清洗后的数据导入MySQL用SQL做常规统计再用django的ORM做业务查询。这个组合拳既体现了“大数据处理”的思路又不至于引入分布式框架那一套复杂度。答辩时你可以理直气壮地说“本系统采用Pandas完成数据预处理通过MySQL存储大规模评分数据利用索引优化查询性能”——技术上完全站得住。2.3 协同过滤推荐算法的核心原理协同过滤Collaborative Filtering是整个项目唯一的算法核心也是最容易被追问的地方。它的基本假设非常朴素如果你和某个人过去对电影的评价很相似那 TA 喜欢的电影你也大概率会喜欢。具体到实现有两种流派。基于用户的协同过滤User-Based CF是“找同好”先算用户之间的相似度找到最像你的那群人再把他们喜欢而你没看过的电影推荐给你。基于物品的协同过滤Item-Based CF是“找相似品”先算电影之间的相似度推荐和你曾经打过高分的电影相似的其他电影。毕设里我强烈建议做基于物品的协同过滤原因很实际用户数量级通常比电影数量级小但用户相似度矩阵的计算量是用户数的平方一旦注册用户多了在线实时算相似度会卡死。而电影数量是相对稳定的电影相似度矩阵完全可以离线算好存下来用户请求推荐时只需要查表快得多。3. 项目落地第一步环境搭建与数据准备3.1 开发环境的具体版本选择这一节是纯经验之谈版本对了后面的坑能少一半。我自己踩过Python版本不一致导致django运行报错的坑所以直接给一套经过验证的组合Python 3.8 或 3.9兼容性最好第三方库基本都支持django 3.2 LTS长期支持版稳定性和资料丰富度都优于4.xMySQL 5.7 或 8.0推荐8.0注意配置好字符集Pandas 1.3 以上数据处理主力scikit-learn 1.0 左右用于计算余弦相似度矩阵提示django 3.2 对Python版本有硬性要求装之前先确认python --version别一上来就pip install django把最新版装上了最新版有时候和某些第三方插件不兼容。装好之后用django-admin startproject movie_recommend创建项目再python manage.py startapp recommend创建应用。这个命名有讲究项目名用下划线不是中划线否则后面import会有问题。3.2 数据集的选择与预处理细节电影推荐领域最经典的数据集是MovieLens但直接裸用会有几个问题。原始数据里的用户ID和电影ID是纯数字编号而你要做的是展示给用户好看的电影信息所以建议先同步一份电影元数据片名、类型、海报链接再和评分数据做关联。我的预处理流程是固定的三步读入ratings.csv和movies.csv用pd.merge()关联剔除没有对应电影信息的评分记录。将用户ID和电影ID分别映射为从0开始的连续整数这一步是为了后面构建矩阵时不出索引越界。过滤掉评分次数过少的用户比如小于10条否则冷启动用户太多推荐效果会很难看。import pandas as pd ratings pd.read_csv(ratings.csv) movies pd.read_csv(movies.csv) # 清洗缺失值并合并 data pd.merge(ratings, movies, onmovieId) data data.dropna(subset[title, rating]) # 用户和电影重新编码 user_ids {uid: i for i, uid in enumerate(data[userId].unique())} movie_ids {mid: i for i, mid in enumerate(data[movieId].unique())} data[uid] data[userId].map(user_ids) data[mid] data[movieId].map(movie_ids) # 过滤冷门用户 valid_users data.groupby(uid).size() data data[data[uid].isin(valid_users[valid_users 10].index)]这段代码跑完数据就变得规整了。后面所有算法计算都基于uid和mid这两个映射字段原始ID只用来对接详情展示。3.3 同步到MySQL的两种姿势数据清洗完要落到数据库里供django使用。我建议同步三张表用户表、电影表、评分表。评分表是核心字段包括user_id、movie_id、rating、timestamp电影表除了ID还要有标题、类型和海报URL。同步方式有两条路。一条是直接在django的ORM里写脚本循环插入适合数据量几千条的场景代码简单但慢。另一条是先LOAD DATA INFILE导入临时表再用SQL插入正式表适合几万条以上速度差距在十倍以上。如果你只是做课程级别的项目几千条数据直接脚本插入就够了。但要是在答辩时被问到“如果数据量上百万怎么做”你得能说出“分批量提交”“关闭自动提交”这类优化话术这比实际代码更体现水平。实操心得往MySQL插数据时一定记得给评分表的(user_id, movie_id)建联合索引。这个索引在生成用户推荐列表时会被高频查询不建的话数据过万后接口响应会肉眼可见地变慢。4. 协同过滤算法从原理到代码4.1 相似度计算的数学基础协同过滤离不开相似度度量最常用的有两个余弦相似度和皮尔逊相关系数。余弦相似度看的是两个向量方向上的相似程度公式是向量内积除以模的乘积皮尔逊相关系数则是先各自减去均值再算余弦相似度能消除评分尺度差异带来的影响。实际场景里用户A习惯打高分、用户B习惯打低分两者可能品味一致但打分尺度完全不同。这时候用余弦相似度可能算出来相似度不高而用皮尔逊相关系数就能准确捕捉到两者的正相关关系。这也是为什么在评分预测里皮尔逊公式的效果通常优于纯余弦。皮尔逊相关系数的公式表达两个用户的评分向量分别为r_a和r_b先算平均分再计算协方差除以标准差之积结果落在 -1 到 1 之间。实现起来用scikit-learn的pairwise_distances配合correlation指标非常方便。4.2 基于物品的协同过滤近邻计算基于物品的协同过滤核心是构建“物品相似度矩阵”。具体来说对任意两部电影找到同时给这两部电影评过分的用户集合用这些用户的评分计算两部电影的相似度。代码逻辑并不复杂但有点绕建议先看注释再看代码def compute_movie_similarity(data, top_k20): # 构建 电影-用户 评分矩阵 movie_user_matrix data.pivot_table(indexmid, columnsuid, valuesrating) movie_user_matrix movie_user_matrix.fillna(0) # 使用余弦相似度计算物品间相似度 from sklearn.metrics.pairwise import cosine_similarity sim_matrix cosine_similarity(movie_user_matrix) # 转成字典并取每个电影的TopK相似物品 movie_sim_dict {} for i, mid in enumerate(movie_user_matrix.index): sim_scores sim_matrix[i] # 排除自己取前K个 top_indices sim_scores.argsort()[-top_k-1:-1][::-1] movie_sim_dict[mid] [ (int(movie_user_matrix.index[j]), float(sim_scores[j])) for j in top_indices if j ! i ] return movie_sim_dict这里有个关键细节fillna(0)把缺失评分填成0是因为余弦相似度公式在向量不等长时需要补零才能计算。这个方法在学术上叫“朴素实现”严谨度够用但同时也意味着如果两部电影恰好被同一批人打了一样的分数相似度会异常高——这在真实场景里时有发生不用太担心毕设展示没问题。4.3 预测评分与推荐生成有了物品相似度矩阵给用户推荐电影就变成两步操作。第一步把用户已经打过分的电影找出来第二步遍历这些电影的相似电影累加加权评分最后按照预测分数排序取TopN。加权评分的公式为预测分 (当前电影的相似度 × 用户对相似源电影的评分) 的加权平均数。通俗讲你和一部电影的相似度越高你的评分在加权公式里的话语权越大。一个需要处理的问题是在用户冷启动阶段——新用户没评分过任何电影相似度逻辑完全失灵。我实践中的补救方案是“热度兜底”即冷启动时直接推荐全局平均分最高、评分人数最多的电影有数据后再切回协同过滤推荐。注意这个热度兜底策略一定要在答辩时主动讲出来因为它体现了工程思维——算法失效时有降级方案而不是崩溃或者返回空列表。5. django核心模块实现与页面渲染5.1 数据模型与用户认证django的ORM是直接映射数据库表的数据模型定义好了数据访问代码会简洁很多。用户模型我直接继承django自带的AbstractUser加一个avatar字段就够用不必从零造轮子。电影模型和评分模型按前面预处理的结构定义即可。from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): avatar models.URLField(blankTrue) class Movie(models.Model): tmdb_id models.IntegerField(uniqueTrue) title models.CharField(max_length255) genres models.CharField(max_length255) poster_url models.URLField(blankTrue) avg_rating models.FloatField(default0) rating_count models.IntegerField(default0) class Rating(models.Model): user models.ForeignKey(User, on_deletemodels.CASCADE, related_nameratings) movie models.ForeignKey(Movie, on_deletemodels.CASCADE, related_nameratings) score models.FloatField() created_at models.DateTimeField(auto_now_addTrue)avg_rating和rating_count是“冗余字段”意思是为了查询性能有意地在电影表里冗余了统计信息。这样首页展示电影列表时可以直接排序不需要每次关联子查询算平均分。这种设计在真实系统里非常常见答辩时能说出“用空间换时间”这句很加分。5.2 推荐服务的缓存与降级设计推荐服务是整个系统的核心调用频率最高所以在设计上我特别讲究缓存。第一次为用户计算完推荐列表后直接把结果存到Redis里设置过期时间一小时同一小时内用户再刷新页面直接从Redis拿到结果响应时间从几百毫秒降到几十毫秒。缓存之外还有一层降级如果Redis挂了代码要能自动回退到实时计算模式。实现上就是catch异常后走兜底逻辑保证用户永远能看到页面而不是看到“系统繁忙”。这个设计在互联网公司叫“多级容灾”虽然是毕设但代码里体现这种意识质量直接上一个档次。import redis r redis.Redis(hostlocalhost, port6379, db0) def get_recommendations(request): user_id request.user.id cache_key frec:user:{user_id} try: cached r.get(cache_key) if cached: return JsonResponse({recommendations: eval(cached)}) except redis.RedisError: pass # 缓存不可用则走实时计算 recs compute_recommendation_for_user(user_id) try: r.setex(cache_key, 3600, str(recs)) except redis.RedisError: pass return JsonResponse({recommendations: recs})5.3 前端页面展示与交互拆解页面上我分了四个主要区域顶部导航栏、轮播推荐位、电影卡片流、我的评分列表。推荐位是协同过滤结果的重点展示区用大图海报加“猜你喜欢”的标签电影卡片流默认按热度排序用户可以点击“推荐”按预测评分重排。为了让项目观感不像传统后台系统我做了两个小设计。第一个是评分交互用户点击星星打分的动作通过AJAX提交不刷新页面即可更新评分结果第二个是实时刷新打完分后立刻在页面上重新渲染推荐结果让用户直观感受到“我的操作影响了推荐”——这一点在演示时非常震撼观感分直接拉满。前端技术上我只用了原生JavaScript加少量jQuery没有上Vue或React。原因很简单毕设的核心考点在后端和算法前端堆复杂框架反而会分散注意力而且会让论文不好写——你总不能花大篇幅去写框架源码解读吧当然如果答辩要求里明确写了“页面美观”那就另当别论。6. 远程调试与项目定制在线演示场景下的实战经验6.1 局域网演示的调试方案很多同学的毕设最终需要在线演示不管是给导师看还是远程答辩展示。这时候就涉及一个很现实的问题怎么让不在同一台电脑上的人访问到你的系统。我用的方案很简单在有图形界面的服务器或一台主力电脑上启动django服务设置ALLOWED_HOSTS加入自己的局域网IP或公网映射域名然后python manage.py runserver 0.0.0.0:8000。访问时用http://对方看到的IP:8000就行。如果你用的是云服务器那就更简单了记得把安全组的8000端口放行。这一步踩坑概率极高很多人服务起了半天访问不到一看安全组没开端口。注意ALLOWED_HOSTS如果用通配符*在DEBUG模式关闭后会报错必须在配置里写清楚实际访问的域名或IP。6.2 答辩演示前一定要检查的三个环节答辩演示是最容易出现事故的场景我总结了三项“事前必查清单”按重要性排序第一数据量要适中。建议预热800到1500条评分数据太少了推荐效果看不出来太多了页面渲染会卡顿。第二冷启动用户要预留。提前准备一个已经打过50部以上评分的测试账号答辩现场演示给新注册用户看会陷入空白推荐的尴尬。第三Redis服务必须提前启动。推荐接口依赖缓存没启动虽然会降级道实时计算但首次请求会明显变慢给评委留下“系统不够流畅”的印象。6.3 如何把毕设往自己方向定制如果是三个人一组的小组项目或者导师要求你做一些差异化设计我推荐几个性价比高的定制方向加入用户偏好标签让用户选择喜欢的电影类型动作、爱情、科幻用这个标签做粗排再用协同过滤精排加入时间衰减因子用户在最近一周的行为权重高于三个月前的行为这在技术上叫时间窗口加权增加可视化统计页面用ECharts展示观影热度、评分分布、推荐命中率这部分论文里能放图非常加分如果时间极度充裕还可以考虑引入内容特征相融合的混合推荐即把电影的“类型标签”编码成特征向量和协同过滤的相似度加权取平均。这个方向属于锦上添花适合学有余力的同学普通场景不做也不影响主流程完整。6.4 常见问题速查表与排查日志我在开发和调试过程中遇到过几个高频问题整理成对照表遇到同类情况可以直接照着排查现象常见原因解决办法启动后访问URL报404urls.py路由没配置或APP未添加进INSTALLED_APPS核对路由和settings配置注册时报数据库错误数据库迁移未执行运行python manage.py makemigrations migrate推荐页返回500相似度矩阵为全零数据量太少检查评分数据量保证每部电影至少被评5次以上中文乱码MySQL字符集不是utf8mb4建库时指定utf8mb4相似电影结果异常未排除自身或相似度矩阵索引错位打印矩阵对角线检查若不为0说明没排除自身页面样式失效静态文件加载失败检查STATICFILES_DIRS配置运行collectstatic排查问题有个总原则先看日志不要瞎猜。django的报错信息非常详细大部分问题在控制台里已经告诉你发生在哪一行、什么类型的错误。拿同样的错误信息去查比自己在代码里漫无目的地翻要快得多。7. 扩展进阶方向与论文写作思路如果到这一步项目已经平稳落地还剩最后一段路要用心走——毕业论文。论文的结构我建议这么搭第一章绪论讲推荐系统在流媒体时代的价值第二章相关技术综述逐个介绍django框架、协同过滤算法、大数据预处理技术第三章系统需求分析与设计画系统用例图和模块图第四章系统实现按照数据模块、算法模块、Web模块三个维度展开并贴关键代码第五章系统测试用功能测试表格加性能测试曲线图。论文里最容易出彩的地方是“推荐效果评估”。你可以用离线测试的方式把数据集划分成训练集和测试集用召回率、精确率两个指标计算不同近邻数量K下的效果画出一张折线图。这就是标准学术论文里“实验评估”的完整流程导师看到这里基本不会卡你。实操心得评估实验一定要提前跑因为参数调优可能来回花两三天。数据量小看不出来差异数据量太大跑一夜也是常态确定K值的横坐标从5、10、15、20、25五档入手够用了。我个人在实际操作中的体会是推荐系统这个题目最怕的就是纯“调包”你不理解相似度矩阵是怎么构建的、冷启动问题怎么处理遇到一个问题就卡死一个。反过来如果底层原理通了这个项目的每一行代码都像是自己长出来的——要什么功能加什么功能答辩时随便往深了问都能接得住。最后分享一个小技巧写代码时务必保持每个模块的函数都加上docstring注释就算写得简短。这不仅是为了论文查重时的代码降重更是为了三个月后你回头调试时还能看懂自己当初的思路。毕设是大学的谢幕项目值得你认真把它打磨成一部“能拿得出手的作品”而不只是一份“交差的任务”。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑