Netflix数据揭秘:谁是各流派评分之王?🎬
大家好!最近我完成了一个有趣的数据分析实战项目——整理Netflix电影和电视剧的演员评分数据,最终挖掘出各个流派中平均IMDB评分最高的演员。今天我就严格按照项目笔记的流程,把完整的数据清洗、整理、分析过程分享给大家,希望能给同样对数据感兴趣的小伙伴一些启发!
📌 分析目标
此数据分析的目的是,整理不同流派影视作品(比如喜剧片、动作片、科幻片)中,各演员出演作品的平均IMDB评分,从而挖掘出各个流派中的高评分作品演员。本实战项目的目的在于练习整理数据,从而得到可供下一步分析的数据。
📁 数据集简介
原始数据集记录了截止至2022年7月美国地区可观看的所有Netflix电视剧及电影数据。数据集包含两个数据表:titles.csv和credits.csv。
titles.csv 包含电影及电视剧相关信息,每列含义如下:
type:作品类型(电视节目SHOW或电影MOVIE)production_countries:出品国家列表(字符串形式的列表)
credits.csv 包含演职员信息,每列含义如下:
role:演职员类型(ACTOR演员或DIRECTOR导演)
📥 读取数据
首先导入数据分析所需的库——Pandas,并通过read_csv函数将两个原始数据文件读入DataFrame。
import pandas as pdoriginal_titles = pd.read_csv("titles.csv")original_credits = pd.read_csv("credits.csv")
查看前几行数据,确认读取成功:
original_titles.head()
| | | | | | | | | | | | | | |
|---|
| Five Came Back: The Reference... | | This collection includes 12 World War II-era p... | | | | | | | | | | | |
| | | A mentally unstable Vietnam War veteran works ... | | | | | | | | | | | |
| | | Intent on seeing the Cahulawassee River before... | | | | ['drama', 'action', 'thriller', 'european'] | | | | | | | |
| Monty Python and the Holy Grail | | King Arthur, accompanied by his squire, recrui... | | | | ['fantasy', 'action', 'comedy'] | | | | | | | |
| | | 12 American military prisoners in World War II... | | | | | | | | | | | |
original_credits.head()
🧹 评估和清理数据
为了区分原始数据和清洗后的数据,我们先创建两个副本:
cleaned_titles = original_titles.copy()cleaned_credits = original_credits.copy()
📐 数据整齐度
从cleaned_titles的前10行可以看出,genres和production_countries列中包含多个值(以列表形式存储),但实际上它们是字符串,需要拆分成多行。
查看genres列的第一个值:
cleaned_titles['genres'][1]
输出:"['drama', 'crime']"(字符串)
使用eval函数将字符串转换为真正的列表:
cleaned_titles['genres'] = cleaned_titles['genres'].apply(lambda s: eval(s))cleaned_titles['genres'][1]
输出:['drama', 'crime'](列表)
然后用explode将列表拆成多行:
cleaned_titles = cleaned_titles.explode("genres")cleaned_titles.head(10)
(此处显示拆分行后的结果,原本一行变成多行)
同样的操作也应用于production_countries列:
cleaned_titles['production_countries'] = cleaned_titles['production_countries'].apply(lambda s: eval(s))cleaned_titles = cleaned_titles.explode('production_countries')
查看cleaned_credits的前10行,结构已经很整齐,无需进一步拆分。
🧼 数据干净度
通过info()了解数据的基本情况:
cleaned_titles.info()
输出显示共有17818条记录,多个列存在缺失值,如title(缺失1条)、description(缺失28条)、age_certification(缺失较多)、genres(缺失63条)、production_countries(缺失379条)、seasons(缺失很多)、imdb_score(缺失842条)等。
另外,release_year是整数,应该转换为日期类型:
cleaned_titles["release_year"] = pd.to_datetime(cleaned_titles["release_year"], format='%Y')
对于cleaned_credits:
cleaned_credits.info()
输出显示有77801条记录,character列存在缺失值(约9772条缺失),person_id是整数,应转为字符串:
cleaned_credits["person_id"] = cleaned_credits["person_id"].astype("str")
处理缺失数据
分析所需的核心数据是imdb_score和genres,缺失这些值会影响分析,因此需要删除。
查看imdb_score缺失的观察值:
cleaned_titles.query("imdb_score.isnull()")
共有842行缺失,删除它们:
cleaned_titles = cleaned_titles.dropna(subset=["imdb_score"])cleaned_titles["imdb_score"].isnull().sum() # 输出0
查看genres缺失的观察值:
cleaned_titles.query("genres.isnull()")
共有6行缺失,删除:
cleaned_titles = cleaned_titles.dropna(subset=["genres"])cleaned_titles["genres"].isnull().sum() # 输出0
cleaned_credits中character缺失不影响分析,保留。
处理重复数据
检查两个DataFrame是否有完全重复的行:
cleaned_titles.duplicated().sum() # 输出0cleaned_credits.duplicated().sum() # 输出0
均无重复。
处理不一致数据
查看genres列的值分布:
cleaned_titles['genres'].value_counts()
输出显示所有流派名称都是统一的,没有不一致。但存在空字符串,需要删除:
cleaned_titles = cleaned_titles.query('genres != ""')cleaned_titles.query('genres == ""') # 空DataFrame
查看production_countries列的值分布:
cleaned_titles['production_countries'].value_counts()
由于国家代码较多,可以临时设置显示所有行:
with pd.option_context('display.max_rows', None): print(cleaned_titles['production_countries'].value_counts())
发现有一个值'Lebanon',而标准国家代码应为'LB',属于不一致。将其统一替换为'LB':
cleaned_titles["production_countries"] = cleaned_titles["production_countries"].replace({"Lebanon": "LB"})
再次检查确认'Lebanon'已不存在。
查看original_credits中role列的值分布:
original_credits['role'].value_counts()
只有ACTOR和DIRECTOR两种,没有不一致。为了方便,将其转换为category类型:
cleaned_credits["role"] = cleaned_credits["role"].astype("category")
处理无效或错误数据
使用describe()查看数值列的统计信息,确保没有超出合理范围的数值:
original_titles.describe()
从输出看,runtime最小为0(可能有问题,但暂不处理),imdb_score范围1.5~9.6,imdb_votes范围5~229万,都在合理范围内。
🔗 整理数据
现在数据已经清洗完毕,我们需要将titles和credits合并,以便同时获取影视作品信息和演员信息。
合并两个DataFrame
通过id(影视作品ID)进行内连接:
credits_with_titles = pd.merge(cleaned_credits, cleaned_titles, on="id", how="inner")
合并后,我们就能知道每个演职员参与过的影视作品的具体信息。
筛选演员
由于我们只关心演员,不关心导演,所以筛选role == "ACTOR":
actor_with_titles = credits_with_titles.query('role == "ACTOR"')
分组计算平均IMDB评分
我们需要按流派和演员分组,计算每个演员在每个流派下的平均评分。注意,分组时使用person_id而不是name,因为名字可能有重复或拼写错误。
groupby_genres_and_person_id = actor_with_titles.groupby(["genres", "person_id"])
提取imdb_score并计算均值:
imdb_score_groupby_genres_and_person_id = groupby_genres_and_person_id["imdb_score"].mean()
结果是一个多层索引的Series,可以重置索引变成规整的DataFrame:
imdb_score_groupby_genres_and_person_id_df = imdb_score_groupby_genres_and_person_id.reset_index()
此时我们得到了每个演员在每个流派下的平均IMDB评分。
🏆 挖掘各流派评分之王
为了找出每个流派中平均评分最高的演员,我们需要再次按流派分组,求出最高分:
genres_max_scores = imdb_score_groupby_genres_and_person_id_df.groupby("genres")["imdb_score"].max()
输出各流派的最高平均分:
genresaction 9.3animation 9.3comedy 9.2crime 9.5documentation 9.1drama 9.5european 8.9family 9.3fantasy 9.3history 9.1horror 9.0music 8.8reality 8.9romance 9.2scifi 9.3sport 9.1thriller 9.5war 8.8western 8.9Name: imdb_score, dtype: float64
接下来,将最高分与原始分组表合并,得到每个流派最高分对应的演员ID:
genres_max_score_with_person_id = pd.merge(imdb_score_groupby_genres_and_person_id_df, genres_max_scores, on=["genres", "imdb_score"])
结果可能有多行,因为一个流派可能有多个演员并列最高分。
为了得到演员名字,我们需要从cleaned_credits中提取唯一的person_id和name对应关系:
actor_id_with_names = cleaned_credits[['person_id', 'name']].drop_duplicates()
然后合并:
genres_max_score_with_actor_name = pd.merge(genres_max_score_with_person_id, actor_id_with_names, on="person_id")
最后,按流派排序,并重置索引,让结果更清晰:
genres_max_score_with_actor_name = genres_max_score_with_actor_name.sort_values("genres").reset_index().drop("index", axis=1)
🎉 最终成果:各流派高分演员榜
以下是整理后的最终结果(共136行,展示部分):
有趣发现:
- 动作片最高分9.3由多位配音演员获得,他们很可能参与了一些高分动画电影。
- 犯罪片和剧情片的最高分9.5均被罗伯特·德尼罗拿下,不愧是老戏骨!
- 战争片最高分8.8,西部片最高分8.9,还有提升空间。
📥 资源获取
在公众号后台回复关键词 「Netflix演员电影评分」,即可获取本项目的数据文件(titles.csv 和 credits.csv)以及完整的 Jupyter Notebook 代码文件,方便你动手实践!
💡 总结与反思
通过这个项目,我们完整地实践了数据清洗、整合、分组聚合的全流程,最终得到了每个流派中平均IMDB评分最高的演员名单。当然,本次分析还可以进一步深化:
- 样本量过滤:有些演员可能只出演了一两部作品,平均分可能受极端值影响,后续可以加入“至少出演n部”的条件。
- 结合其他因素:可以结合投票数、年份等进一步分析,比如近十年活跃演员的评分趋势。
- 可视化:可以用图表展示各流派最高分分布,或演员评分对比。
希望这篇详细的笔记能帮助到正在学习数据分析的你!如果你有任何问题或想法,欢迎留言交流! 🚀
本文使用的数据集来源于Netflix公开数据,仅用于学习交流。