news 2026/10/23 14:41:26

电影票房数据可视化与预测:从Pandas清洗到随机森林建模全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
电影票房数据可视化与预测:从Pandas清洗到随机森林建模全流程

简介:这是一份面向毕业设计的Python电影数据可视化与票房影响因素分析预测项目源码包,适合计算机相关专业学生完成毕设、课程设计或系统复现数据分析全流程。内含完整可运行的Python脚本、Jupyter Notebook分析文档、数据库脚本及PDF说明文档,覆盖从豆瓣电影数据采集清洗、SQL存储到可视化展示与票房预测建模的完整链路。资源共38个文件,主要包含6个py源码文件、3个ipynb交互式分析笔记、1份README.pdf、1个sql数据库脚本及24张结果图表png,压缩包大小5.17MB,整体结构清晰,便于按模块阅读运行。目前已有335人学习下载。项目经过严格调试可放心运行,不仅能获得可直接改写的毕业设计源码,还能参考其数据可视化思路、票房影响因素分析方法和预测代码,对理解Python数据分析实战非常有帮助。

1. 项目拆解:从压缩包到可运行环境

毕业设计做到电影票房数据可视化与票房预测这个方向,你拿到的项目包通常是一套 Python 源码加一份 PDF 文档。这套方案能解决什么?把电影数据从采集整理、可视化展示到影响因素分析与票房预测串成一条完整链路——先用 Pandas 清洗数据,再用 Pyecharts 生成图表,最后用 Sklearn 建模预测。适合想在一两个月内跑完数据分析全流程的毕业生,也适合刚入门数据科学的从业者当练手项目。很多网传的“免费 python 源码大全”都是散件拼凑,而这个标题的价值在于它围绕一个主题把“数据获取—分析—建模—呈现”闭环了,答辩时拿出来能讲清楚每一张图、每一个系数是怎么来的。

我拿到这类压缩包后,第一件事从来不是急着改代码,而是先把 PDF 文档翻完,确认环境依赖版本、数据字段含义和运行顺序。常见结构是data/放原始 CSV,code/放数据清洗、可视化、建模的脚本,PDF 里写设计思路和运行说明。下面我按自己做过的类似项目,把从解压到出结果的路一步步讲清楚,包括参数怎么调、坑在哪里。

2. 数据准备与清洗:票房数据里的脏活累活

2.1 数据集的字段解析

电影票房数据集的字段通常比想象中多,但真正能用的就那十几个。典型的字段包括movie_title(电影名)、genre(类型)、release_date(上映日期)、box_office(票房,单位混乱的重灾区)、rating(评分)、votes(评分人数)、budget(制作成本)、runtime(片长)、director_avg_rating(导演历史均分)、actor_avg_rating(主演历史均分)等。

import pandas as pd df = pd.read_csv('data/movies.csv', encoding='utf-8-sig') print('数据规模:', df.shape) print('字段类型:\n', df.dtypes) print('数值字段分布:\n', df.describe(include='all').T)

这段代码用于加载原始数据并快速查看整体情况。encoding='utf-8-sig'是关键,它能自动去掉 UTF-8 的 BOM 头,避免列名首字出现\ufeff这种隐形字符。如果读出来还是乱码,改成gbk或gb18030再试。df.describe(include='all').T会输出每一列的非空计数、唯一值个数、均值、分位数,字段缺失到什么程度一眼就看出来了。

2.2 缺失值与异常值处理

原始票房数据的缺失和异常通常集中在三个地方:box_office字段混用“亿”“万”“美元”单位;budget字段大量为空;release_date字段格式不统一。

# 统计各字段缺失率 missing_rate = df.isnull().mean().sort_values(ascending=False) print('缺失率:\n', missing_rate[missing_rate > 0]) # 票房统一转换为“万元” def to_wan(value): if isinstance(value, str): if '亿' in value: return float(value.replace('亿', '')) * 10000 elif '万' in value: return float(value.replace('万', '')) try: return float(value) except: return None df['box_office_wan'] = df['box_office'].apply(to_wan) # 删除票房缺失且无法转换的样本 df = df.dropna(subset=['box_office_wan']) print('清洗后样本量:', len(df))

