☰
Python电影数据分析与可视化毕业设计:从数据清洗到图表落地
2026/10/3 7:49:32 网站建设 项目流程

简介:这份资源是面向计算机相关专业学生与项目实战学习者的Python电影数据分析及可视化毕业设计完整资料包,经导师指导并认可,可直接用于毕业设计、课程设计或期末大作业。包内共39个文件,涵盖Python源码、前端页面与样式脚本、数据库文件、答辩PPT及说明文档等,压缩包约20.87MB,目录结构清晰,便于按模块查阅与二次开发。项目围绕电影数据的采集、清洗、统计分析与可视化展示展开,包含主程序入口、数据库操作模块、模板页面与静态资源,并附有答辩PPT与相关分析文档,方便理解整体设计思路与实现细节。所有代码均经过严格调试,确保可运行,读者可据此掌握数据分析流程、可视化图表实现与项目部署方法,也能作为答辩与文档撰写的参考。目前已有468人学习下载,适合需要完整项目案例与实战练习的学习者参考使用。

1. 电影数据分析项目到底在做什么:从一份毕业设计压缩包说起

很多同学拿到「基于python电影数据分析及可视化源码+PPT文档资料(毕业设计).zip」这类资源时,第一反应是解压、跑通、截图、交差。但真正答辩时被问一句「你的数据从哪来、清洗规则是什么、为什么用这个图不用那个图」,往往就卡壳了。这个标题背后其实是一条完整的数据分析链路:用 Python 采集或读取电影数据,做清洗与特征提取,再用可视化把票房、评分、类型、年份等维度讲成一个有结论的故事,最后配上 PPT 文档形成可交付的毕业设计。它适合计算机、大数据、信息管理方向的本科生,也适合想用一个小而完整的项目入门 pandas 与 echarts 可视化的自学者。核心不是代码有多长,而是你能不能把「数据 → 结论 → 图表」这条线讲清楚。

2. 数据从哪来、怎么存:电影数据集的获取与结构设计

2.1 三种常见数据来源与选型理由

电影数据不像电商订单那样有现成接口,常见做法有三类。第一类是公开数据集,比如豆瓣 Top250 的公开整理版、Kaggle 上的 TMDB 电影元数据,字段通常包含片名、评分、评价人数、类型、上映年份、导演、主演。优点是结构干净、可直接进 pandas;缺点是字段固定,想加「票房」往往没有。第二类是自己写爬虫抓取,用 requests + BeautifulSoup 或 lxml 解析列表页与详情页,能拿到更贴合选题的字段,但要处理反爬、编码、分页。第三类是手动整理 Excel,适合数据量小、只做可视化展示的场景,缺点是工作量大且不好写进「技术实现」章节。

我一般建议毕业设计用「公开数据集为主 + 少量爬虫补充」的组合:主体数据保证可复现,补充字段体现工作量。选型时先问自己三个问题——答辩时能不能说清数据来源合法性、字段是否支撑你要做的图表、数据量是否在 500 到 5000 条之间(太少图表没意义,太多清洗成本高)。

2.2 用 pandas 读取并统一字段的最小代码

下面这段代码演示读取 CSV、重命名列、统一缺失值标记的完整流程,是后续所有分析的地基。

import pandas as pd import numpy as np # 读取原始数据,注意 encoding 常见为 utf-8 或 gbk df = pd.read_csv("movies_raw.csv", encoding="utf-8") # 统一列名,避免中文列名在后续绘图时出问题 df = df.rename(columns={ "电影名": "title", "评分": "rating", "评价人数": "votes", "类型": "genre", "上映年份": "year", "导演": "director" }) # 评分转数值,无法转换的置为 NaN df["rating"] = pd.to_numeric(df["rating"], errors="coerce") df["votes"] = pd.to_numeric(df["votes"], errors="coerce") df["year"] = pd.to_numeric(df["year"], errors="coerce") # 删除标题为空的行,评分缺失的先保留待后续填充 df = df.dropna(subset=["title"]) print(df.shape) print(df.dtypes)

