尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Python电影数据集探索实战:从清洗到可视化全流程
简介一份基于Python的电影数据分析项目包面向正在完成课程设计、期末大作业或毕设的计算机、人工智能、大数据、数学、电子信息等相关专业学生也适合刚入门数据分析的开发者参考。包内共3个文件一个Python脚本用于完整执行分析流程一个Jupyter Notebook便于分步交互式学习与调试一个HTML文件用于展示分析结果压缩包仅674KB轻量便捷。目前已有134人学习下载。项目围绕电影数据集展开探索性分析涵盖数据加载、清洗、统计与可视化等常见环节代码经过调试可直接运行能帮助理解从原始数据到结论输出的完整思路。对于需要快速搭起一个数据分析demo或套用分析模板的读者是一份具有实操参考价值的素材。1. 拿到一份电影数据集先别急着画图很多人学 Python 数据分析第一件事是去下载网上现成的电影数据集然后照着教程画几张票房直方图、情感分析词云就觉得项目做完了。但真正落到自己的分析任务里——无论是课程作业、简历项目还是公司要你做一份影片排片策略分析——你面对的往往就是一个不明不白的.zip压缩包里面有几张 CSV 或 JSON列名靠猜缺失值靠肉眼日期格式五花八门。探索电影数据集Movie Dataset Exploration本质上不是画图而是把一份原始表格变成你能信任的分析底稿的过程。这篇笔记要解决的就是从解压一个 zip 开始到完成一次有结论、有依据、可复用的电影数据探索分析你需要经过哪几步、参数怎么调、哪些坑我替你踩过了。适合谁看刚学完 pandas 基础但没做过完整项目的新手以及有经验但想看看别人怎么处理脏数据和可视化选型的熟手。我默认你已经装好了 Python 3.8 和 Jupyter后面每一步都给完整代码和说明。2. 数据加载与字段摸底先搞清楚你手里是什么2.1 解压与文件侦察别急着 pd.read_csv一个.zip文件里通常不只有一张表。常见结构是一个主数据文件比如movies.csv加若干附属表credits.csv、keywords.csv、ratings.csv也可能是一个 JSON 嵌套结构。我一般会先建一个干净的工作目录把压缩包解开再用命令行看一眼文件清单和体积。mkdir movie_explore cd movie_explore unzip 基于python数据分析-探索电影数据集.zip -d raw ls -lh raw/逻辑说明把解压后的数据隔离在raw/目录里之后所有清洗结果写进processed/避免反复解压污染原始数据。参数说明unzip的-d指定解压目标目录不加的话会直接摊在当前目录文件一多就很乱。ls -lh的-h让文件体积以人类可读格式显示如果看到 CSV 超过 500MB后面读取时就要考虑chunksize或dtype优化否则内存直接爆掉。接下来不要直接打印 DataFrame 的全部列先用 Python 把字段名单和类型扫一遍。import pandas as pd import zipfile from pathlib import Path # 优先读解压后的文件如果解压失败了再走 zipfile 内存读取 data_dir Path(raw) csv_files list(data_dir.glob(*.csv)) print(找到 CSV 文件, [f.name for f in csv_files]) df pd.read_csv(csv_files[0], nrows100) print(字段总数, len(df.columns)) print(df.dtypes)逻辑说明nrows100表示只读前 100 行做一次快速侦察拿到字段名、数据类型的初步印象避免一上来就把整个大文件载入内存结果发现列名不对、分隔符不对白白浪费时间。参数说明pd.read_csv默认分隔符是逗号如果文件是tsv或分号分隔需要显式指定sepnrows是只读指定行数的参数它是侦察阶段最值钱的参数之一。如果文件是 JSON 格式改用pd.read_json但嵌套 JSON 需要先json.load再pd.json_normalize这一步晚点细说。2.2 数据字典先于数据分析拿到字段后不要急着看统计量先给每个字段建立业务含义假设。这一步叫数据字典Data Dictionary很多人跳过后面全在猜。电影数据集的常见字段有budget制作预算、revenue全球票房、vote_average平均评分、vote_count评分人数、release_date上映日期、genres类型通常是 JSON 字符串、spoken_languages语言JSON。其中genres和spoken_languages这种嵌套字段是最容易翻车的地方因为它们的单元格里存的可能是一段 JSON。# 看一下多行样本手动确认字段内容格式 for col in [genres, spoken_languages]: print(f--- {col} 样例 ---) print(df[col].iloc[0][:200] if isinstance(df[col].iloc[0], str) else df[col].iloc[0])逻辑说明用前 100 行数据里某几条的具体内容判断该字段是纯文本、数字还是 JSON 字符串。这是决定后续用ast.literal_eval还是正则清洗的关键。参数说明df[col].iloc[0]取第一行的值isinstance判断它是不是字符串因为 pandas 会把全数字列读成int64或float64读取类型不对后面做字符串操作就会报AttributeError。这里我建议你直接在 Jupyter 里做完侦察后把字段清单和你的猜测写成字典存成data_dict.yaml后面清洗的时候随时对照。这一步花 10 分钟能省后面两小时。2.3 加载全量数据并区分字段类型侦察阶段确认了列名和格式现在可以正式加载全量数据。此时要做的关键决策是哪些列用默认类型读哪些列必须强制指定dtype。电影数据集里最常见的问题是budget和revenue是数值但可能混入空字符串导致变成objectrelease_date是字符串需要后续转日期类型。df pd.read_csv( csv_files[0], dtype{ budget: float32, revenue: float32, }, parse_dates[release_date], low_memoryFalse, ) print(f全量数据形状{df.shape}) print(df.info())逻辑说明dtype参数直接指定列的数据类型避免 pandas 自动推断时把小数字列读成int64造成内存浪费parse_dates把指定列解析为datetime64后续做年份、月份聚合时才有意义low_memoryFalse让 pandas 一次性读取所有数据完成类型推断而不是分块推断导致某列类型不一致。参数说明float32比默认的float64省一半内存对预算、票房这种精度要求不高的数值足够parse_dates接受列名列表解析失败会抛异常报出具体行。如果release_date里有各种奇怪格式parse_dates会直接报错这时候先不要指定它改为读进来后再手动清洗。提示这一步常见的报错是ValueError: could not convert string to float说明目标列里有脏数据。我的处理方式是在dtype里先不指定该列读进来后用pd.to_numeric(..., errorscoerce)做容错转换这个坑后面避坑章节单独讲。3. 数据清洗把脏数据洗成能用的样子3.1 缺失值全景图别只看 isna().sum()大多数教程会教你df.isna().sum()看缺失值这没错但不够。电影数据集里很多缺失不是 NaN而是 0。预算为 0、票房为 0 的电影和真正缺失的电影要区分对待因为 0 值在计算相关系数时会严重扭曲结果。missing df.isna().sum() zero_count (df 0).sum() summary pd.DataFrame({缺失数: missing, 零值数: zero_count}) summary[缺失率] (summary[缺失数] / len(df)).map(lambda x: f{x:.2%}) print(summary[summary[缺失数] 0])逻辑说明把缺失数和零值数放在同一张表里看能快速判断哪些字段空得异常。比如revenue有 3000 条缺失、2000 条零值那说明数据收集阶段很多小成本电影根本没有票房记录这两个要区分处理。参数说明df 0返回布尔 DataFrame.sum()按列统计零值数量missing / len(df)计算缺失率并用map格式化成百分比字符串。这里没有直接 dropna因为不同字段的缺失处理策略不同——budget缺失可以用中位数填充overview缺失就只能删除该行或标记为无简介。3.2 从 JSON 字符串里拆出多值字段genres字段通常是这样的字符串[{id: 28, name: Action}, {id: 12, name: Adventure}]。要把它转成可分析的格式常见做法是拆成多个二进制列one-hot或者提取第一个类型做主分类。我一般会两者都要一个genre_main做主分类一组genre_*做多标签分析。import ast def parse_genres(genre_str): if isinstance(genre_str, str): try: items ast.literal_eval(genre_str) return [item[name] for item in items if name in item] except (ValueError, SyntaxError): return [] return [] df[genres_list] df[genres].apply(parse_genres) df[genre_main] df[genres_list].apply(lambda x: x[0] if x else Unknown) # 多标签 one-hot from sklearn.preprocessing import MultiLabelBinarizer mlb MultiLabelBinarizer() genre_encoded mlb.fit_transform(df[genres_list]) genre_df pd.DataFrame(genre_encoded, columnsmlb.classes_, indexdf.index) df pd.concat([df, genre_df], axis1) print(genre_df.sum().sort_values(ascendingFalse).head(10))逻辑说明ast.literal_eval安全地把字符串形式的列表解析成 Python 列表比eval安全得多解析失败就返回空列表避免一行脏数据让整个 apply 中断。genre_main是主类型用于后续的箱线图分组。MultiLabelBinarizer把类型列表变成多列 0/1 矩阵这样一部电影可以同时属于 Action 和 Comedy不丢失信息。参数说明ast.literal_eval只解析字面量结构不会执行任意代码这是安全性的关键MultiLabelBinarizer的classes_属性会按字母序生成列名列名顺序不按出现频率后面解释特征时注意别搞混。这一步之后genre_df的列数可能多达 20建议只保留出现次数前 10 的类型否则后面可视化图例挤成一团。3.3 日期字段的标准化与衍生字段电影数据集的release_date往往有2015-06-19和6/19/15这种混搭格式。parse_dates在遇到混合格式时会很痛苦我建议先全部读成字符串再手动统一解析。# 先转字符串再统一解析 df[release_date] df[release_date].astype(str) # 尝试多种格式 date_formats [%Y-%m-%d, %m/%d/%Y, %d/%m/%Y, %Y/%m/%d] parsed pd.to_datetime(df[release_date], formatmixed, errorscoerce) df[release_date_clean] parsed df[release_year] parsed.dt.year df[release_month] parsed.dt.month print(df[release_year].value_counts().sort_index().tail(5))逻辑说明formatmixed是 pandas 2.0 以后支持的参数允许在同一列里尝试多种日期格式解析不了的变成 NaT。之后从干净的日期列提取年份、月份作为衍生字段后续按年聚合票房趋势、按月看档期效应都靠它们。参数说明formatmixed在 pandas 1.x 里不可用需要errorscoerce配合infer_datetime_formatTrueerrorscoerce让解析失败的变成NaT而不是抛异常中断。dt访问器只能用于 datetime64 类型的 Series如果你发现series.dt报错说明这一列还没转成 datetime 类型。清洗完这四步后你的df应该比原始数据多出十几列但这些列都是分析友好的。先不要画图把清洗后的数据存一份副本。# 只保留分析需要的列 keep_cols [id, title, budget, revenue, vote_average, vote_count, release_year, release_month, genre_main] list(mlb.classes_[:10]) df_clean df[keep_cols].copy() df_clean.to_parquet(processed/movies_clean.parquet, indexFalse)逻辑说明把处理后的结果保存为 parquet 格式比 CSV 读取快得多、体积更小后续探索阶段反复读取不需要重新清洗。参数说明to_parquet需要安装pyarrow或fastparquet库如果环境装不了退而求其次用to_csv(xxx.csv, indexFalse)只是读取速度慢一些。indexFalse表示不把 DataFrame 索引写入文件避免下次读回来多一列Unnamed: 0。4. 探索性分析与可视化让数据自己说话4.1 票房与评分的分布特征画图前先算偏度很多教程上来就df[revenue].hist()结果看到一根长尾拖到右边然后说票房分布右偏严重。这没错但你可以更进一步看偏度系数、看分位数、看 top 1% 占了多少票房。这一步能让你的分析从描述走向洞察。import numpy as np rev df_clean[revenue].dropna() rev rev[rev 0] # 排除 0 值 skew rev.skew() top1_pct rev.quantile(0.99) top1_share rev[rev top1_pct].sum() / rev.sum() print(f票房偏度{skew:.2f}) print(fTop 1% 电影贡献了 {top1_share:.1%} 的票房总额) print(f票房中位数{rev.median() / 1e6:.1f} 百万美元) print(f票房均值{rev.mean() / 1e6:.1f} 百万美元)逻辑说明偏度大于 1 说明分布严重右偏均值被少数大片拉高中位数才是典型电影的票房水平。top1_share算出头部电影的市场集中度如果 Top 1% 贡献了超过 20% 的票房那分析时要按分组或对数变换处理直接做线性回归会被这些极端值主导。参数说明quantile(0.99)计算 99 分位值median和mean的差异本身就是分布形态的一种度量。这个逻辑同样适用于budget和vote_count——所有呈现出长尾分布的数值字段后续做相关性分析前都要考虑是否取对数。4.2 年份维度的趋势分析用折线图看档期与大盘变化时间维度是电影分析里信息量最大的切面。按年聚合票房总和、电影产量、平均评分可以看大盘走势按月聚合可以看档期效应。我用一个子图把它们放在一起看。import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[figure.figsize] (12, 6) sns.set_style(whitegrid) # 按年聚合 yearly df_clean.groupby(release_year).agg( 电影数量(id, count), 总票房(revenue, sum), 平均评分(vote_average, mean), ).dropna() # 子图 1产量和总票房 fig, ax1 plt.subplots() ax1.bar(yearly.index, yearly[电影数量], alpha0.3, label电影产量) ax1.set_ylabel(电影产量) ax1.legend(locupper left) ax2 ax1.twinx() ax2.plot(yearly.index, yearly[总票房] / 1e9, colorcrimson, markero, label总票房十亿美元) ax2.set_ylabel(总票房) ax2.legend(locupper right) plt.title(逐年电影产量与总票房对比) plt.show()逻辑说明twinx()创建共享 x 轴的双 y 轴图把产量柱状和总票房折线叠加显示直观看出两者是否同步。如果产量增长但总票房下跌说明单片平均收益在下降这是市场分析里很有价值的结论。参数说明groupby(release_year)后的.agg()里元组形式(id, count)表示对 id 列执行 count 操作新列名叫电影数量dropna()会删掉所有聚合字段为 NaN 的行比如 2030 年还没有完整数据。按月的分析同理直接groupby(release_month)看票房分布你可以发现春节档、暑期档、圣诞档的票房峰值。国内的数据比国外档期更集中这个和发行策略有关。4.3 类型维度箱线图对比不同 genre 的票房表现类型字段现在是干净的 one-hot 列可以用箱线图看每种类型的票房分布差异。但要注意一部电影属于多个类型按类型分组时同一部电影会出现在多个组里箱线图之间不完全独立。# 把长表转出来每行是一个电影-类型对 genre_cols list(mlb.classes_[:10]) melted df_clean.melt( id_vars[title, revenue], value_varsgenre_cols, var_namegenre, value_nameis_in, ) melted melted[melted[is_in] 1] melted[revenue_log] np.log1p(melted[revenue]) plt.figure(figsize(14, 6)) sns.boxplot(datamelted, xgenre, yrevenue_log, paletteSet3) plt.xticks(rotation45) plt.ylabel(票房对数变换) plt.title(不同电影类型的票房分布对比) plt.show()逻辑说明melt把宽表转成长表one-hot 的多列折叠成类型一列然后筛选is_in 1的行这样每个电影-类型组合就是一行。np.log1p对票房做对数变换因为原始票房分布太偏箱线图会变成一条线压在底部对数变换后分布形态才看得出来。参数说明np.log1p(x)等价于log(x1)好处是 x0 时结果为 0不会产生负无穷melt的id_vars是保留不变的列value_vars是要折叠的列折叠后产生variable和value两列这里改名成了genre和is_in。如果跑完这一步你发现 Animation 和 Adventure 的票房中位数明显高过 Drama而 Drama 的数量最多但票房偏低——这就是典型的类型产量与商业回报背离后面可以继续深挖入的原因。4.4 相关性分析发现变量之间的真实关系最后做一次数值字段的相关性分析。但这里有一个关键操作vote_count和vote_average要分开放因为评分人数本身反映的是热度而非质量。corr_cols [budget, revenue, vote_average, vote_count, release_year] # 对预算和票房取对数减少极端值影响 for col in [budget, revenue, vote_count]: df_clean[f{col}_log] np.log1p(df_clean[col]) corr df_clean[[f{c}_log if c in [budget, revenue, vote_count] else c for c in corr_cols]].corr() plt.figure(figsize(8, 6)) sns.heatmap(corr, annotTrue, cmapcoolwarm, fmt.2f, center0) plt.title(数值字段相关性热力图) plt.show()逻辑说明corr()默认计算 Pearson 相关系数。难点在于对数变换后字段名变了所以用列表推导式生成新的列名列表。看结果时重点关注预算与票房的相关性通常最强0.6-0.7评分与票房往往是弱相关甚至负相关——这就是口碑不等于商业成功的数据证明。参数说明fmt.2f控制热力图里显示两位小数center0让颜色映射以 0 为中心正值红色负值蓝色。如果你发现budget与revenue相关系数只有 0.3先检查一下预算列是否大量为 00 值太多会把相关系数拉低这是数据质量问题不是真实关系。5. 探索电影数据集的避坑指南五个高频翻车现场这条是探索电影数据集这类项目最容易踩的坑也是这类数据分析项目最耗时间的部分。我按现象 → 原因 → 解决逐条写每一条都是实际发生过、有代表性的。5.1 明明有 1 万行数据画图却只有 3000 个点现象df_clean有 1 万行但sns.scatterplot(xbudget, yrevenue)画出来的图稀稀拉拉点少了很多。原因budget和revenue列里有大量 0 值和缺失值。0 值在散点图上全部堆在左下角原点看起来就像只有一个点NaN 行在绘图时被 seaborn 默默丢弃了。解决先做一次显式过滤让图的样本量、实际统计量你心里有数。plot_df df_clean[ (df_clean[budget] 0) (df_clean[revenue] 0) df_clean[revenue].notna() ] print(f过滤前 {len(df_clean)} 行过滤后 {len(plot_df)} 行) sns.scatterplot(dataplot_df, xbudget_log, yrevenue_log, alpha0.4)逻辑说明这张图里alpha0.4让重叠的点呈现深浅效果否则上万个点叠在一起全是黑色的。过滤条件budget 0排除了预算为零的影片因为预算没记录和预算为零在业务含义上完全不同。5.2 年份列里混进了解析失败的 NaT时间趋势图出现断层现象按年份画折线图时x 轴的年份出现断层2010 年和 2012 年之间断了线但数据里明明有 2011 年的电影。原因release_date解析时用了errorscoerce有些格式没被解析成功变成NaT后被groupby自动忽略但不该被忽略的是某些年份字符串本身是类似2011-00-00这种含有零月零日的脏格式pd.to_datetime会把它们解析失败或解析成 NaN。解决先单独排查日期字段的分布异常。# 检查日期解析失败的样本 bad_dates df[df[release_date_clean].isna()][[title, release_date]] print(f日期解析失败行数{len(bad_dates)}) print(bad_dates.head(20)) # 对类似 2011-00-00 的情况做手动修正 df[release_date_clean] pd.to_datetime( df[release_date].str.replace(-00-, -01-, regexFalse), errorscoerce ) df[release_year] df[release_date_clean].dt.year逻辑说明str.replace(-00-, -01-, regexFalse)把月份为零的日期替换成 1 月因为pd.to_datetime无法解析2011-00-00但对2011-01-30毫无压力。替换后重新解析errorscoerce兜底剩下的真正脏数据。5.3 用 ast.literal_eval 解析 genres 时遇到 None 和 NaN 直接报错现象df[genres].apply(ast.literal_eval)报ValueError: malformed node or string中断了整个清洗流程。原因genres列里不全是 JSON 字符串还有 NaN、None 或以nan字符串形式存储的值。ast.literal_eval只接受合法的字面量字符串遇到 NaN 就炸了。解决在解析函数里加类型判断和异常捕获把解析失败的值统一变成空列表。def safe_parse_genres(val): if pd.isna(val): return [] if isinstance(val, str): try: items ast.literal_eval(val) return [i[name] for i in items if name in i] except (ValueError, SyntaxError): return [] return [] df[genres_list] df[genres].apply(safe_parse_genres) # 处理完后检查还有多少空类型 empty_ratio df[genres_list].apply(len).eq(0).mean() print(f类型为空的比例{empty_ratio:.2%})逻辑说明pd.isna(val)能同时识别 NaN、None、NaT三种形态。异常捕获不能只抓ValueError还要抓SyntaxError因为有些脏数据的 JSON 字符串里混入了多余的花括号会触发语法错误。5.4 预算和票房相关系数只有 0.2和网上别人算的 0.7 对不上现象做了一个 30 分钟的预算与票房相关性分析结果相关系数只有 0.2换一个数据集又变成 0.8心里完全不踏实。原因相关系数对缺失值和离群值极度敏感。如果你的数据里有大量预算为 0 但票房很高的纪录片、或者个别票房 20 亿美元的特效大片这两个极端群体叠加后会严重拉低相关系数。解决清洗时把 0 值和缺失值分离处理并报告不同处理策略下的相关系数对比。# 策略 1不处理直接算 r_raw df_clean[budget].corr(df_clean[revenue]) # 策略 2剔除预算或票房为 0 的行 valid df_clean[(df_clean[budget] 0) (df_clean[revenue] 0)] r_filtered valid[budget].corr(valid[revenue]) # 策略 3对数变换后再算 r_log valid[budget_log].corr(valid[revenue_log]) print(f原始相关系数{r_raw:.3f}) print(f剔零后相关系数{r_filtered:.3f}) print(f对数变换后相关系数{r_log:.3f})逻辑说明把三个结果列出来你就知道哪一个才是预算越大票房越高这个结论的真实强度。剔零后相关系数显著上升说明 0 值确实是数据缺失而非真实结果最后的结论里要说清楚是基于哪种处理策略得出的。5.5 内存占用爆炸跑了 20 分钟还在 groupby现象数据集就 4 万行但groupby(release_year).apply(复杂函数)跑了几分钟没结果Jupyter 内核差点死掉。原因大部分人的第一反应是数据量太大其实是apply里的函数用了循环逐行处理没有向量化或者groupby(release_year)后调用.apply()做拼接操作每一组都要复制一次数据效率极低。解决能用内置聚合函数解决的问题绝不用apply需要逐行计算时用transform或列表推导式。# 慢的做法groupby apply 循环 # df.groupby(release_year).apply(lambda g: g[revenue].mean()) # 快的做法直接用 agg 聚合 yearly_stats df_clean.groupby( release_year, as_indexFalse ).agg( 平均票房(revenue, mean), 票房中位数(revenue, median), 电影数量(id, count), ) # 如果需要同时保留原始行的字段用 transform df_clean[年票房均值] df_clean.groupby(release_year)[revenue].transform(mean)逻辑说明agg走的是 pandas 底层的 C 实现比 Python 层的apply快一个数量级。transform保持原有行数不变把聚合结果广播回每一行不需要merge回原表。提示如果你真的需要一个复杂的自定义函数先用sample(10000)做小样本测试确认函数没有死循环或异常数据后再跑全量。这是我对所有apply操作的习惯性防线。6. 让探索不流于表面做一张票房潜力评分表如果你只停留在画了十张图、总结了五条规律这种探索很容易在面试或答辩时被追问到哑口无言。我通常会在探索的最后一步做一个可落地的产出——把多维度的探索结果压缩成一个计算字段或评分让别人能直接使用。这里给出一个大多数人没做过但很实用的技巧构建一个票房潜力评分Revenue Potential Score把探索阶段发现的规律融合进一个 0-100 的分数。先确定评分维度。基于前面的相关分析预算budget_log与票房相关性最强其次是类型Adventure、Animation 的中位数票房更高再次是上映月份暑期档和圣诞档均值更高。把这个逻辑转成可写代码的打分函数def revenue_score(row): score 0.0 # 维度 1预算对数标准化0-40 分 if row[budget_log] 0: score min(row[budget_log] / 8, 1) * 40 # 维度 2类型加分0-30 分 genre_bonus { Adventure: 30, Animation: 25, Science Fiction: 20, Action: 15, Fantasy: 10, Drama: 5, Comedy: 5 } score genre_bonus.get(row[genre_main], 0) # 维度 3档期加分0-30 分 if row[release_month] in [5, 6, 7, 11, 12]: # 暑期档 圣诞档 score 30 elif row[release_month] in [3, 4, 8, 10]: score 15 else: score 5 return min(score, 100) df_clean[revenue_score] df_clean.apply(revenue_score, axis1)逻辑说明每个维度的分数上限在注释里写得很清楚总分不超过 100。为什么用axis1的apply因为这个函数的逻辑依赖多列联合判断无法用 pandas 的内置聚合替代。虽然之前说避免apply循环但这里只有 4 万行、函数复杂度低耗时在 2 秒以内属于可接受范围。参数说明budget_log / 8做了一个简单归一化预算 8 位数的电影约 1 亿美元log1p后约 18.4能拿满 40 分revenue_score最后min(score, 100)防止三个月都占满的情况超过 100。算完分数后验证一下这个分数是否真的和票房相关用分组对比或回归都行。最简单的方法是看不同分数段的中位票房。df_clean[score_bin] pd.cut(df_clean[revenue_score], bins[0, 30, 50, 70, 100]) result df_clean.groupby(score_bin, observedTrue).agg( 电影数量(id, count), 中位票房(revenue, median), 平均评分(vote_average, mean), ) print(result)逻辑说明pd.cut把分数切成四个段位分组统计后能看到一个明显的单调趋势——如果 70-100 分段的电影明显票高中位票房高于其他段位说明这个评分表的区分度是有效的这个结论比一句预算很重要更有说服力。参数说明pd.cut的bins指定切分边界[0, 30, 50, 70, 100]会把分数分成(0,30]、(30,50]等四个区间observedTrue是 pandas 2.x 里对 Categorical 类型分组时的要求不写会出现可见性警告。到这里一次完整的电影数据集探索分析就闭环了从zip解压到字段侦察从清洗 JSON 嵌套字段到多维可视化从避坑排查到产出一个可复用的 revenue score。我个人的习惯是每次分析结束后把评分规则和清洗流程一起写进项目 README这样下个月回头看时能清楚地知道自己当初为什么把budget0排除了为什么genre_main取的是列表第一个而不是 weight 最高的类型。这个方向如果做成简历项目也建议把 score 的构建思路单独展示——面试官非常喜欢问为什么给 Adverture 30 分而不给 Action 20 分这个问题的回答能体现你对数据分布的理解是画图画不出来的亮点。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