这段逻辑的核心是按“字符串后缀判断单位再换算”,避免用正则表达式在多种格式之间来回试。票房单位不统一是分析结果失真的第一名,转换后务必做一次随机抽查。等等,还有一个常见的坑是部分票房数据本身传入时就被存成了字符串,例如"3.5亿",如果不做类型清理,后续corr()直接报错。

2.3 上映日期与档期的衍生特征

票房预测的基线模型里,最容易被忽略的是“档期”信息。春节档、暑期档、国庆档的票房基数完全不同,同一部电影放在不同月份上映,预测结果会差出几个量级。这里需要从release_date提出年、月、星期几和是否节假日档期。

df['release_date'] = pd.to_datetime(df['release_date'], errors='coerce') df['release_year'] = df['release_date'].dt.year df['release_month'] = df['release_date'].dt.month df['release_weekday'] = df['release_date'].dt.weekday # 0 为周一 # 档期标记:春节/暑期/国庆 def mark_holiday(month): if month == 2: return 'spring' elif month in (7, 8): return 'summer' elif month in (9, 10): return 'national' return 'normal' df['season'] = df['release_month'].apply(mark_holiday) print(df['season'].value_counts())

日期处理用pd.to_datetime并指定errors='coerce',无法解析的日期会变成NaT而不是中断脚本,这是写数据处理脚本的基本素养。档期字段后续会做get_dummies或者直接编码,在特征重要性排序中,它往往能排进前三。

3. 数据可视化:用 ECharts 把票房故事讲明白

3.1 年度票房趋势与类型分布的可视化

数据可视化在这个项目里承担的角色不只是“出图给导师看”,它还是你理解数据分布的手段。常见做法是用 Pyecharts(底层就是 ECharts)画组合图:折线图展示年度总票房变化,饼图展示电影类型占比,条形图展示票房前十影片。

from pyecharts.charts import Bar, Line from pyecharts import options as opts year_box = df.groupby('release_year')['box_office_wan'].sum().sort_index() line = ( Line() .add_xaxis(year_box.index.tolist()) .add_yaxis( '年度总票房(万元)', year_box.values.tolist(), is_smooth=True, linestyle_opts=opts.LineStyleOpts(width=3, color='#d14a61'), ) .set_global_opts( title_opts=opts.TitleOpts(title='电影年度票房趋势'), tooltip_opts=opts.TooltipOpts(trigger='axis'), ) ) line.render('charts/year_trend.html')

Pyecharts 1.x 和 2.x 的 API 差异很大,我建议直接用 2.x,因为 2.x 的配置更贴近opts风格,图表渲染也稳定。is_smooth=True会让折线更圆润,答辩展示时观感更好。trigger='axis'表示鼠标悬停时整条轴的数值一起显示,便于对比多个系列,这个细节在展示多年份不同类型票房时会用到。

3.2 用 Grid 组合多图,做一个数据看板页

如果只出一张图,答辩评委可能觉得单薄。我一般会用Grid把四张图组合到同一个 HTML 页面,形成一个小型数据看板。这样既能展示图表制作能力,又能让“数据可视化”这个题目落到实处。

from pyecharts.charts import Pie, Bar, Grid from pyecharts.faker import Faker from pyecharts.commons.utils import JsCode # 类型占比饼图 genre_count = df['genre'].value_counts() pie = ( Pie() .add( '类型占比', [list(z) for z in zip(genre_count.index.tolist(), genre_count.values.tolist())], radius=['35%', '60%'], center=['25%', '50%'], label_opts=opts.LabelOpts(formatter='{b}: {d}%'), ) .set_global_opts( title_opts=opts.TitleOpts(title='电影类型分布', pos_left='10%'), legend_opts=opts.LegendOpts(pos_top='bottom'), ) ) # 票房前十横向条形图 top10 = df.nlargest(10, 'box_office_wan') bar = ( Bar() .add_xaxis(top10['movie_title'].tolist()) .add_yaxis('票房(万元)', top10['box_office_wan'].tolist()) .reversal_axis() .set_series_opts(label_opts=opts.LabelOpts(position='right')) .set_global_opts( title_opts=opts.TitleOpts(title='票房TOP10影片', pos_left='55%'), yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=10)), ) ) grid = Grid().add(pie, grid_opts=opts.GridOpts(pos_left='55%')).add(bar, grid_opts=opts.GridOpts()) grid.render('charts/dashboard.html')

