电影数据集分析实战:从Notebook到可复现脚本的完整指南

发布时间:2026/10/13 0:08:59
电影数据集分析实战:从Notebook到可复现脚本的完整指南
简介这份资源面向计算机、人工智能、大数据、数学及电子信息等相关专业的学生与技术学习者提供一套基于Python的电影数据集分析实践项目可用于课程设计、期末大作业或毕业设计的参考。压缩包共3个文件包含1个py脚本、1个ipynb笔记本和1个html页面整体约674KB分别对应可执行分析代码、交互式探索过程与结果展示便于对照理解数据清洗、统计与可视化的完整流程。目前已有134人学习下载。项目代码经过调试下载后可直接运行读者能借此掌握用Python处理真实电影数据的思路包括字段解析、分组聚合、趋势观察与图表呈现等环节并参考其代码组织方式与排错逻辑快速搭建自己的分析框架适合具备一定Python基础、希望积累数据分析实战经验的学习者使用。1. 电影数据集分析包从 Notebook 到可复现脚本的完整落地很多同学拿到「电影数据集分析」这类资源第一反应是打开 Notebook 从头跑到尾看到图表出来就以为完事了。但真正做课程设计或毕设答辩时老师问一句「你这个评分分布是怎么算的、缺失值怎么处理的」往往就卡住了。这个资源包的核心价值不在于图表多好看而在于它提供了一条从原始 CSV 到可视化结论的完整链路Explore Movie Dataset.ipynb负责交互式探索Explore Movie Dataset.py是等价的脚本版本Explore Movie Dataset.html则是导出后的静态报告方便直接放进论文附录或答辩材料。它适合正在做数据分析课程设计、期末大作业的学生也适合想拿一个真实数据集练手 pandas 和 matplotlib 的入门者。前提是你得愿意读懂每一行代码在干什么而不是只按 ShiftEnter。2. 环境准备与数据加载把依赖和数据路径先理顺2.1 依赖清单与安装方式这个项目用到的库都是数据分析的常规组合不需要额外配置复杂环境。常见做法是建一个独立虚拟环境避免和系统 Python 里的包版本打架。我一般会先确认 Python 版本再一次性装齐。# 创建虚拟环境推荐避免污染全局环境 python -m venv movie_env # 激活虚拟环境 # Windows: movie_env\Scripts\activate # macOS / Linux: source movie_env/bin/activate # 安装核心依赖 pip install pandas numpy matplotlib seaborn jupyter这里几个包的分工要说清楚pandas负责数据读取和清洗numpy处理数值计算matplotlib和seaborn负责画图jupyter用来跑.ipynb文件。版本上没有强制要求但建议 pandas 不低于 1.3否则某些groupby的写法会报 warning。如果你用的是 Anaconda这些库基本都自带了直接跳过安装步骤即可。提示如果pip install速度慢可以换国内镜像源加上-i https://pypi.tuna.tsinghua.edu.cn/simple参数。2.2 数据加载与首次体检拿到数据集后不要急着画图。先做三件事看形状、看类型、看缺失。这三步能帮你避开后面 80% 的翻车。import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns # 读取数据注意编码问题常见的有 utf-8 和 gbk df pd.read_csv(movies.csv, encodingutf-8) # 第一步看数据规模和列名 print(数据形状:, df.shape) print(列名列表:, df.columns.tolist()) # 第二步看每列的数据类型和非空数量 print(df.info()) # 第三步看缺失值分布 missing df.isnull().sum() missing_pct (missing / len(df) * 100).round(2) missing_df pd.DataFrame({缺失数: missing, 缺失占比%: missing_pct}) print(missing_df[missing_df[缺失数] 0].sort_values(缺失数, ascendingFalse))这段代码的逻辑很直白shape告诉你有多少行多少列info()让你看清哪些列是数值型、哪些是字符串型缺失值统计则决定你后面要不要做填充或删除。参数上唯一需要注意的是encoding如果报UnicodeDecodeError换成gbk或latin-1再试。很多新手在这一步就卡住以为是代码问题其实只是编码不对。2.3 字段含义与选型判断电影数据集通常包含这些字段预算budget、票房revenue、评分vote_average、投票数vote_count、类型genres、上映日期release_date、片长runtime等。不同来源的数据集列名可能略有差异但核心字段大同小异。你需要先确认哪些字段适合做数值分析哪些适合做分类统计。比如genres字段往往是一串用竖线或逗号分隔的标签直接拿来 groupby 没有意义得先拆分。release_date是字符串要转成 datetime 才能按年份聚合。这些转换在 Notebook 里都有对应代码但你要理解为什么这么做而不是照抄。3. 数据清洗与特征构造决定分析质量的关键一步3.1 缺失值处理策略电影数据里最常见的缺失集中在预算、票房和片长上。处理方式取决于你的分析目标如果只是看评分分布预算缺失可以不管但如果要做「预算与票房的关系」那就必须处理。# 查看关键字段的缺失情况 key_cols [budget, revenue, runtime, vote_average] print(df[key_cols].describe()) # 策略一删除关键字段缺失的行适合缺失比例低的情况 df_clean df.dropna(subset[budget, revenue]) # 策略二用中位数填充适合缺失比例较高但不想丢数据 df[runtime] df[runtime].fillna(df[runtime].median()) # 策略三标记缺失适合缺失本身有意义的场景 df[budget_missing] df[budget].isnull().astype(int)三种策略没有绝对优劣。dropna简单粗暴但如果缺失比例超过 20%删完可能就没剩多少数据了。中位数填充保守但会引入偏差。标记缺失则适合做后续分析时把「是否缺失」本身作为一个特征。我一般会先看缺失比例低于 5% 就删高于 20% 就考虑标记中间地带用中位数。3.2 类型字段拆分与票房归一化genres字段是典型的「一列多值」需要拆成多行或者做 one-hot 编码。同时预算和票房往往量级很大直接画散点图会挤在一起需要做对数变换。# 拆分 genres 字段把 Action|Adventure|Sci-Fi 拆成单独的行 df_exploded df_clean.copy() df_exploded[genres] df_exploded[genres].str.split(|) df_exploded df_exploded.explode(genres) # 统计每个类型的电影数量 genre_counts df_exploded[genres].value_counts() print(genre_counts.head(10)) # 对预算和票房做对数变换避免极端值影响可视化 df_clean[log_budget] np.log1p(df_clean[budget]) df_clean[log_revenue] np.log1p(df_clean[revenue]) # 计算ROI投资回报率注意除零问题 df_clean[roi] df_clean.apply( lambda row: row[revenue] / row[budget] if row[budget] 0 else np.nan, axis1 )explode是 pandas 0.25 之后才有的方法作用是把列表型的单元格展开成多行。np.log1p等价于log(1x)好处是当 x 为 0 时不会报错。ROI 计算里加了budget 0的判断因为数据里确实存在预算为 0 的记录直接除会得到 inf。这些细节在 Notebook 里可能一笔带过但你自己写的时候不注意就会踩坑。3.3 时间字段解析与年份特征release_date通常是字符串格式需要转成 datetime 才能提取年份和月份。# 转换日期格式errorscoerce 会把无法解析的值变成 NaT df_clean[release_date] pd.to_datetime(df_clean[release_date], errorscoerce) # 提取年份和月份 df_clean[release_year] df_clean[release_date].dt.year df_clean[release_month] df_clean[release_date].dt.month # 按年份统计电影数量 yearly_count df_clean.groupby(release_year).size() print(yearly_count.tail(20))errorscoerce这个参数很关键。如果不用它遇到格式不对的日期会直接抛异常用了之后无法解析的值变成NaT后续可以用dropna处理。年份提取后可以做趋势分析月份提取后可以看上映档期的分布规律这些都是课程设计里容易出彩的点。4. 可视化与结论输出让图表真正说明问题4.1 评分分布与票房关系图可视化的核心原则是一张图只说一件事。不要试图在一张图里塞进所有信息。# 设置中文字体避免中文显示为方块 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False # 图1评分分布直方图 fig, axes plt.subplots(1, 2, figsize(14, 5)) axes[0].hist(df_clean[vote_average].dropna(), bins30, colorsteelblue, edgecolorwhite) axes[0].set_title(电影评分分布) axes[0].set_xlabel(评分) axes[0].set_ylabel(电影数量) # 图2预算与票房散点图对数坐标 axes[1].scatter(df_clean[log_budget], df_clean[log_revenue], alpha0.3, s10, colorcoral) axes[1].set_title(预算与票房关系对数坐标) axes[1].set_xlabel(预算对数) axes[1].set_ylabel(票房对数) plt.tight_layout() plt.savefig(rating_and_revenue.png, dpi150) plt.show()alpha0.3让散点半透明避免重叠区域看不清密度。s10控制点的大小。dpi150保证保存的图片足够清晰放进论文不会糊。中文字体设置是必须的否则标题里的中文全是方框这个坑几乎每个人都踩过。4.2 类型统计与年份趋势# 图3电影类型 Top10 条形图 fig, axes plt.subplots(1, 2, figsize(14, 5)) genre_counts.head(10).plot(kindbarh, axaxes[0], colormediumseagreen) axes[0].set_title(电影类型 Top10) axes[0].set_xlabel(数量) # 图4按年份的电影产量趋势 yearly_count_filtered yearly_count[(yearly_count.index 1980) (yearly_count.index 2023)] axes[1].plot(yearly_count_filtered.index, yearly_count_filtered.values, colortomato, linewidth2) axes[1].set_title(电影产量年度趋势) axes[1].set_xlabel(年份) axes[1].set_ylabel(电影数量) plt.tight_layout() plt.savefig(genre_and_trend.png, dpi150) plt.show()barh是水平条形图适合类型名称较长的情况。年份趋势图里我加了 1980 到 2023 的过滤因为早期数据往往不完整画进去反而干扰判断。这些过滤条件不是固定的你可以根据实际数据分布调整。4.3 从 Notebook 到脚本的迁移要点资源包里同时提供了.ipynb和.py两个版本这不是凑数。Notebook 适合探索阶段可以一段一段跑、随时看中间结果脚本适合最终交付能一键运行、方便集成。迁移时注意几点把display()换成print()把%matplotlib inline去掉把分散的单元格合并成函数。# 脚本版的组织方式把分析逻辑封装成函数 def load_and_clean(path): df pd.read_csv(path, encodingutf-8) df df.dropna(subset[budget, revenue]) df[release_date] pd.to_datetime(df[release_date], errorscoerce) df[release_year] df[release_date].dt.year return df def plot_distributions(df, save_dir.): fig, ax plt.subplots(figsize(8, 5)) ax.hist(df[vote_average].dropna(), bins30) ax.set_title(评分分布) fig.savefig(f{save_dir}/rating_dist.png, dpi150) plt.close(fig) if __name__ __main__: data load_and_clean(movies.csv) plot_distributions(data)这种写法比 Notebook 更适合放进毕设的代码附录里老师一看就知道你有工程意识。plt.close(fig)是防止内存泄漏的习惯写法批量生成图表时尤其重要。5. 避坑与排查那些跑不通时该看的地方5.1 编码报错UnicodeDecodeError现象pd.read_csv()直接抛UnicodeDecodeError: utf-8 codec cant decode byte...。原因CSV 文件不是 UTF-8 编码常见的是 GBK 或 Latin-1尤其在国内平台下载的数据集。解决先试encodinggbk再试encodinglatin-1。如果都不行用chardet库检测import chardet; chardet.detect(open(movies.csv,rb).read())。5.2 中文字体显示为方块现象图表标题和轴标签里的中文全是方框。原因matplotlib 默认字体不支持中文。解决在绘图前设置plt.rcParams[font.sans-serif] [SimHei]Windows或[Arial Unicode MS]macOS。如果系统没有 SimHei换成Microsoft YaHei也行。设置完记得加plt.rcParams[axes.unicode_minus] False否则负号也会显示异常。5.3 除零导致 inf 或 NaN现象计算 ROI 或增长率时出现inf或大量NaN。原因分母为 0 或缺失。解决用apply加条件判断或者用np.wheredf[roi] np.where(df[budget] 0, df[revenue] / df[budget], np.nan)。算完之后用df[roi].replace([np.inf, -np.inf], np.nan)再兜底一次。5.4 explode 之后行数暴涨现象拆分 genres 后数据行数从几千变成几万后续统计全乱了。原因explode会把每个类型拆成独立行一部电影有 3 个类型就变成 3 行。解决这是正常行为但你要清楚后续统计的口径。如果只想统计类型分布用 explode 后的数据没问题如果要算每部电影的平均票房得用 explode 前的数据。两种口径不要混用。5.5 Notebook 能跑但脚本报错现象.ipynb里一切正常换成.py就各种NameError。原因Notebook 的单元格共享全局命名空间变量顺序执行脚本是自上而下执行变量定义顺序错了就会报错。解决把脚本里的函数定义放在调用之前把import统一放在文件开头。用if __name__ __main__:包住主逻辑避免导入时自动执行。6. 进阶技巧把分析结果做成可复用的报告6.1 用 pandas profiling 快速生成数据概览如果你不想手写一堆describe()和缺失值统计可以用ydata-profiling原 pandas-profiling一键生成 HTML 报告。# 安装pip install ydata-profiling from ydata_profiling import ProfileReport profile ProfileReport(df_clean, title电影数据集概览, explorativeTrue) profile.to_file(movie_report.html)这份报告会自动包含每列的分布、缺失、相关性热力图适合放在毕设附录里作为数据说明。缺点是数据量大时生成较慢几万行以内没问题。6.2 把关键结论导出为 Markdown 表格答辩时老师往往没时间看你的 Notebook一份简洁的结论表格比什么都管用。# 汇总关键指标 summary { 指标: [电影总数, 平均评分, 平均片长(分钟), 总票房(亿美元), 评分最高年份], 值: [ len(df_clean), round(df_clean[vote_average].mean(), 2), round(df_clean[runtime].mean(), 1), round(df_clean[revenue].sum() / 1e8, 2), int(df_clean.groupby(release_year)[vote_average].mean().idxmax()) ] } summary_df pd.DataFrame(summary) summary_df.to_markdown(summary.md, indexFalse) print(summary_df.to_string(indexFalse))to_markdown需要tabulate库支持pip install tabulate即可。导出的 Markdown 表格可以直接粘进论文或答辩 PPT。6.3 参数化你的分析脚本最后一个技巧把文件路径、年份范围、Top N 这些变量抽到脚本开头方便换数据集时快速调整。# 配置区换数据集时只改这里 CONFIG { data_path: movies.csv, encoding: utf-8, year_range: (1980, 2023), top_n: 10, output_dir: ./output } # 使用配置 df pd.read_csv(CONFIG[data_path], encodingCONFIG[encoding]) year_mask (df[release_year] CONFIG[year_range][0]) \ (df[release_year] CONFIG[year_range][1]) df_filtered df[year_mask]这个习惯是我做了十几个数据分析项目之后才养成的。早期每次换数据都要在代码里翻半天改路径后来统一抽成配置字典省了大量时间。从那以后我每次拿到新数据集第一件事就是先把配置区写好再往下写分析逻辑。希望这个思路帮到你。本文还有配套的精品资源点击获取