V100 16GB跑通Qwen 27B:推理速度从4.2到63.8 tok/s的优化实录

V100 16GB跑通Qwen 27B:推理速度从4.2到63.8 tok/s的优化实录

几个月前,我从仓库角落翻出一台配着 Tesla V100 16GB 的老服务器时,同事的第一反应是:这卡还能跑 Qwen 27B 大模型?说实话我自己也没底。Qwen 27B 的 FP16 权重就有 54GB,一块 16GB 显存的 V100 连一半都装不进去&…

📅 2026/9/24 20:30:47
5分钟打造你的专属AI助手:Strands Agents零基础入门指南

5分钟打造你的专属AI助手:Strands Agents零基础入门指南

5分钟打造你的专属AI助手:Strands Agents零基础入门指南 【免费下载链接】harness-sdk Build an agent harness and control it end-to-end. Open-source SDK for production AI agents in Python & TypeScript - any model, any cloud. 项目地址: https://gi…

📅 2026/9/24 20:30:47
Strands Agents快速入门:10个实用示例带你玩转AI智能体

Strands Agents快速入门:10个实用示例带你玩转AI智能体

Strands Agents快速入门:10个实用示例带你玩转AI智能体 【免费下载链接】harness-sdk Build an agent harness and control it end-to-end. Open-source SDK for production AI agents in Python & TypeScript - any model, any cloud. 项目地址: https://git…