注意add的顺序会影响图在Grid里的位置,靠center和pos_left控制。reversal_axis()做横向条形图,电影名特别长时比纵向条形图舒服得多,这个技巧在做“票房前十榜单”时几乎是标配。生成的是纯 HTML 文件,双击就能打开,不需要额外部署。遇到 Pyecharts 版本过低导致图表空白时,先查pyecharts.__version__,再考虑是不是echarts资源加载失败。

3.3 中文乱码与字体渲染的排查顺序

图表乱码这类问题在数据可视化项目里出现频率极高,而且它不是单一原因造成的。按照下面的顺序排查,比瞎试快很多。

先看 CSV 读进来的文字是否正常。pd.read_csv默认编码在处理中文时经常出错,解决方案是优先utf-8-sig,一旦发现乱码立即切换gb18030。再看 HTML 渲染时浏览器是否识别中文字体,Pyecharts 默认配置在 Windows 下没问题,但在部分 Linux 环境需要设置os.environ['PYECHARTS_FONT']指定字体。最后是 Pyecharts 图表内中文标签缺失,这个通常是opts参数里误用了英文逗号或转义问题,打印一下生成 HTML 里<meta charset="utf-8">是否存在即可定位。

4. 票房影响因素分析与预测:从相关性矩阵到随机森林

4.1 相关性矩阵:哪些因素和票房真相关

做影响因素分析,第一步不是直接跑回归,而是计算相关系数矩阵。这一步能快速剔除虚假的强相关性,也能发现意料之外的关联。

features = ['box_office_wan', 'rating', 'votes', 'budget_wan', 'runtime', 'release_year', 'is_holiday', 'actor_avg_rating'] # 编码档期字段 df['is_holiday'] = (df['season'] != 'normal').astype(int) corr = df[features].corr(method='pearson') bucket = corr['box_office_wan'].sort_values(ascending=False) print('与票房的相关性排序:\n', bucket)

相关系数结果可以整理成一张表当作论文素材:

因素与票房的相关系数初步判断
votes0.62强相关,但存在内生性
rating0.45中等正相关
budget_wan0.38制作成本影响显著
actor_avg_rating0.21导演/主演口碑有加成
runtime-0.08与票房关联较弱

votes和票房相关系数最高,但这背后有一个经典的逻辑陷阱:电影票房高才有人去评分,评分人数是结果而不是原因。把它直接当作特征纳入预测模型会引发特征泄漏,这部分在避坑章节展开。特征选择时我一般保留rating而谨慎对待votes,或者干脆只保留评分本身。

4.2 多元线性回归:拿一个容易解释的基准模型

影响因素分析不能停在相关系数上,答辩时老师一定会追问“这个相关性显著吗?控制其他变量后还成立吗?”多元线性回归就是回答这个问题的工具。

import numpy as np from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.preprocessing import StandardScaler X = df[['rating', 'budget_wan', 'runtime', 'actor_avg_rating', 'is_holiday']].copy() y = df['box_office_wan'].copy() # 特征标准化 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) X_train, X_test, y_train, y_test = train_test_split( X_scaled, y, test_size=0.2, random_state=42 ) lr = LinearRegression() lr.fit(X_train, y_train) print('R2:', lr.score(X_test, y_test)) print('系数:', dict(zip(X.columns, np.round(lr.coef_, 4))))

标准化让不同量纲的特征处在大致相同的尺度,回归系数的绝对值大小可以直接反映该特征的相对重要程度。注意test_size=0.2配合random_state=42是固定随机种子,保证每次运行结果可复现,这一点在毕业设计中很重要——导师重跑你的代码,结果应该一致。线性回归的优势是可解释性强,你和老师解释“评分每高 1 分,票房平均高多少万元”时就靠这条回归曲线。代价是它假设特征与票房是线性关系,真实场景这个假设常常不成立,所以还需要随机森林。