逻辑说明:rename把中文列名换成英文,是为了后面用 matplotlib 或 pyecharts 时避免字体与编码问题;pd.to_numeric的errors="coerce"参数是关键,它把「暂无评分」「9.0分」这类脏数据统一变成 NaN,而不是直接报错中断。参数上,encoding要根据实际文件调整,Windows 下导出的 CSV 常是 gbk,读出来乱码就换编码重试。dropna(subset=["title"])只删标题缺失的行,因为标题是主键,评分缺失可以后面用中位数填充。

2.3 数据表结构设计与字段含义

把数据落成一张主表最省事,字段设计如下表。这张表既是代码里的 DataFrame 结构,也是 PPT 里「数据说明」页的素材。

字段名类型含义是否可空
titlestring电影名称否
ratingfloat评分(0-10)是
votesint评价人数是
genrestring类型,多值用 / 分隔是
yearint上映年份是
directorstring导演是
countrystring制片国家是

提示:genre 字段如果是「剧情/爱情/喜剧」这种多值,不要急着拆成多列,先保留原样,等做类型分布图时再用str.split展开,这样原始信息不丢。

3. 清洗与特征工程:让评分和票房能真正拿来画图

3.1 缺失值、异常值与重复值的处理顺序

清洗顺序错了,后面全白做。我的习惯是:先去重,再处理异常值,最后填缺失。去重用df.drop_duplicates(subset=["title", "year"]),因为同名电影可能翻拍,标题加年份才是唯一键。异常值重点看评分和年份:评分超出 0 到 10 的直接置 NaN,年份小于 1900 或大于当前年份的也置 NaN。缺失值填充要分字段——评分用同类型电影的中位数填充比全局均值合理,评价人数缺失可以填 0 并单独标记,因为「没人评价」和「评价人数未知」是两回事。

# 去重 df = df.drop_duplicates(subset=["title", "year"]) # 异常值处理 df.loc[(df["rating"] < 0) | (df["rating"] > 10), "rating"] = np.nan df.loc[(df["year"] < 1900) | (df["year"] > 2025), "year"] = np.nan # 按类型分组填充评分中位数 df["rating"] = df.groupby("genre")["rating"].transform( lambda x: x.fillna(x.median()) ) # 若仍有缺失,用全局中位数兜底 df["rating"] = df["rating"].fillna(df["rating"].median()) # 评价人数缺失填 0 df["votes"] = df["votes"].fillna(0).astype(int)

groupby(...).transform是这里最值得讲的参数:它返回与原表等长的序列,不会改变行数,比apply更适合填充场景。lambda x: x.fillna(x.median())对每个类型组单独算中位数,避免用爱情片的评分去填恐怖片的缺失。

3.2 从年份和类型里榨出可分析的维度

原始字段往往不够用,需要派生新列。年份可以派生出「年代」(每十年一档),类型可以拆出「是否剧情片」「是否系列电影」这类布尔特征。评价人数跨度极大,从几十到几百万,直接画图会被极端值压扁,所以做对数变换np.log1p(votes)是常见做法。

# 派生年代列 df["decade"] = (df["year"] // 10 * 10).astype("Int64") # 类型拆分为列表,便于统计 df["genre_list"] = df["genre"].fillna("").str.split("/") # 评价人数对数变换,缓解长尾分布 df["votes_log"] = np.log1p(df["votes"]) # 标记是否为高评分电影 df["is_high_rated"] = df["rating"] >= 8.0

np.log1p等价于log(1+x),专门处理含 0 的数据,比np.log安全。astype("Int64")用大写 I 是为了支持缺失值,普通int64遇到 NaN 会报错。这些派生列在画「各年代电影数量」「评分与评价人数关系」时直接可用。

3.3 用 describe 和分组统计做清洗后的自检

清洗完不能直接画图,先跑一遍统计自检,确认没有离谱的值。

print(df[["rating", "votes", "year"]].describe()) # 按年代统计电影数量和平均评分 decade_stat = df.groupby("decade").agg( count=("title", "count"), avg_rating=("rating", "mean") ).reset_index() print(decade_stat)

