如何高效基于两个pandas DataFrame构建演员-电影关联宽表
高效实现演员-电影宽表的方法
你的嵌套循环方法效率极低是完全可以预见的——800万+演员 × 2000+电影,这意味着要执行超过1600亿次判断,完全不是Python循环能处理的量级。我们可以利用pandas的向量化操作(底层基于C实现)来完成这个任务,速度会提升几个数量级。
核心思路
先把宽格式的影片主演表转成长格式(每一行对应一个演员-影片对),再关联演员姓名,最后重新整理成你需要的宽格式。
具体步骤(附代码)
假设你的两个DataFrame结构如下:
actor_names:包含列nconst(演员ID)、primaryName(演员姓名)movie_cast:包含列tconst(影片ID)、primaryTitle(影片名称),以及7个主演列(比如principalCast1到principalCast7,请替换成你实际的列名)
1. 将影片主演的宽格式转成长格式
用melt函数把7个主演列拆成单独的行,每一行对应一个演员和他参演的影片:
import pandas as pd # 转换长格式,保留影片ID和名称,拆分主演列 melted_cast = movie_cast.melt( id_vars=['tconst', 'primaryTitle'], # 保留影片的标识信息 value_vars=['principalCast1', 'principalCast2', 'principalCast3', 'principalCast4', 'principalCast5', 'principalCast6', 'principalCast7'], # 替换成你实际的7个主演列名 value_name='nconst' # 拆分后的演员ID列名 ).dropna(subset=['nconst']) # 移除没有主演的空行
2. 关联演员姓名表
把长格式的演员-影片对和演员姓名表合并,得到带姓名的完整数据:
# 关联演员姓名,只保留有匹配姓名的演员(如果需要保留所有参演演员,把how改成'left') actor_movie_long = melted_cast.merge( actor_names, on='nconst', how='inner' )
3. 转换为目标宽格式
先按演员分组收集所有参演影片,再把影片列表拆分成多列:
# 按演员姓名和ID分组,收集所有参演影片 actor_movie_groups = actor_movie_long.groupby(['primaryName', 'nconst'])['primaryTitle'].agg(list).reset_index() # 确定最多的参演影片数,生成对应的列名 max_movie_count = actor_movie_groups['primaryTitle'].str.len().max() movie_columns = [f'movie {i+1}' for i in range(max_movie_count)] # 将影片列表拆分成多列,合并到演员信息中 movie_df = actor_movie_groups['primaryTitle'].apply(pd.Series).rename(columns=lambda idx: movie_columns[idx]) actor_movie_wide = pd.concat([actor_movie_groups[['primaryName', 'nconst']], movie_df], axis=1)
额外优化建议
- 如果存在同一演员重复参演同一部影片的情况(虽然概率低),可以在分组时去重:
actor_movie_groups = actor_movie_long.groupby(['primaryName', 'nconst'])['primaryTitle'].agg(lambda x: list(set(x))).reset_index() - 如果你的数据集非常大,可以考虑用
dask.dataframe来处理,它支持并行计算,能进一步提升速度。
内容的提问来源于stack exchange,提问作者DrBrodsky
相关产品推荐
相关产品推荐