4.3 随机森林:把非线性关系和交互效应交给树模型

随机森林最直接的好处是它不关心特征之间的线性关系,能自动捕捉“高预算 + 暑期档 + 高评分”这类组合效应。它还能输出特征重要性,这和毕业设计题目里的“影响因素分析”完美对应。

from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, r2_score rf = RandomForestRegressor( n_estimators=500, max_depth=8, min_samples_leaf=2, n_jobs=-1, random_state=42, ) rf.fit(X_train, y_train) y_pred = rf.predict(X_test) print('R2:', r2_score(y_test, y_pred)) print('MAE:', mean_absolute_error(y_test, y_pred)) importance = pd.Series(rf.feature_importances_, index=X.columns).sort_values(ascending=False) print('特征重要性:\n', importance)

n_estimators=500在样本量不大时收益有限,但能稳定减少方差;max_depth=8限制树深度防止过拟合,特别是电影数据集通常只有几百上千条,树太深很容易把训练集背下来。min_samples_leaf=2保证叶子节点覆盖足够多样本。n_jobs=-1表示使用全部 CPU 核心,如果你的电脑配置一般,把这个参数改成4会更稳妥,否则训练时风扇猛转是常态。特征重要性结果通常会出现rating排第一、is_holiday第二、budget_wan第三的局面,如果votes没有被剔除,它也会靠前,这时候论文里就要多写一段关于“评分人数与票房存在双向因果”的讨论。

4.4 预测效果的评估与解读

模型跑完不是看 R2 超过 0.8 就完事,毕业设计要能解释误差来源。常见做法是把预测结果和真实值做一张散点图,再用np.abs(y_test - y_pred)找出误差最大的十部电影,手动分析这些电影为什么预测不准。

import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False plt.scatter(y_test, y_pred, alpha=0.5) plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--') plt.xlabel('真实票房(万元)') plt.ylabel('预测票房(万元)') plt.title('随机森林预测效果') plt.savefig('charts/rf_predict.png', dpi=150)

plt.rcParams['font.sans-serif']不设置的话,图表里中文会显示成方块,这在 Matplotlib 里是必踩的坑。散点越贴近红色对角线说明预测越准。我实际跑过的项目中,误差最大的样本几乎都是“低成本黑马”或“高成本扑街”,这类片子的票房走向本身就难以从常规特征推断——黑马靠口碑发酵,扑街片往往是被档期竞争挤压。写论文时把这段当作“模型边界”分析,比单纯堆指标更能拿分。

5. 避坑与常见问题:毕业设计里最容易翻车的 5 个点

5.1 中文乱码:从 CSV 到图表全链路

现象:Pandas 读出来列名是乱码,Matplotlib 图表标题里全是方块,HTML 打开后图表标签空白。

原因:三处编码问题叠加。CSV 文件可能是 GBK 编码;Matplotlib 默认字体不含中文字形;Pyecharts 渲染环境缺少中文字体。

解决:CSV 读取换成encoding='utf-8-sig',不行就gb18030;Matplotlib 加两行plt.rcParams;Pyecharts 在代码开头设置os.environ['PYECHARTS_FONT'] = 'Microsoft YaHei'(Windows)或'WenQuanYi Zen Hei'(Linux)。这三处都改完,乱码基本清零。

5.2 特征泄漏:把未来信息塞进了训练集

现象:模型 R2 高达 0.95,但答辩评委一眼看穿“你的特征里有未来变量”。

原因:把votes(评分人数)直接当特征。电影上映后才有人评分,而票房影响评分人数,反过来评分人数也反映票房热度,双向因果导致模型在训练时偷看了未来信息。

解决:预测任务的正确特征是“上映前就能确定的信息”,例如预算、导演/演员历史均分、档期、片长。对votes这类上映后的数据,要么剔除,要么在论文中明确讨论它的来源,绝不放进预测模型。这是评委常问的问题,提前准备这段解释能拉回不少印象分。

