Python影视数据分析可视化实战:从数据清洗到交互看板
发布时间:2026/9/26 14:03:27来源:尧图网络
简介这份资源面向具备Python基础、希望进入影视数据分析与推荐系统领域的学习者与开发者围绕影视行业数据展开从预处理、深度学习建模到可视化呈现的完整实践。项目将FCN全卷积网络创造性地用于影视数据特征提取并采用LSTM模型完成影评情感分类与票房预测同时结合漏斗图、饼图、柱状图直观展示作品流失、类型占比与票房差异配合协同过滤等推荐算法构建电影推荐逻辑。压缩包共273个文件约120.38MB以63个py脚本、38个html页面、36个pyc缓存、33张jpg与14张png图片为主另含csv、xls数据表、bin与pth模型权重、h5与pb模型文件及少量css、js前端资源覆盖数据清洗、模型训练与可视化展示各环节。目前已有564人学习下载适合作为课程设计、毕业项目或影视数据挖掘练手案例帮助读者掌握NumPy、Pandas、Matplotlib、Seaborn与TensorFlow/Keras的协同使用理解从数据获取到推荐落地的完整链路。1. 从零搭建 Python 影视数据分析可视化一份能跑通的实战路径很多人第一次接触 Python影视数据分析可视化是手里攥着一份从公开渠道拿到的影视数据集想看看评分分布、票房走势、类型占比结果卡在第一步——数据脏得没法看或者画出来的图自己都不想看第二眼。这个方向的核心不是炫技而是把「数据清洗 → 指标计算 → 图表呈现」这条链路跑通让数据真正能说话。它适合有 Python 基础语法认知、想用 pandas matplotlib/echarts 做点实际东西的人也适合想搭可视化大屏但不知道从哪下手的开发者。下面这套路径是我自己反复跑过、踩过坑之后沉淀下来的每一步都有可复现的命令和参数说明不玩虚的。2. 数据从哪来、怎么洗影视数据集的获取与预处理2.1 影视数据的三个常见来源与选型理由做影视数据分析第一步永远是找数据。常见做法有三种一是用 Python爬虫 从公开影视页面抓取二是直接下载 Kaggle、和鲸社区等平台整理好的 CSV三是调用公开 API 获取结构化数据。三种方式各有边界爬虫灵活但维护成本高页面结构一变就得改代码现成数据集省事但字段定义往往和你的分析目标对不上API 数据干净但有调用频率限制。我一般会优先选现成 CSV 做第一版分析把链路跑通之后再考虑用爬虫补充字段。原因很简单——先验证分析逻辑再解决数据获取顺序反了容易在爬虫反爬上耗掉全部精力。如果你确实需要爬虫Python爬虫可视化界面 这类工具可以作为调试辅助但核心逻辑还是得自己写。选数据集时重点看四个字段片名、上映年份、评分、票房或观看量。这四个字段能支撑起大部分基础分析场景。如果数据集里还有类型、导演、演员那就能做更细的维度拆解。2.2 用 pandas 做清洗缺失值、异常值、类型转换拿到 CSV 之后别急着画图。先做三件事看形状、看类型、看缺失。下面这段代码是我每次拿到新数据集都会先跑一遍的模板。import pandas as pd import numpy as np # 读取数据注意编码问题中文数据集常用 gbk 或 utf-8-sig df pd.read_csv(movie_data.csv, encodingutf-8-sig) # 1. 看整体形状和字段类型 print(df.shape) print(df.dtypes) # 2. 看缺失值分布 missing df.isnull().sum() print(missing[missing 0]) # 3. 评分字段转数值强制转换无法转换的变成 NaN df[rating] pd.to_numeric(df[rating], errorscoerce) # 4. 票房字段去掉货币符号和逗号再转数值 df[box_office] df[box_office].astype(str).str.replace(r[$,], , regexTrue) df[box_office] pd.to_numeric(df[box_office], errorscoerce) # 5. 删除评分和票房都缺失的行保留至少有一个核心指标的数据 df df.dropna(subset[rating, box_office], howall) # 6. 用中位数填充评分缺失值避免均值被极端值拉偏 df[rating] df[rating].fillna(df[rating].median()) # 7. 年份字段处理提取四位数字 df[year] df[release_date].astype(str).str.extract(r(\d{4})) df[year] pd.to_numeric(df[year], errorscoerce) print(df.shape) print(df[[title, year, rating, box_office]].head())这段代码的逻辑说明errorscoerce是关键参数它让无法转换的值变成 NaN 而不是直接报错这在处理脏数据时非常实用。howall表示只有当评分和票房同时缺失时才删除该行避免误删有效数据。用中位数填充评分而不是均值是因为影视评分常有极端低分均值会被拉低。参数方面encoding要根据实际文件调整中文 CSV 常见的是utf-8-sig和gbk如果报UnicodeDecodeError就换一个试。str.extract里的正则(\d{4})用来抓取年份如果日期格式不统一可能需要更复杂的正则。2.3 数据质量检查清单与常见脏数据形态清洗完之后跑一遍下面这个检查清单能避开后面画图时的很多玄学问题检查项判断方法处理方式评分是否在 0-10 范围df[rating].describe()超出范围的置为 NaN年份是否在合理区间df[year].between(1900, 2025)过滤掉异常年份票房是否有负值df[box_office] 0置为 NaN 或删除片名是否有重复df[title].duplicated().sum()根据业务判断是否去重类型字段是否有多值检查分隔符拆分成多行或做 one-hot脏数据的常见形态包括评分写成「8.5分」带中文单位、票房写成「1.2亿」这种中文数量级、年份混在日期字符串里、类型字段用「/」或「|」分隔多个值。这些都得在清洗阶段处理掉不然后面聚合和画图全是坑。3. 用 pandas 做影视指标聚合评分、票房、类型的多维拆解3.1 按年份和类型做分组聚合数据干净之后就可以做分析了。影视数据分析最核心的三个维度是时间年份、类型genre、评分/票房。下面这段代码演示如何按年份和类型做聚合。# 按年份统计平均评分和总票房 yearly_stats df.groupby(year).agg( avg_rating(rating, mean), total_box(box_office, sum), movie_count(title, count) ).reset_index() # 过滤掉电影数量太少的年份避免小样本导致均值失真 yearly_stats yearly_stats[yearly_stats[movie_count] 5] # 按类型拆分先处理多值字段 df_genre df.copy() df_genre[genre] df_genre[genre].str.split(/) df_genre df_genre.explode(genre) df_genre[genre] df_genre[genre].str.strip() # 按类型统计平均评分 genre_stats df_genre.groupby(genre).agg( avg_rating(rating, mean), movie_count(title, count) ).reset_index() # 只保留电影数量大于 10 的类型 genre_stats genre_stats[genre_stats[movie_count] 10] genre_stats genre_stats.sort_values(avg_rating, ascendingFalse) print(yearly_stats.head(10)) print(genre_stats)逻辑说明explode是把列表列展开成多行的关键方法处理「剧情/动作/科幻」这种多值字段时必须用。agg里用字典映射的方式可以一次性算出多个指标比循环高效得多。过滤movie_count是为了避免「某年只有 1 部电影平均分 9.5」这种误导性结论。参数方面movie_count 5这个阈值可以根据数据量调整数据量大就调高数据量小就调低。genre_stats排序后可以直观看到哪些类型的平均评分最高但要注意样本量样本太少的类型不具备统计意义。3.2 票房与评分的相关性分析很多人关心「评分高的电影是不是票房也高」这个问题可以用 pandas 的corr方法快速验证。# 计算评分和票房的皮尔逊相关系数 valid_df df.dropna(subset[rating, box_office]) correlation valid_df[rating].corr(valid_df[box_office]) print(f评分与票房的相关系数: {correlation:.3f}) # 按评分区间分组看各区间平均票房 valid_df[rating_bin] pd.cut(valid_df[rating], bins[0, 5, 6, 7, 8, 9, 10], labels[0-5, 5-6, 6-7, 7-8, 8-9, 9-10]) rating_box valid_df.groupby(rating_bin, observedTrue)[box_office].mean() print(rating_box)逻辑说明corr默认算皮尔逊相关系数值在 -1 到 1 之间接近 0 说明线性相关性弱。pd.cut用来做分箱把连续评分变成离散区间方便看趋势。observedTrue在新版 pandas 里避免出现空分组。这里有个血泪经验影视评分和票房的相关性通常不高因为票房受宣发、档期、IP 影响太大。如果算出来相关系数只有 0.2 左右不要怀疑代码写错了这就是真实情况。分析结论要基于数据不要预设「好电影一定卖座」。4. 可视化落地matplotlib 与 echarts 的选型与实操4.1 matplotlib 画静态分析图折线、柱状、散点matplotlib 是 Python数据分析与可视化 的基石适合做静态分析图。下面这段代码画出年份趋势折线图和类型评分柱状图。import matplotlib.pyplot as plt import matplotlib # 设置中文字体Windows 用 SimHeiMac 用 Arial Unicode MS matplotlib.rcParams[font.sans-serif] [SimHei] matplotlib.rcParams[axes.unicode_minus] False fig, axes plt.subplots(1, 2, figsize(14, 5)) # 左图年份平均评分折线 axes[0].plot(yearly_stats[year], yearly_stats[avg_rating], markero, linewidth2, color#2c7fb8) axes[0].set_xlabel(年份) axes[0].set_ylabel(平均评分) axes[0].set_title(各年份电影平均评分趋势) axes[0].grid(alpha0.3) # 右图类型平均评分柱状 axes[1].barh(genre_stats[genre], genre_stats[avg_rating], color#7fcdbb) axes[1].set_xlabel(平均评分) axes[1].set_title(各类型电影平均评分) axes[1].invert_yaxis() plt.tight_layout() plt.savefig(movie_analysis.png, dpi150, bbox_inchestight) plt.show()逻辑说明subplots(1, 2)创建一行两列的画布axes[0]和axes[1]分别操作两个子图。barh画水平柱状图配合invert_yaxis让排名第一的类型显示在最上面。bbox_inchestight防止保存时标签被裁掉。参数方面dpi150是保存图片的分辨率用于报告可以调到 300。中文字体设置是必须的不设置的话中文会显示成方块。Windows 用SimHeiMac 用Arial Unicode MSLinux 需要额外安装字体。4.2 用 pyecharts 做交互式可视化大屏如果要做 可视化大屏 或者网页端展示pyecharts 比 matplotlib 更合适它生成的 HTML 可以嵌入网页支持交互。from pyecharts.charts import Bar, Line, Pie, Grid from pyecharts import options as opts # 类型分布饼图 genre_pie ( Pie() .add(, [list(z) for z in zip(genre_stats[genre], genre_stats[movie_count])]) .set_global_opts( title_optsopts.TitleOpts(title各类型电影数量分布), legend_optsopts.LegendOpts(orientvertical, pos_leftleft) ) .set_series_opts(label_optsopts.LabelOpts(formatter{b}: {c})) ) # 年份趋势折线图 year_line ( Line() .add_xaxis(yearly_stats[year].tolist()) .add_yaxis(平均评分, yearly_stats[avg_rating].round(2).tolist()) .set_global_opts( title_optsopts.TitleOpts(title年份评分趋势), xaxis_optsopts.AxisOpts(name年份), yaxis_optsopts.AxisOpts(name评分) ) ) # 组合成大屏布局 grid ( Grid(init_optsopts.InitOpts(width1200px, height500px)) .add(genre_pie, grid_optsopts.GridOpts(pos_left55%)) .add(year_line, grid_optsopts.GridOpts(pos_right55%)) ) grid.render(movie_dashboard.html)逻辑说明pyecharts 采用链式调用add方法添加数据系列set_global_opts设置全局配置。Grid用来做多图布局通过pos_left和pos_right控制位置。render输出 HTML 文件浏览器打开即可看到交互效果。参数方面InitOpts里的width和height控制画布尺寸做大屏时按实际分辨率设置。LabelOpts的formatter支持{b}名称、{c}数值、{d}百分比等占位符。如果数据量大饼图建议只显示 Top 10 类型其余合并为「其他」。4.3 可视化图表选型对照表不同分析目标适合不同的图表类型选错了图数据再准也白搭。分析目标推荐图表不推荐原因年份趋势折线图饼图饼图无法体现时间连续性类型占比饼图/环形图折线图折线图不适合展示部分与整体评分与票房关系散点图柱状图散点图能看出相关性和离群点类型评分对比水平柱状图垂直柱状图类型名较长时水平更易读多维度对比雷达图饼图雷达图能同时展示多个维度选图的核心原则是看趋势用折线看对比用柱状看分布用直方图或箱线图看关系用散点图看占比用饼图。别为了好看选不合适的图。5. 避坑与排查影视数据分析可视化最常见的 5 个翻车现场5.1 中文乱码图表上的方块字现象matplotlib 画出来的图标题和轴标签全是方块。原因默认字体不支持中文系统找不到对应字形。解决在画图前设置matplotlib.rcParams[font.sans-serif] [SimHei]Mac 换成Arial Unicode MS。如果还不行用matplotlib.font_manager查一下系统里有哪些中文字体选一个存在的。5.2 票房字段转数值全是 NaN现象pd.to_numeric之后票房列全是 NaN。原因原始数据里票房带「亿」「万」这种中文单位或者带货币符号和逗号直接转数值会失败。解决先用str.replace去掉非数字字符再处理数量级。比如「1.2亿」要先提取 1.2再乘以 1e8。这一步建议单独写个函数用apply逐行处理。5.3 groupby 之后数据量骤减现象原始数据几万行groupby 之后只剩几十行。原因分组字段里有大量 NaNpandas 默认会把 NaN 分组丢掉。解决加dropnaFalse参数保留 NaN 分组或者先填充分组字段的缺失值。如果是多值字段 explode 之后数据量暴增那是正常现象因为一行变成了多行。5.4 pyecharts 生成的 HTML 打开是空白现象render生成了 HTML 文件浏览器打开一片空白。原因多半是 CDN 资源加载失败pyecharts 默认从网络加载 echarts.js。解决把InitOpts里的js_host指向本地资源或者用pyecharts的离线资源包。内网环境尤其要注意这个问题提前把静态资源下载到本地。5.5 相关系数算出来是 NaN现象corr返回 NaN。原因参与计算的两列里有一列全是 NaN或者两列的方差为 0所有值相同。解决先dropna再算检查两列的数据分布。如果某列所有值都一样相关系数没有意义需要换指标。6. 进阶技巧用 Plotly Dash 搭一个可交互的影视数据看板静态图看久了会腻而且每次换筛选条件都要重新跑代码。用 Plotly Dash 可以搭一个带下拉筛选、联动更新的看板部署到内网就能给团队用。下面是一个最小可运行示例。import dash from dash import dcc, html, Input, Output import plotly.express as px app dash.Dash(__name__) app.layout html.Div([ html.H2(影视数据分析看板), dcc.Dropdown( idgenre-dropdown, options[{label: g, value: g} for g in genre_stats[genre].unique()], valuegenre_stats[genre].iloc[0], clearableFalse ), dcc.Graph(idrating-trend) ]) app.callback( Output(rating-trend, figure), Input(genre-dropdown, value) ) def update_chart(selected_genre): filtered df_genre[df_genre[genre] selected_genre] yearly filtered.groupby(year)[rating].mean().reset_index() yearly yearly[yearly[year] 1990] fig px.line(yearly, xyear, yrating, titlef{selected_genre}类型评分趋势) fig.update_layout(templateplotly_white) return fig if __name__ __main__: app.run(debugTrue, host0.0.0.0, port8050)逻辑说明dcc.Dropdown是下拉筛选组件dcc.Graph是图表容器。app.callback装饰器把下拉框的值和图表更新函数绑定用户每次选择都会触发update_chart重新计算并返回新图。px.line是 Plotly Express 的快捷折线图方法比原生 Plotly 简洁很多。参数方面debugTrue开发时用生产环境关掉。host0.0.0.0让局域网内其他机器也能访问port按需改。templateplotly_white是配色主题还有plotly_dark等可选。这个看板的价值在于把分析逻辑封装成可交互的工具非技术同事也能自己筛选查看。部署时用gunicorn或waitress做生产级服务别直接用app.run。我自己做这类项目最大的教训是别一上来就追求大而全的看板先把数据清洗和核心指标算对再逐步加图表和交互。数据错了图再漂亮也是自欺欺人。另外每次改完清洗逻辑一定要重新跑一遍全流程别只测局部不然中间某个字段类型变了后面全崩。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网