describe看 min 和 max 是否在合理区间,groupby().agg()用命名聚合让结果列名清晰。如果某个年代 count 只有个位数,画折线图时那个点会剧烈抖动,答辩时容易被追问,所以要么合并年代,要么在图里标注样本量。

4. 可视化怎么选图:评分、票房、类型三个维度的落地画法

4.1 评分分布与年代趋势:直方图加折线图的组合

评分是连续变量,看分布用直方图,看趋势用折线图。用 matplotlib 画的时候,中文字体要提前设置,否则全是方框,这是新手最常见的翻车点。

import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei"] plt.rcParams["axes.unicode_minus"] = False fig, axes = plt.subplots(1, 2, figsize=(14, 5)) # 左图:评分分布直方图 axes[0].hist(df["rating"].dropna(), bins=20, color="#4C72B0", edgecolor="white") axes[0].set_title("电影评分分布") axes[0].set_xlabel("评分") axes[0].set_ylabel("电影数量") # 右图:各年代平均评分折线图 axes[1].plot(decade_stat["decade"], decade_stat["avg_rating"], marker="o", color="#DD8452") axes[1].set_title("各年代平均评分趋势") axes[1].set_xlabel("年代") axes[1].set_ylabel("平均评分") plt.tight_layout() plt.savefig("rating_analysis.png", dpi=150)

font.sans-serif设为 SimHei 是 Windows 下的常用做法,Mac 可换 Arial Unicode MS,Linux 服务器没有中文字体时要么装字体要么改用英文标签。axes.unicode_minus = False解决负号显示成方块的问题。dpi=150保证导出图片放进 PPT 不糊。tight_layout自动调整子图间距,避免标题和坐标轴重叠。

4.2 类型分布与票房对比:横向条形图更适合长标签

电影类型名称较长,用横向条形图(barh)比竖向柱状图可读性好。先把 genre_list 展开统计频次。

from collections import Counter # 展开所有类型并计数 genre_counter = Counter([g for sublist in df["genre_list"] for g in sublist if g]) genre_df = pd.DataFrame(genre_counter.most_common(10), columns=["genre", "count"]) fig, ax = plt.subplots(figsize=(10, 6)) ax.barh(genre_df["genre"][::-1], genre_df["count"][::-1], color="#55A868") ax.set_xlabel("电影数量") ax.set_title("Top10 电影类型分布") plt.tight_layout() plt.savefig("genre_distribution.png", dpi=150)

Counter做频次统计比手写循环简洁,most_common(10)直接取前 10。[::-1]反转顺序是因为 barh 默认从下往上画,反转后数量最多的类型显示在最上方,符合阅读习惯。如果要做「各类型平均评分」对比,把 count 换成 groupby 后的 mean 即可,图类型不变。

4.3 用 pyecharts 做可交互大屏:适合答辩演示的加分项

静态图放进 PPT 够用,但如果想体现「可视化大屏」这个热词,pyecharts 生成的 HTML 可以交互,答辩时鼠标悬停看数值很加分。下面是一个评分与评价人数散点图的最小示例。

from pyecharts.charts import Scatter from pyecharts import options as opts sample = df.dropna(subset=["rating", "votes_log"]).sample(300, random_state=42) scatter = ( Scatter() .add_xaxis(sample["rating"].round(1).tolist()) .add_yaxis("评价人数(对数)", sample["votes_log"].round(2).tolist()) .set_global_opts( title_opts=opts.TitleOpts(title="评分与评价人数关系"), xaxis_opts=opts.AxisOpts(name="评分"), yaxis_opts=opts.AxisOpts(name="评价人数 log"), ) ) scatter.render("rating_votes_scatter.html")

sample(300)是因为散点太多会糊成一片,随机抽样 300 个点既保留趋势又保证渲染流畅,random_state固定随机种子让每次结果一致,方便复现。render输出 HTML,用浏览器打开即可交互。注意 pyecharts 版本差异较大,导入路径在不同版本可能不同,跑之前先确认已安装的版本。