5.3 Pyecharts 版本冲突

现象:代码from pyecharts.charts import Bar直接ModuleNotFoundError,或者之前能跑的代码换台机器就报AttributeError。

原因:Pyecharts 1.x 和 2.x 的导入路径完全不同,1.x 用from pyecharts import Bar,2.x 用from pyecharts.charts import Bar。老项目在新版本环境里的兼容性不好。

解决:在requirements.txt里锁定版本,常见写法是pyecharts==2.0.6或pyecharts==1.9.1,不要写“不高于最新版”这类模糊约束。换电脑重跑前,先pip install -r requirements.txt安装锁定版本,而不是随手pip install pyecharts抓最新版。

5.4 票房单位混用导致预测结果偏出一个数量级

现象:预测出的票房数值和真实值差了几十倍,看残差图发现整体曲线被少数几个极端值拉偏。

原因:票房字段混有“万”“亿”以及美元票房,“3.5 亿”和“12000 万”被当成同一个数量级。更隐蔽的是有些数值是美元换算过的,有些没有。

解决:清洗阶段统一单位,并保留一个currency_type字段做标注。用 Pandas 做随机抽检后打印 10 条转换前后的对比,别只看统计量。这类问题一旦进入回归模型,系数会完全失真。

5.5 模型评估只看 R2,忽略预测业务误差

现象:R2 是 0.75,看着还行,但 MAE(平均绝对误差)高达 12000 万元,一部电影预测偏差上亿,这在业务上毫无意义。

原因:R2 衡量的是相对方差解释程度,对极端值敏感,一部爆款电影的误差就能把整体指标拉偏。

解决:同时报告MAE、MAPE(平均绝对百分比误差)和R2。票房预测场景对 MAE 的要求是“单部电影误差越小越好”,不要只看 R2 一条线。实际项目中我会加一句:如果 MAE 超过样本均值的三成,这个模型只能当作分析工具,不适合做实际票房预测。

6. 进阶用法:用 SHAP 解释票房预测的黑匣子,再做成网页版看板

随机森林的特征重要性只能告诉你“评分”重要,却不能告诉你“评分高是抬升票房还是拉低票房”。我建议用 SHAP 做第二次解释,这是毕业设计里区分“会调包”和“懂模型”的常见办法。它能把模型对每一部电影预测的贡献拆解成每个特征的具体数值,答辩时评委问“你的模型凭什么给这部片子预测 3 亿”,你能拿出 SHAP force plot 一五一十讲清楚。

import shap explainer = shap.TreeExplainer(rf) shap_values = explainer.shap_values(X_train) shap.summary_plot(shap_values, X_train, feature_names=X.columns)

TreeExplainer专门针对树模型,计算速度比KernelExplainer快很多。summary_plot输出的 beeswarm 图里,每个点代表一部电影,横向位置表示该特征对这个样本预测值的拉高或拉低程度,颜色深浅表示特征值高低。拿到这张图之后,你在论文里可以明确写:评分对票房有正向拉动作用,但预算的影响并非单调——高预算影片中,评分对票房的边际影响会被放大,这就是交互效应的证据。从这个角度看,SHAP 不只是模型解释工具,它还是影响因素分析的额外一章素材。

用 Streamlit 把以上内容做成页面,导师双击就能打开交互界面。它的部署成本比 Flask 低很多,只要把数据加载、模型加载和pyplot三个组件串起来就行。

import streamlit as st import pandas as pd import pickle st.set_page_config(page_title='电影票房分析与预测看板', layout='wide') df = load_clean_data() st.title('电影票房影响因素分析与预测') tab1, tab2, tab3 = st.tabs(['数据概览', '可视化分析', '票房预测']) with tab2: st.image('charts/rf_predict.png', caption='随机森林预测效果') with tab3: with open('models/rf.pkl', 'rb') as f: rf = pickle.load(f) inputs = st.select_slider('评分', options=[float(i) for i in range(2, 10)]) st.write('预测票房(万元):', rf.predict([[...]]))