📅 2026/9/24 20:30:47
MORE NEWS

更多资讯

📰

大模型推理成本暴跌99.7%:技术拆解与低成本部署实战

今年以来,训练侧的光芒逐渐被另一组数字盖过——大模型推理成本在一年内暴跌了约99.7%。这个数字不是我拍脑袋估的,而是从API定价、开源框架吞吐提升和硬件能效变化三者交叉验证得出的行业共识。一年前,调用一次顶级模型的千token价格还能让人…

📰

深度学习艺术风格迁移实战:VGG19与Gram矩阵原理、复现与避坑指南

简介:这是一份面向计算机类毕业设计与课程作业的深度学习艺术风格迁移项目源码包,适合正在学习CNN、损失函数与图像风格迁移的学生参考。项目中用Python或C构建系统,并集成TensorFlow/PyTorch等框架,体现了从数据预处理、模型训练…

📰

基于LangChain与ChatGLM-6B的本地知识库问答系统搭建指南

简介:基于LangChain与ChatGLM-6B等大语言模型构建本地知识库自动问答系统,是面向人工智能开发者与自然语言处理学习者的完整项目实践资源,可解决私有知识检索与智能问答落地问题。资源围绕本地知识库问答场景,涵盖语料切分、向量检…

📰

深入浅出IP协议:从地址规划到静态配置与排障实践

做网络维护的人可能都有这种经历:新设备接进公司网络,第一件事就是问“IP 配了没有”;跨部门联调连不上,先甩过来一句“你 IP 看看是不是写错了”。做了几年网络相关的工作,我最大的体会是,计算机网络里概念…

📰

自由开发者的技术近况:SSE选型、性能优化与排错实战

“想问一下大家现在都在做些什么呢”——这句话我最近在好几个技术社群里都看到过,不是那种寒暄式的随口一问,而是带着一点迷茫、一点好奇、一点想对表的意思。说实话,我自己也经常在深夜盯着屏幕的时候冒出这个念头。做技术这行,…

📰

CC Switch 完全指南:一键切换 Codex 模型服务商与报错排查

如果你最近在用 Codex CLI 这类 AI 编程助手,并且同时接触了两三家大模型服务商的 API,那你大概率已经体会过这种痛苦:换一家供应商,就要去翻配置文件、改 base_url、换 API Key,然后重启终端,运气不好还要…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