多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

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

电影票房数据可视化与预测:从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/放原始 CSVcode/放数据清洗、可视化、建模的脚本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, encodingutf-8-sig) print(数据规模:, df.shape) print(字段类型:\n, df.dtypes) print(数值字段分布:\n, df.describe(includeall).T)这段代码用于加载原始数据并快速查看整体情况。encodingutf-8-sig是关键它能自动去掉 UTF-8 的 BOM 头避免列名首字出现\ufeff这种隐形字符。如果读出来还是乱码改成gbk或gb18030再试。df.describe(includeall).T会输出每一列的非空计数、唯一值个数、均值、分位数字段缺失到什么程度一眼就看出来了。2.2 缺失值与异常值处理原始票房数据的缺失和异常通常集中在三个地方box_office字段混用“亿”“万”“美元”单位budget字段大量为空release_date字段格式不统一。# 统计各字段缺失率 missing_rate df.isnull().mean().sort_values(ascendingFalse) 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], errorscoerce) 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并指定errorscoerce无法解析的日期会变成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_smoothTrue, linestyle_optsopts.LineStyleOpts(width3, color#d14a61), ) .set_global_opts( title_optsopts.TitleOpts(title电影年度票房趋势), tooltip_optsopts.TooltipOpts(triggeraxis), ) ) line.render(charts/year_trend.html)Pyecharts 1.x 和 2.x 的 API 差异很大我建议直接用 2.x因为 2.x 的配置更贴近opts风格图表渲染也稳定。is_smoothTrue会让折线更圆润答辩展示时观感更好。triggeraxis表示鼠标悬停时整条轴的数值一起显示便于对比多个系列这个细节在展示多年份不同类型票房时会用到。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_optsopts.LabelOpts(formatter{b}: {d}%), ) .set_global_opts( title_optsopts.TitleOpts(title电影类型分布, pos_left10%), legend_optsopts.LegendOpts(pos_topbottom), ) ) # 票房前十横向条形图 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_optsopts.LabelOpts(positionright)) .set_global_opts( title_optsopts.TitleOpts(title票房TOP10影片, pos_left55%), yaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(font_size10)), ) ) grid Grid().add(pie, grid_optsopts.GridOpts(pos_left55%)).add(bar, grid_optsopts.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 charsetutf-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(methodpearson) bucket corr[box_office_wan].sort_values(ascendingFalse) 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_size0.2, random_state42 ) 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_size0.2配合random_state42是固定随机种子保证每次运行结果可复现这一点在毕业设计中很重要——导师重跑你的代码结果应该一致。线性回归的优势是可解释性强你和老师解释“评分每高 1 分票房平均高多少万元”时就靠这条回归曲线。代价是它假设特征与票房是线性关系真实场景这个假设常常不成立所以还需要随机森林。4.3 随机森林把非线性关系和交互效应交给树模型随机森林最直接的好处是它不关心特征之间的线性关系能自动捕捉“高预算 暑期档 高评分”这类组合效应。它还能输出特征重要性这和毕业设计题目里的“影响因素分析”完美对应。from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, r2_score rf RandomForestRegressor( n_estimators500, max_depth8, min_samples_leaf2, n_jobs-1, random_state42, ) 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_, indexX.columns).sort_values(ascendingFalse) print(特征重要性:\n, importance)n_estimators500在样本量不大时收益有限但能稳定减少方差max_depth8限制树深度防止过拟合特别是电影数据集通常只有几百上千条树太深很容易把训练集背下来。min_samples_leaf2保证叶子节点覆盖足够多样本。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, alpha0.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, dpi150)plt.rcParams[font.sans-serif]不设置的话图表里中文会显示成方块这在 Matplotlib 里是必踩的坑。散点越贴近红色对角线说明预测越准。我实际跑过的项目中误差最大的样本几乎都是“低成本黑马”或“高成本扑街”这类片子的票房走向本身就难以从常规特征推断——黑马靠口碑发酵扑街片往往是被档期竞争挤压。写论文时把这段当作“模型边界”分析比单纯堆指标更能拿分。5. 避坑与常见问题毕业设计里最容易翻车的 5 个点5.1 中文乱码从 CSV 到图表全链路现象Pandas 读出来列名是乱码Matplotlib 图表标题里全是方块HTML 打开后图表标签空白。原因三处编码问题叠加。CSV 文件可能是 GBK 编码Matplotlib 默认字体不含中文字形Pyecharts 渲染环境缺少中文字体。解决CSV 读取换成encodingutf-8-sig不行就gb18030Matplotlib 加两行plt.rcParamsPyecharts 在代码开头设置os.environ[PYECHARTS_FONT] Microsoft YaHeiWindows或WenQuanYi Zen HeiLinux。这三处都改完乱码基本清零。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 Bar2.x 用from pyecharts.charts import Bar。老项目在新版本环境里的兼容性不好。解决在requirements.txt里锁定版本常见写法是pyecharts2.0.6或pyecharts1.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_namesX.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电影票房分析与预测看板, layoutwide) 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而是把每一类误差都能讲出一个故事。再回到标题本身这套方案值得投入的理由在于它的每一层产出都能直接展示数据清洗表格、可视化图表、相关性分析和回归系数、模型预测对比、最后再封装成一个网页看板。希望帮到你。本文还有配套的精品资源点击获取
返回列表