这段代码用tabs把数据展示和预测拆开,胜在逻辑清晰和文件少。你只需要在终端运行streamlit run dashboard.py,就会弹出浏览器页面。把 Streamlit 放进项目里,论文工作量看起来会从“做了一个可视化分析”变成“做了一套可视化分析与预测系统”,这在毕业设计评分上很有价值。

最后说一点我做类似题目时的经验:模型不是越复杂越好,评委更关心你能不能解释观众的决策逻辑。我当年演示随机森林时,被问过一句“为什么预测错误集中在喜剧片和恐怖片”,我一开始答不上来,因为没看 SHAP。后来发现喜剧片的票房严重依赖演员阵容,而恐怖片极度依赖档期排片,这两类影片的风险因子不在常规特征里。做这个项目最重要的不是调出 0.9 的 R2,而是把每一类误差都能讲出一个故事。再回到标题本身,这套方案值得投入的理由在于它的每一层产出都能直接展示:数据清洗表格、可视化图表、相关性分析和回归系数、模型预测对比、最后再封装成一个网页看板。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 11:56:13

IPv4升级IPv6建设设计方案:双栈过渡、地址规划与排障实战

简介&#xff1a;面向网络架构师、运维人员和企业IT决策者&#xff0c;这份IPv4向IPv6过渡的建设设计方案&#xff0c;系统梳理了IPv4协议在地址空间、扩展性、安全性与移动性等方面的瓶颈&#xff0c;并针对现有网络改造和新建网络两类场景给出清晰的组网路径。方案重点比较了…

作者头像 李华
网站建设 2026/10/22 11:56:13

VC++网络嗅探器源码解析:WinPcap抓包与MFC协议解析实战

简介&#xff1a;网络嗅探器Sniffer源代码包是一套基于VC实现的数据包捕获完整工程&#xff0c;内含可直接编译的解决方案&#xff0c;适合熟悉C并希望深入网络底层编程的开发者。整个资源共21个文件&#xff0c;包括6个头文件、3个C源文件&#xff0c;以及图标、资源脚本、工程…

作者头像 李华
网站建设 2026/10/22 11:56:11

Agent-Reach 实战:CLI 驱动的 AI Agent 框架架构解析与工具开发

1. 从零认识 Agent-Reach&#xff1a;一个 CLI 驱动的 AI Agent 框架到底解决什么问题第一次看到 Agent-Reach 这个名字&#xff0c;很多人会以为它又是一个"套壳聊天机器人"。但真正把代码拉下来跑一遍就会发现&#xff0c;它瞄准的是一个更底层、也更痛的问题&…

作者头像 李华
网站建设 2026/10/23 0:35:56

B站移动端正则表达式屏蔽弹幕:从基础语法到实用规则

不知道你有没有在弹幕里见过这种场面&#xff1a;一部电影刚到高潮&#xff0c;满屏的“前方高能”“注意前方”先把剧情泄了个底朝天&#xff1b;一部综艺刚出热门段子&#xff0c;弹幕区就成了“加群”“关注公众号”“求三连”的广告位&#xff1b;更别提某些引战弹幕&#…

作者头像 李华
网站建设 2026/10/22 11:56:11

基于SpringBoot+MyBatisPlus的毕业季旅游定制平台设计

每年到毕业设计季&#xff0c;我总会被问到一个问题&#xff1a;Java方向到底选个什么题目&#xff0c;既能保证工作量、又能把技术栈讲清楚&#xff0c;还不至于做到一半自己先想放弃&#xff1f;如果你打算走 SpringBoot 这条线&#xff0c;我一直比较推荐「毕业季旅游一站式…

作者头像 李华
网站建设 2026/10/22 13:56:33

UserService六版重构实录:事务、缓存、并发与认证实践

一个UserService&#xff0c;被我从 v1 一路重写到 v6&#xff0c;每次重构都伴随着线上事故或者 code review 上的激烈争论。前两天还有人问我&#xff1a;Service 层不就查个库、存个数据&#xff0c;能翻出什么花&#xff1f;问出这句话的人&#xff0c;大概率没有经历过缓存…

作者头像 李华