5. 避坑与排查:毕业设计里最容易翻车的五个地方

5.1 中文乱码:图表全是方框

现象:matplotlib 图上标题和标签显示为一个个方框。原因:默认字体不含中文,且系统未正确指定中文字体。解决:在绘图前设置plt.rcParams["font.sans-serif"] = ["SimHei"],Mac 换成["Arial Unicode MS"],Linux 用fc-list :lang=zh查可用中文字体再填进去。如果换了字体还不行,清理 matplotlib 缓存目录后重试。

5.2 编码报错:UnicodeDecodeError

现象:pd.read_csv直接抛UnicodeDecodeError: 'utf-8' codec can't decode byte。原因:文件实际是 gbk 或 gb18030 编码,常见于 Excel 另存的 CSV。解决:先试encoding="gbk",再试encoding="gb18030",还不行就用chardet检测。最稳的办法是用 Excel 打开后另存为 UTF-8 编码的 CSV。

5.3 评分被当成字符串:排序和计算全乱

现象:df["rating"].mean()报错或结果离谱,排序时「10」排在「9」前面。原因:评分列里混有「暂无评分」等文本,pandas 推断为 object 类型。解决:读取时加dtype={"rating": float}会直接报错暴露问题,更好的是读完后用pd.to_numeric(errors="coerce")转换,再检查 NaN 比例,超过 30% 就要回头查数据源。

5.4 图表数据对不上:清洗前后行数不一致

现象:PPT 里写「共 2000 部电影」,图上加起来只有 1800。原因:去重、异常值置 NaN 后 dropna 又删了一批,但文档没同步更新。解决:每一步清洗后都打印df.shape并记录,最终以清洗后的行数为准写进文档。建议在代码里用注释标出每步删了多少行,答辩被问时能直接答。

5.5 pyecharts 图表空白:HTML 打开没内容

现象:生成的 HTML 用浏览器打开一片空白。原因:多半是数据里含 NaN 或 None,pyecharts 序列化失败;也可能是 CDN 资源加载问题。解决:绘图前对数据做dropna(),数值统一round(2)避免浮点过长。如果是离线环境,把 pyecharts 的 js 依赖改为本地引用,或直接用 matplotlib 出静态图保底。

6. 让这份毕业设计多拿十分的两个进阶技巧

第一个技巧是把「结论」写进图里,而不是只放图。答辩老师看的是你的分析能力,不是绘图能力。比如你发现「90 年代平均评分最高但样本量最少」,就在 PPT 对应页写一句「90 年代高分可能受样本量影响,需谨慎解读」,这一句就能体现你懂统计陷阱。具体做法是在代码里把关键统计量算出来存成变量,导出到文本或直接写进图标题。

top_decade = decade_stat.sort_values("avg_rating", ascending=False).iloc[0] note = f"最高平均评分年代:{int(top_decade['decade'])}s,样本量 {int(top_decade['count'])}" print(note) # 把 note 写进 PPT 的结论页

第二个技巧是给项目加一个「可复现说明」。在压缩包里放一个requirements.txt和一段 README,写明 Python 版本、依赖库版本、运行顺序。很多人答辩被问「换台电脑能跑吗」就慌,其实只要pip install -r requirements.txt能装上,再按data_clean.py → analysis.py → visualize.py顺序跑,就能复现。依赖版本不要写太死,用pandas>=1.5这种范围写法,避免答辩现场装不上。

# requirements.txt 示例 pandas>=1.5 numpy>=1.23 matplotlib>=3.6 pyecharts>=2.0

我自己的血泪经验是:毕业设计最花时间的不是写代码,而是清洗数据和调图表细节,代码可能只占三成时间。所以别等到最后一周才动手,先把数据跑通、把图出一版,再慢慢补 PPT 文档。另外,PPT 里每一张图都要能回答「这张图说明了什么」,答不上来的图就删掉,宁少勿滥。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询