电影票房预测分析系统:Django+Echarts+机器学习完整实战

发布时间:2026/9/10 8:48:22
电影票房预测分析系统:Django+Echarts+机器学习完整实战 每年到这个时间点总能看到一批毕业生在论坛里蹲电影票房相关的毕设题目一眼望过去全是“XX电影数据分析系统”“基于XX的票房预测”但真正能落地跑通的寥寥无几。我自己去年帮带的一个学弟做的就是这个方向题目就叫“电影市场预测分析系统”技术栈是 Python Django Echarts顺带加了一些简单的机器学习预测和可视化大屏展示。因为实际动手踩了不少坑从数据采集清洗、数据库设计到图表渲染、模型预测调优整个过程走下来有一套很顺的路径今天就把这套完整方案整理出来给正在做毕设或者想拿这个方向练手的同学一个可以直接参考的版本。先说清楚这系统是干嘛的。它本质上是一个 Web 项目后端用 Django 提供数据接口和页面渲染前端用 Echarts 做票房数据的可视化展示包括票房趋势、类型分布、地区占比、排行榜这些常规维度同时接了一个简单的票房预测模块基于历史数据做回归预测用来估算一部电影上映后的票房区间。适合的人群很明确计算机、大数据、人工智能方向的毕业生尤其是想做数据分析 / 可视化 / 机器学习应用方向但又不想卷算法的同学拿这个当作课设或者毕设的底子非常吃香。1. 项目整体设计与技术路线1.1 需求拆解这个系统到底要做什么毕设项目最怕的是需求写得不清楚做到一半发现逻辑混乱。这个系统的核心需求其实可以拆成三块数据管理、可视化分析、票房预测。数据管理负责把电影信息、票房数据、上映时间、评分等抓下来存进数据库提供增删改查的能力这是 Django 最擅长的部分。可视化分析负责把数据库里的数据通过接口取出来在前端用图表的形式呈现Echarts 干的就是这件事。票房预测则需要基于历史数据训练一个简单的回归模型让用户选择一部电影的属性预测它上映后的票房量级。从用户视角来看系统大概有几个页面数据总览大屏、票房趋势分析、电影类型分布、地区票房榜、电影热度分析、票房预测工具。每个页面对应一到两个核心图表数据来源统一走后端接口页面只负责渲染和交互。这个拆分的好处是前后端职责清晰查 bug 的时候不会一头雾水。1.2 技术选型为什么是 Django Echarts 机器学习很多初学的人一上来就往复杂了想非要用 Spring Boot Vue Redis 才觉得有排面结果自己根本不熟最后连环境都配不明白。我建议稳住用你自己最熟、社区资料最多的技术栈组合。Django 的优势在于自带 ORM、Admin 后台、模板引擎和强大的生态。写一个博客型的数据展示网站Django 不需要额外搭前端工程一个 Template 模板就能渲染出完整页面配上 DRFDjango Rest Framework做接口数据返回 JSON 给前端非常顺手。Echarts 是百度开源的可视化库图表类型丰富文档齐全配置项写起来也很直观做毕设展示完全够了。预测模块的话不需要上深度学习那套东西数据量不够硬件也撑不住。用 Scikit-learn 的线性回归、随机森林或 XGBoost 做票房区间预测既符合“人工智能”的题眼又能实际跑出结果答辩的时候也容易讲清楚算法原理。这套方案的综合成本低、周期短、效果上限高。1.3 项目目录结构与模块划分项目结构直接决定后续开发效率。我按 Django 的应用App来划模块而不是把全部逻辑堆在默认的views.py里。大致结构是这样的movie_analysis/ ├── manage.py ├── requirements.txt ├── movie_analysis/ # 项目配置 │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── movies/ # 电影数据应用 │ ├── models.py │ ├── views.py │ ├── urls.py │ ├── admin.py │ ├── data_loader.py # 数据导入脚本 │ └── services/ │ └── predictor.py # 预测模型 ├── stats/ # 可视化分析应用 │ ├── views.py │ └── urls.py ├── templates/ │ ├── base.html │ ├── dashboard.html # 总览大屏 │ ├── trend.html ├── static/ │ ├── css/ │ ├── js/ │ └── echarts.min.js └── data/ ├── movies_clean.csv └── boxoffice.csv这种结构的好处是movies应用管电影和预测stats应用管图表接口和页面路由职责互不干扰。后面加功能不会越改越乱。2. 数据层票房数据从哪来、怎么洗2.1 数据源选择与采集思路做电影分析首先得有数据。常见的公开数据源有 TMDB、豆瓣电影、猫眼电影、艺恩等。但毕设项目不建议直接写爬虫去抓实时数据一方面反爬机制会让你头疼另一方面数据不稳定答辩现场万一挂了就尴尬。我学弟当时用的是 GitHub 上一个公开的电影票房数据集包含 2007 年到 2023 年的电影信息字段有电影名称、上映日期、类型、制片国家、票房、评分、导演、主演等接口是 CSV 和 SQLite 两种格式。下载后直接作为初始种子数据后面再手工补充少量新片的数据。这个思路省时省力又能保证数据质量。如果一定要爬数据不要头铁直接怼大站找那些反爬弱的公开 API比如 TMDB 的 API注册个 key 就能拿数据。注意限速和请求头伪装频控调低一点能做到 2 秒一个请求最保险。2.2 数据清洗与特征工程数据拿到手以后千万不能直接灌数据库要先洗一遍。常见的脏数据包括缺失值、重复行、票房字段类型不一致、日期格式混乱、分类字段大小写不统一。我用 Pandas 做了预处理代码大致长这样import pandas as pd df pd.read_csv(data/movies_raw.csv) # 去掉完全重复的行 df.drop_duplicates(inplaceTrue) # 票房统一为“万元”为单位的数值 df[box_office] df[box_office].str.replace(亿, ).astype(float) * 10000 # 日期统一格式 df[release_date] pd.to_datetime(df[release_date], errorscoerce) # 填充缺失评分用该类型的均值 df[rating] df[rating].fillna(df.groupby(genre)[rating].transform(mean))特征工程上我选了几个对票房影响明显的特征电影类型、上映月份、档期春节档 / 暑期档 / 国庆档 / 其他、首日口碑评分、主演热度指数针对顶级演员做映射权重、导演历史票房均值。这些特征构造好以后存成新的表后续预测模块直接调用非常方便。2.3 数据库模型设计Django 的 ORM 模型是整个系统的地基设计合理能省掉后面非常多的麻烦。我设计的核心模型有两个电影基础信息表Movie和票房每日数据表DailyBoxOffice。from django.db import models class Movie(models.Model): name models.CharField(max_length128, verbose_name电影名) release_date models.DateField(verbose_name上映日期) genre models.CharField(max_length64, verbose_name类型) country models.CharField(max_length32, verbose_name制片国家) rating models.FloatField(verbose_name豆瓣评分) director models.CharField(max_length64, verbose_name导演) box_office_total models.FloatField(verbose_name总票房(万元)) budget models.FloatField(verbose_name制作成本(万元), default0) actor_hot_index models.FloatField(verbose_name主演热度, default0) class Meta: db_table movie_info ordering [-box_office_total] class DailyBoxOffice(models.Model): movie models.ForeignKey(Movie, on_deletemodels.CASCADE) date models.DateField(verbose_name日期) daily_bo models.FloatField(verbose_name单日票房(万元)) screen_cnt models.IntegerField(verbose_name排片场次) class Meta: db_table daily_box_office unique_together (movie, date)设计要点有两个。一是外键关系要明确DailyBoxOffice 通过外键指向 Movie这样查询一部电影的票房曲线只需要反向关联不用额外建冗余字段。二是金额字段统一用 FloatField 存“万元”不存成字符串避免后面统计时反复转换。3. 后端核心Django 接口与业务逻辑3.1 Django 项目初始化与应用拆分环境这块其实是很劝退新手的点先说下最稳的路径。用 virtualenv 创建独立的虚拟环境然后安装 Django 4.2 LTS 版本、pandas、numpy、scikit-learn、djangorestframework、django-cors-headers、pymysql 这些依赖。requirements.txt 里写好版本号换机器一键安装。python -m venv venv source venv/bin/activate # Windows 下执行 venv\Scripts\activate pip install django4.2 pandas numpy scikit-learn djangorestframework django-cors-headers pymysql创建项目后先配置 settings.py 的数据库、静态文件目录、模板目录和跨域设置。我是用 MySQL 还是 SQLite 呢本地跑毕设强烈建议 SQLite零配置文件即数据库如果服务器上部署且数据量大了再切 MySQL。Django 切换数据库非常方便改一下 ENGINE 和 NAME 就行。DATABASES { default: { ENGINE: django.db.backends.sqlite3, NAME: BASE_DIR / db.sqlite3, } } STATIC_URL /static/ STATICFILES_DIRS [BASE_DIR / static]3.2 数据查询接口实现可视化页面需要的接口大致有这么几个总票房统计概览、年度票房趋势、类型票房占比、地区票房 Top10、电影排行列表。这些接口用 DRF 写能省掉很多序列化的手写代码但毕设如果不想引入太多框架直接用 Django 的 JsonResponse 返回字典也是非常干净的。我学弟这里用了 DRF 的 APIView因为写起来更规范答辩时也能提一句“基于 RESTful 风格的接口设计”。以票房趋势接口为例from rest_framework.views import APIView from rest_framework.response import Response from django.db.models import Sum from movies.models import DailyBoxOffice from datetime import datetime class BoxOfficeTrendView(APIView): def get(self, request): year request.query_params.get(year, datetime.now().year) daily_data ( DailyBoxOffice.objects .filter(date__yearyear) .values(date) .annotate(totalSum(daily_bo)) .order_by(date) ) dates [d[date].strftime(%m-%d) for d in daily_data] totals [d[total] for d in daily_data] return Response({dates: dates, totals: totals})这个接口输出的 JSON 结构是标准的{dates: [...], totals: [...]}前端 Echarts 拿到后直接把数组塞进 series几乎没有二次处理成本。接口返回格式保持统一是开发过程中很重要的一点。3.3 票房预测模块的算法实现预测模块是系统的亮点也是“人工智能”体现得最明显的地方。我选了随机森林回归作为主力模型因为它对特征数值范围不敏感不容易过拟合而且能输出特征重要性答辩时可以解释哪些因素影响票房最大。训练流程大致是这样从数据库读电影数据把类型、档期这类类别特征做 LabelEncoder 或 One-Hot然后划分训练测试集用 R2 和 MAE 评估效果。import joblib import pandas as pd from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder def train_model(): df pd.read_csv(data/model_features.csv) le LabelEncoder() df[genre] le.fit_transform(df[genre]) df[slot] le.fit_transform(df[slot]) features [genre, slot, release_month, rating, actor_hot_index, director_avg_bo, budget] X df[features] y df[box_office_total] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) model RandomForestRegressor( n_estimators300, max_depth12, min_samples_leaf2, random_state42 ) model.fit(X_train, y_train) print(R2:, model.score(X_test, y_test)) joblib.dump(model, movies/models/boxoffice_model.pkl) joblib.dump(le, movies/models/label_encoder.pkl) return model预测的时候把用户输入的属性变量做同样的编码和拼接调用model.predict()输出结果。为了让预测结果更容易理解我把预测值转换成“预测票房区间”比如 1.2 亿到 1.8 亿之间而不是一个生硬的数字用户一看就知道大致量级。这个技巧在答辩演示时效果很好。4. 前端可视化Echarts 图表实战4.1 Echarts 引入方式与基本配置Echarts 的引入方式有两种一种是直接下载echarts.min.js放到 static 目录另一种是 npm 引入。Django 项目用不着 npm直接 script 标签引入本地文件是最简单可靠的。去官网下载构建版注意选的是“完整版”而非“核心版”否则地图组件可能缺失。script src/static/js/echarts.min.js/script引入后基本思路是先给一个 div 容器设置宽高然后echarts.init(dom)初始化实例再调用setOption配置图表。setOption 是 Echarts 的灵魂所有图表的样式、数据、交互都在这里配置。4.2 票房趋势、类型分布、榜单三大图表这三个图表是系统的门面做出来以后页面效果立竿见影。票房趋势图用折线图用刚写的接口数据填进去。配置里要多用tooltip的trigger: axis鼠标滑过能展示各个日期对应的票房交互感非常好。平滑曲线改成smooth: true观感高级很多。类型分布图用饼图。注意饼图的 data 要传{name: 动作, value: 1200}这种格式和折线图不一样。用radius: [30%, 70%]配置一个环形饼图比实心饼图好看还能把中间区域空出来放总票房数字这个设计很多大屏项目都在用。排行榜用横向柱状图。横向柱状图的关键是把 xAxis 和 yAxis 的类型对调数据量大的时候用yAxis的inverse: true把最高票房的电影放在最上面。配置好 label 显示数值效果非常直观。const chart echarts.init(document.getElementById(trendChart)); fetch(/api/boxoffice/trend/?year2023) .then(res res.json()) .then(data { chart.setOption({ tooltip: { trigger: axis }, xAxis: { type: category, data: data.dates }, yAxis: { type: value }, series: [{ name: 总票房(万元), type: line, smooth: true, areaStyle: {}, data: data.totals }] }); });4.3 可视化大屏布局与交互既然系统叫“可视化分析”页面就不能做成传统的表格堆列表至少有一个页面要像大屏的样子。做法是网格布局把页面分成多个卡片区域每个卡片放一个图表背景用深色标题区域加一排统计卡显示总票房、总电影数、评分均值等指标。布局上我直接用 CSS Grid四列两行整体自适应。深色背景下 Echarts 的轴线颜色设置为浅色文本颜色也是近白色。每个图表之间留出间距视觉上不会挤在一起。交互部分做了两个小功能。第一个是点击饼图的某一个扇区下方会联动显示该类型下票房前十的电影列表第二个是年份下拉框切换折线图和排行榜一起刷新。这些交互用 Echarts 的chart.on(click, params)事件实现拿到参数以后调用对应的接口更新其他图表。这些细节做出来答辩时老师问“有没有交互功能”你就可以直接现场演示了。5. 系统部署与运行全流程5.1 本地运行三步走跑起来是一个项目最基本的体面也是很多同学卡住的地方。本地运行基本上三步第一步把数据导入数据库python manage.py makemigrations python manage.py migrate python manage.py shell -c from movies.data_loader import load_data; load_data()第二步启动开发服务器python manage.py runserver 0.0.0.0:8000第三步浏览器访问 http://127.0.0.1:8000 先看首页大屏能不能正常出图再看接口有没有报错。这三步如果顺畅说明环境、数据库、数据导入都没问题。如果哪一步卡住先看命令行报错信息99% 的情况是缺依赖或者数据库没迁移按照报错找解决方案很快。5.2 线上部署要点毕设如果只要求演示本地跑完全足够。但如果老师要求部署到服务器或者你想放到线上展示给朋友看那就得做部署。Django 部署的方案通常是用 Nginx Gunicorn MySQL。核心流程是项目代码传到服务器创建虚拟环境装依赖迁移数据库然后用 Gunicorn 启动 Django把它配到 Nginx 反向代理静态文件由 Nginx 直接托管。配置 Nginx 的时候最容易踩的坑是静态文件 404。解决方式是在 settings.py 里设置STATIC_ROOT然后执行python manage.py collectstatic把所有静态文件集中到一个目录再让 Nginx 指向这个目录。这一步一定要在部署前做否则页面打开全是裸的。需要留意的是 DEBUG 要改成 FalseALLOWED_HOSTS要加上你的服务器 IP 或域名。还有一些安全设置比如 SECRET_KEY 不要硬编码在源码里可以用环境变量代替。安全设置不一定要很深但至少不该让项目以明显不安全的配置直接裸奔。6. 常见问题排查与避坑实录6.1 Django 跨域与请求问题写接口的时候最常见的报错是跨域。前端页面在本地开 8000 端口请求接口如果走了另一个端口或者线上域名浏览器就会拦。开发阶段直接装django-cors-headers然后CORS_ALLOW_ALL_ORIGINS True演示没压力。但如果生产环境也放开所有域名其实是有安全风险的所以线上建议配置白名单。还有一个容易忽略的坑是模板引擎在渲染 JSON 时把括号转义成了 HTML 实体导致前端拿到quot;之类的字符。这个问题的根源是用了{{ data }}直接渲染正确做法是把 JSON 传到json_script过滤器或者用 fetch 拉接口不要直接嵌入模板。6.2 Echarts 图表不显示问题Echarts 图表不显示90% 的原因都是容器没有高度。div 如果只设置了宽度没设置高度echarts.init能成功但图表区域为 0看起来就是一片空白。初始化之前用 Chrome 开发者工具看一下容器的高度如果是 0就给 div 写死一个height: 400px问题就解决了。另一个高频问题是图表数据格式不对。后端返回的某个字段多了一层嵌套或者日期格式是时间戳导致 x 轴数据全是null。我排查的方法是打开浏览器的网络面板看一眼 API 返回的 JSON 长什么样再拿 DevTools 的 Console 打印一下setOption的数据基本定位一遍就稳。6.3 预测模型过拟合与数据偏差问题模型预测这块常见的坑是数据量太少导致过拟合。电影样本只有两三百条时随机森林在训练集上分数很高测试集却拉胯。解决方式是加正则参数min_samples_leaf调大、max_depth限制深度还可以开max_featuressqrt做随机特征选择。我用下来的经验是max_depth10~12、min_samples_leaf2~4在小样本上比较稳。还有一个更隐蔽的问题是训练集和预测时特征不一致。比如训练数据里有类型为“纪录片”预测模块的用户输入没有这个选项LabelEncoder 硬编码就会报错。我的做法是在保存模型的同时把编码器对象一起保存而且所有类别以classes_为准预测前统一用同一个编码器 transform不在预测接口里重新 fit。实际操作中还有一个我挺推荐的小优化模型训练完以后把特征重要性输出到前端展示告诉用户“评分和主演热度对票房影响最大”这比单出个预测数字更有说服力答辩时老师一听就知道你是真做了分析而不是死套模型。整套系统做下来前后大概花了两周时间其中数据清洗和模型调优占了一大半写代码本身并没有想象中那么慢。我现在回头看这个项目最大的价值不是“演示效果多炫”而是它把 Web 开发、数据库设计、数据分析和机器学习串在了一个完整流程里让你把课堂上的碎片知识拼成了一整块。如果后续还想扩展可以往推荐系统方向加一点用户观影偏好推荐或者用爬虫定时更新每日票房数据让系统真正“活”起来。做毕设最忌讳的是闭门造车中间卡住的时候多去查别人的开源项目看看别人怎么组织代码、怎么处理边界情况很多问题都能迎刃而解。