
简介面向计算机相关专业正在准备毕业设计的学生及需要项目实战的Python学习者这份电影数据可视化及票房影响因素分析与预测源码包围绕数据采集、存储、可视化分析与票房预测的完整流程展开可直接用于课程设计、期末大作业或毕设项目。压缩包共38个文件约5.18MB涵盖6个py核心脚本、3个ipynb交互式分析笔记、1个sql数据库脚本、1份pdf文档以及24张png可视化结果图并附带README说明其中png直观呈现各阶段输出ipynb便于分步执行与修改整体结构清晰、模块划分明确。已有425人学习经过严格调试下载即用。从豆瓣电影数据的导入、基于Pandas和SQL的多种可视化展示到票房影响因素分析与预测建模各环节均有对应代码与结果截图便于对照理解分析思路也适合在现有框架上快速二次开发完整覆盖数据到结论的实践链路。1. 基于 Python 的电影数据可视化与票房预测这套毕设源码包拆开来看做“基于 Python 的电影数据可视化及票房影响因素分析与预测”的毕设最怕的不是没思路而是下的源码包打不开、库装不上、数据导不进去。这套包我在本地完整跑过围绕豆瓣电影数据把 SQL 建库、数据抓取清洗、Pandas 可视化、SQL 聚合可视化、票房预测串成一条完整链路。压缩包里有可直接导入的 douban.sql有三个 Jupyter Notebook 分别负责可视化、SQL 查询和预测result 目录还留了二十来张结果图供写文档引用。适合两类人拿它当课程设计或期末大作业交差的在校生以及学完 pandas 和 sklearn 想看看真实项目样子的学习者。先泼盆冷水这份资源的票房预测 R² 稳定到 0.5 左右已经不错真实电影数据又脏又少预测本身就带玄学成分。2. 数据准备层douban.sql 与 src 下脚本的分工整个项目是先有数据才能画图、才能预测。src 目录下不是只有一个 main.py而是五个 Python 脚本加一份 SQL 脚本。刚解压的人最容易犯的错误是直接双击 predict.ipynb 跑结果报一大堆找不到表、找不到文件。先把这一层的分工看清后面才不浪费时间。文件职责主要产出douban.sql建库建表电影主表、详情表、类型关联表movie_basic.py抓取列表页基础信息片名、年份、评分、评分人数写库movie_detail.py抓取详情页扩展信息片长、地区、导演、演员写库attachfile.py数据挂接与回填按外键把详情挂到主表database.pyMySQL 连接封装统一的 Connection 对象unit.py清洗与单位转换票房单位归一、类型拆分main.py流程入口按顺序调度上面的脚本从工程角度看这种拆分比把几百行代码堆在一个 ipynb 里合理得多。抓列表、抓详情、补数据三个阶段解耦任何一个阶段挂了都能单独重跑不用从头再来。下面按执行顺序讲每部分怎么落。2.1 先建库douban.sql 的导入方式与表结构预期拿到压缩包后第一步不是 pip install而是把数据库建起来。我习惯用 mysql 命令行直接 source比在 Navicat 里复制粘贴执行更不容易漏语句。mysql -u root -p Enter password: ****** source D:/movie_project/src/douban.sql;路径里建议用正斜杠Windows 的反斜杠在 source 命令里偶尔会被转义解析出问题。如果你把 MySQL 跑在 Docker 容器里命令换成docker exec -i mysql-container mysql -u root -p douban.sql效果一样。导入成功后可以SHOW TABLES;确认预期能看到电影主表、详情表以及电影和类型的关联表。关于表结构电影主表一般包含片名、上映年份、评分、评分人数、票房这些核心字段详情表再补片长、国家地区、导演演员这类扩展信息。由于豆瓣电影是典型的弱结构化数据类型字段经常是“剧情/爱情/冒险”这种用斜杠拼接的多值形式所以单独拆一张类型关联表是常见做法。提示导入前先确认 MySQL 版本。如果 douban.sql 里用了 MySQL 8 专属的排序规则5.7 会直接语法报错具体处理放到第 5 章统一讲。2.2 抓取脚本的分工movie_basic.py 和 movie_detail.py 各管一段这部分对应答辩时最常见的追问“你的数据是自己爬的还是网上找的”答案是两者都有——douban.sql 里已经有存量数据抓脚本是用来增量更新的。movie_basic.py 负责列表页抓的是每部电影最基础的信息片名、年份、评分、评分人数、类型。requests 请求列表页后用 BeautifulSoup 解析定位每个条目对应的 DOM 节点再把清洗后的字段写入 movie 主表。movie_detail.py 负责点击进入详情页后的扩展字段比如片长、制片国家、导演和演员列表。写进详情表后由 attachfile.py 按电影 id 把两张表关联起来形成一个可 join 的完整结构。实际跑的时候要注意反爬。豆瓣对高频请求比较敏感我一般会在请求头带上完整的 User-Agent并且在两次请求之间加time.sleep(random.uniform(1, 3))。如果你只是想把这套源码跑通交作业完全没有必要真的去爬全量数据直接用 douban.sql 里已有的数据就够了抓取脚本这部分在文档里说明“支持增量更新”就行。强行爬全量一旦触发限制反而把自己卡在数据这一关。2.3 database.py 与 unit.py连接参数和清洗口径统一database.py 做的事很简单就是返回一个可用的 MySQL 连接但这个小封装值得学一下。它把所有连接参数集中在一个函数里其他模块调用时不用各自写一遍 pymysql.connect。import pymysql def get_conn(hostlocalhost, port3306, userroot, password123456, databasedouban, charsetutf8mb4): return pymysql.connect( hosthost, portport, useruser, passwordpassword, databasedatabase, charsetcharset )charset 这里不要改成 utf8豆瓣数据里有生僻片名和特殊符号utf8mb4 才能完整存下来。password 参数在实际使用时建议改读配置文件不要硬编码到代码里但毕设项目里直接写在连接函数里也说得过去答辩老师一般不会揪这个点。unit.py 是整包容易被忽略但很关键的文件。电影票房字段在数据源里格式混乱有的写“1.2亿”有的写“8500万”还有的直接给数字。unit.py 里常见的做法是提供gross_to_wan(value)把“1.2亿”转成 12000单位统一成万元把“8500万”转成 8500。类型字段用type_split(type_str)按斜杠拆成列表方便后续构造 one-hot 特征。没有这两个清洗函数后面可视化和建模全都会被脏数据带偏。养成习惯看这类源码包先打开 unit.py 扫一遍就能判断作者的数据口径是否统一。3. 可视化链路从 Pandas 图表到 SQL 聚合再到结果图数据进了库接下来是可视化。这套源码包很聪明地给了两条路线一条用 Pandas 直接在 DataFrame 上画另一条先写 SQL 聚合、再把结果交给 pyplot 渲染。两条路线实际对应两个不同的答辩问题“你会不会用 pandas 做数据分析”和“你会不会写 SQL 查数据”。两条都能讲清楚这个项目的完成度就不一样了。3.1 visualization_pandas.ipynb评分、票房与类型分布的绘图逻辑这个 notebook 的核心逻辑是读表、清洗、再画图。最常见的开场是票房 Top20 横向条形图这种图比竖向条形图更适合展示电影片名这种长文本。import matplotlib.pyplot as plt import pandas as pd # 从数据库读取主表 df pd.read_sql(SELECT title, gross_wan, rating FROM movie, conn) # 按票房取前 20 名 top20 df.nlargest(20, gross_wan) plt.figure(figsize(10, 8)) plt.barh(top20[title], top20[gross_wan]) plt.xlabel(票房万元) plt.tight_layout() plt.savefig(result/p_top20.png, dpi150)这里用nlargest而不是先sort_values再head(20)一行代码省掉两步操作而且不会因为数据里有空值把排序搞乱。savefig的 dpi 设到 150是兼顾图片清晰度和文件大小的常用值写进论文里放大看也不糊。如果讲稿里需要的是“评分与票房的关系”常见做法是画散点图x 轴评分、y 轴票房对数因为票房直接画的话那些亿元级别的离群点会把整个图压缩得没法看。取对数后再画散点趋势反而清楚得多。result 目录里p (2).png、p (4).png这类图就是 notebook 按顺序跑下来自动保存的中间结果你重新跑一遍会覆盖它们。3.2 visualization_sql.ipynb把聚合结果直接交给 pyplot这个 notebook 才是这个项目里最能在答辩时加分的地方。很多人的毕设只是“用 pandas 读 csv 画图”而这份资源里专门用了一个笔记本演示 SQL 查询和聚合相当于告诉评委“我不只会调 pandas 接口还会写 SQL”。SELECT t.type_name, COUNT(*) AS cnt, AVG(m.rating) AS avg_rating FROM movie m JOIN movie_type mt ON m.id mt.movie_id JOIN type t ON mt.type_id t.id GROUP BY t.type_name ORDER BY cnt DESC;这条 SQL 做了两件事算每个类型下的电影数量同时算每个类型的平均评分。前者反映市场供给后者反映观众口碑两个指标放在同一张图里就能直接得出“某个类型产量高但平均分低说明大量跟风作品拉低了口碑”这种结论。执行完把结果接进 DataFrame剩下的绘图步骤跟上一节完全一样df.plot.bar(xtype_name, ycnt)再补一个 y 轴标签就收工。这条链路的价值在于它把 SQL 和 Python 绘图串在了一起而不是各自孤立地展示。3.3 result 目录导览db_struct.png、output.png 与 p 系列图result 目录里二十来张图不是乱放的按内容可以分成三类写毕业设计文档时直接当素材。文件内容用途db_struct.png数据库表结构图放系统设计章节output.png程序运行总览图放运行结果开头p (1).png ~ p (19).png各类分析图表按顺序对应可视化的各个小节预测1.png真实值与预测值散点图放预测模块结果预测2.png特征重要性条形图放影响因素分析部分需要提醒的是这些图是作者当时跑出来的产物直接把别人的图贴进自己的论文答辩时一旦被问“这张图的数据口径是什么”就容易露馅。正确做法是把三个 notebook 完整跑一遍自行生成一份新的图文件名和内容大致对齐即可。时间戳也是证据之一重新跑出来的图是当前日期文档里写“笔者运行得到”就有底气。4. 票房预测predict.ipynb 的特征口径与建模流程票房预测是整套源码里最重的部分也是答辩时最容易拦下你的环节。很多人的误区是直接拿原始字段往 sklearn 里塞然后抱怨分数低。predict.ipynb 的思路不是这样先清特征再选模型最后用图验证一步步来。4.1 预测目标与特征构造单位、缺失值与类别编码预测目标很明确电影票房。这里的第一个坑是单位口径。如果数据里同时存在“1.2亿”和“8500万”模型会把这些当成纯字符串或混乱的数字完全学不出规律。第 2 章里 unit.py 的gross_to_wan就是在解决这个问题统一转成万元后再作为 y 值。特征方面常见的可解释特征包括下面这些。特征处理方式说明评分直接使用豆瓣评分0-10 浮点数评分人数缺失补 0反映讨论热度片长缺失补中位数缺失值占比高时别 drop上映年份直接使用捕捉年度趋势是否热门档期构造 0/1 变量1-2 月、7-8 月、10 月标记为 1类型one-hot 编码多类型可拆成多列代码上构造特征大致长这样features pd.DataFrame({ rating: movie_df[rating], rating_count: movie_df[rating_count].fillna(0), duration: movie_df[duration].fillna(movie_df[duration].median()), year: movie_df[year], is_holiday: movie_df[month].isin([1, 2, 7, 8, 10]).astype(int), })评分人数缺失补 0 而不是补均值是因为缺失大概率意味着“没有人看”这本身就是一个强信号。片长补中位数则是因为片长缺失跟冷门热门关系不大用中位数填充不会引入太大的偏误。档期这个特征才是票房分析里最有价值的部分春节档、暑期档、国庆档对票房的拉动作用往往超过评分本身。4.2 模型选型线性回归打底、随机森林提升预测任务在 sklearn 里能用开箱即用的模型不多以这个项目的数据量我一般会线性回归和随机森林回归各跑一组拿两组结果对比。线性回归的输出是系数可以直接回答“哪个因素对票房影响最大”随机森林则用来提升预测精度对评分与票房之间的非线性关系拟合得更好。from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( features, target, test_size0.2, random_state42) model RandomForestRegressor( n_estimators300, max_depth8, random_state42) model.fit(X_train, y_test) print(R2:, model.score(X_test, y_test))n_estimators设 300 是因为样本量不大300 棵树不会有明显过拟合同时也能让特征重要性更稳定。max_depth限制 8 层是防止树长得太深把训练集的细节背下来。random_state固定 42是为了让实验可复现下次再跑同一个 notebook 得到同一组数字写进论文里经得起复核。这里有个常见的翻车点直接把原始票房数值当 y 训练模型会极其偏向那些亿元级大片导致普通电影的预测全部坍缩到一个常数附近。常见做法是先对票房做对数变换np.log1p(target)让长尾分布压缩成近似的正态分布模型就老实多了。4.3 从预测1.png / 预测2.png 反推训练效果result 里这两张预测图是判断模型靠不靠谱的窗口。预测1.png 是真实值与预测值的散点图横轴真实票房纵轴预测票房点越贴近 45 度对角线说明越准。如果点形成一条水平带说明模型只预测对了大体量小体量电影基本被忽略如果出现对角线下方的密集点云说明存在系统性低估。预测2.png 是特征重要性条形图从这张图可以直接回答论文里“票房影响因素分析”那部分。正常情况下评分人数和评分会占据前两名档期特征排在中间年份和片长的作用相对弱。这跟行业直觉一致讨论热度比影片质量更直接地转化成首周票房而热度在数据里的代理变量就是评分人数。如果特征重要性的排序反常识比如片长排第一先别急着下结论回到数据里查一下是不是片长字段只有少数几部电影有值其他补的是同一个中位数。当某个特征 90% 都是同一个常数时树模型偶尔会用这个常数当切分点导致重要性虚高。提示预测结果不理想时先检查数据泄漏——有没有把“是否豆瓣高分榜”这类事后统计变量放进特征。凡是电影上映之后才产生的信息都不能用来预测上映前的票房。5. 避坑排错五个跑不通的关键节点和对应处理这一章是拆这套源码包最容易翻车的地方汇总。不是说代码本身有 bug而是环境、编码、路径这类问题在毕设场景里特别常见。每一条按现象、原因、解决的顺序写你可以直接对照排查。5.1 douban.sql 导入 MySQL 报 1064 语法错误现象在 Navicat 或命令行执行 douban.sql中途报ERROR 1064 (42000): You have an error in your SQL syntax导入中断。原因最常见的是 MySQL 版本差异。如果脚本是在 MySQL 8 上写的建表语句里可能带DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci而这个排序规则是 MySQL 8 专有的5.7 完全不认识直接语法报错。解决先用文本编辑器打开 douban.sql全局搜索utf8mb4_0900_ai_ci全部替换成utf8mb4_general_ci。如果文件里还有ENGINEInnoDB之外的其他引擎也一并改成 InnoDB。改完再用命令行 source 导入一次。这个方法能解决九成以上的导入失败。5.2 matplotlib 中文乱码标题和标签全变方框现象跑 visualization_pandas.ipynb图能出来但所有中文标题、坐标轴标签全部显示成一个个方框英文和数字正常。原因matplotlib 默认字体是 DejaVu Sans不包含中文字形。Windows 系统能显示中文是因为有微软雅黑和宋体但 matplotlib 不主动调用它们。解决在绘图代码最前面加两行配置plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False第二行必须写否则坐标轴上出现负号时会显示成方块。如果你在 Linux 服务器上跑SimHei 不存在需要先安装文泉驿正黑字体并改字体名为WenQuanYi Zen Hei或者直接把系统里已有的中文字体路径传给font_manager。5.3 predict.ipynb 跑出来 R² 为负数现象模型训练完毕model.score输出一个负数比如 -0.23。这意味着模型预测得比“用平均值瞎猜”还要差。原因三个常见因素。第一没对票房做对数变换极端值主导了损失第二缺失值直接 drop导致训练样本太少第三可能存在数据泄漏某个特征携带了未来信息。解决先对 target 做np.log1p变换再训练R² 通常会从负数转正。缺失值策略改成 5.1 里的 fillna 填充别 drop。最后检查特征列里有没有“上映后评分人数累计”“最终评分”这类本身就依赖结果的数据。排掉泄漏后用cross_val_score做五折交叉验证重新评估得到比单次 train_test_split 更可信的数字。记住跨验证集稳定在 0.4-0.6 的模型在电影票房预测里已经能写进论文了。5.4 装依赖时 sklearn 或 pandas import 崩掉现象照着 README 先装 pandas再装 scikit-learn结果import pandas直接抛ImportError: cannot import name is_numeric_dtype之类的问题或者 sklearn 装完 numpy 版本冲突。原因Python 3.11 以上搭配旧版 pandas 或 nvidia 相关的包时经常会遇到 C 扩展编译产物不匹配。最常见的是 numpy 版本太新或太旧跟 pandas、sklearn 要求的范围对不上。解决别用最新版 Python建议创建 Python 3.8 或 3.9 的虚拟环境。然后用requirements.txt一次装齐如果包里没提供这个文件按顺序执行pip install numpy1.24.4 pip install pandas2.0.3 pip install scikit-learn1.3.2 pip install matplotlib3.7.5 pymysql先定好 numpy 再装 pandas能避开大多数依赖的版本跳变。装完跑一遍python -c import pandas, sklearn, matplotlib三行 import 都成功再打开 notebook别上来直接 Run All。5.5 运行 main.py 报 FileNotFoundError找不到数据文件或 result 目录现象在 PyCharm 里点运行 main.py报错提示找不到 data 目录下的文件或者保存图片时提示No such file or directory: result/...。原因脚本里用的是相对路径data/movie.csv、result/output.png而相对路径是相对当前工作目录解析的。PyCharm 的默认工作目录跟终端命令行不一致双击运行跟python main.py运行的路径也不一致。解决把入口脚本里的路径改成基于__file__的绝对路径。放在文件开头from pathlib import Path BASE_DIR Path(__file__).resolve().parent.parent之后所有文件路径都写成BASE_DIR / result / output.png。这是最不容易出错的做法不受 IDE、命令行、Notebook 三种启动方式影响。从那以后我每次拿到一个毕设源码包第一件事就是把数据读取路径全部改成绝对路径再检查一次 notebook 的 kernel 版本最后才跑 Run All。这个习惯救过我很多次希望帮到你。6. 进阶用法把 predict.ipynb 抽成 train_predict.py 命令行脚本Jupyter Notebook 适合做探索和可视化但答辩演示时评委更可能让你现场跑脚本而不是翻 notebook。把预测模块从 ipynb 抽成可复用脚本算是这份源码最值得做的二次改造。改动量不大却能让你从“运行了别人的 notebook”升级成“写了一个可复用的预测模块”。核心思路是把特征工程、训练、评估三段代码抽成函数再用 argparse 接外部参数。import argparse from pathlib import Path import pandas as pd from sklearn.ensemble import RandomForestRegressor from sklearn.linear_model import LinearRegression def parse_args(): p argparse.ArgumentParser() p.add_argument(--db, defaultdouban) p.add_argument(--model, choices[lr, rf], defaultrf) p.add_argument(--log_target, actionstore_true) p.add_argument(--out, defaultresult) return p.parse_args() def main(): args parse_args() # 连接数据库取数做第4章的特征工程 # 按 args.model 选模型按 log_target 决定是否取对数 # 训练完把图表保存到 args.out 目录 if __name__ __main__: main()--model rf表示用随机森林--model lr表示用线性回归--log_target加上就对票房取对数不加以原始值训练。参数默认值直接沿用第 4 章验证过的配置不需要每次敲全。跑一次预测只需要一行命令python src/train_predict.py --model rf --log_target --out result脚本输出会同时生成一张真实值与预测值的散点图以及一张特征重要性图正好对应原项目里的预测1.png 和预测2.png。参数表可以写进 README答辩时打开终端敲一遍比翻 notebook 的 cell 有说服力得多。本文还有配套的精品资源点击获取