如何通过 Python 分析中国演员现阶段排名
上个月某一天跟朋友聊天,聊到国庆电影,提到《攀登者》上映,预计票房会大好,因为吴京是这部片的主演。然后我就想,目前吴京在国内演员中位列几何呢?正好之前爬了猫眼电影数据,基于python数据分析的方式,分析中国演员排名情况。
数据导入
导入之前爬取到的猫眼数据,由于爬取过程不是本文的主要内容,所以简单描述下数据情况:20110101至20191019年在中国上映,并且有用户评分和票房的影片,总共是2923部。
importpandasaspdfromsklearn.preprocessingimportStandardScalerfromsklearn.clusterimportKMeanspd.set_option('display.max_columns',None)pd.set_option('display.max_rows',None)#加载数据defload_data():#加载电影票房open_filepath='D:\pythondata\\3、猫眼电影\\box_result.csv'movie_box=pd.read_csv(open_filepath)movie_box=movie_box[['电影id','电影名称','首映日期','总票房']].drop_duplicates()#加载电影信息open_filepath='D:\pythondata\\3、猫眼电影\\maoyan_movie.xlsx'movie_message=pd.read_excel(open_filepath,sheet_name='maoyan_movie')movie_message.columns=['电影url','电影名称','电影题材','国家','上映时间','用户评分','电影简介','导演/演员/编剧']movie_message=movie_message[['电影url','电影题材','国家','用户评分','导演/演员/编剧']].copy()movie_message.drop_duplicates(inplace=True)movie_message['电影id']=movie_message.apply(lambdax:x['电影url'].replace('https://maoyan.com/films/',''),axis=1)movie_message[['电影id']]=movie_message[['电影id']].apply(pd.to_numeric)#合并电影信息和票房data=pd.merge(movie_box,movie_message,how='inner',on=['电影id'])returndata
数据处理
由于此次只分析中国演员,所以需要剔除国外影片,并将每部影片的演员列表从字段“导演/演员/编剧”中分割出来。
#只筛选中国的电影data=data[data['国家'].str.contains('中国')]#剔除空值data=data.dropna(subset=["导演/演员/编剧"])#将演员列表从字段“导演/演员/编剧”中分割出来data['演员']=data.apply(lambdax:x['导演/演员/编剧']if'演员'inx['导演/演员/编剧']elseNone,axis=1)data['演员list']=data.apply(lambdax:','.join(x['演员'].split('yyyyy')[1].split('xxxxx')[2:])ifpd.notnull(x['演员'])elseNone,axis=1)#剔除无演员列表的行data=data.dropna(subset=["演员list"])#剔除无用字段data.drop(['导演/演员/编剧'],axis=1,inplace=True)data.drop(['演员'],axis=1,inplace=True)
因为考虑到配音类型的影片是看不到演员本人的,所以需要剔除配音类型影片。再将演员列表从行转置列,使得每行电影名称和演员是一一对应的。由于猫眼电影已经按照演员的出场频率进行排序,所以每部影片取前四名演员,作为影片主演,其中多明星合拍的影片,如《我和我的祖国》就改为取前十名。
#拆分演员列表,并转置成一列data=data.drop("演员list",axis=1).join(data["演员list"].str.split(",",expand=True).stack().reset_index(level=1,drop=True).rename("演员"))#剔除配音演员data=data[~data['演员'].str.contains('配音')]data['演员']=data.apply(lambdax:x['演员'].split('饰:')[0]if'饰:'inx['演员']elsex['演员'],axis=1)#剔除分割演员名称错误的行data=data[~data['演员'].str.contains('uncredited')]data=data[~data['演员'].str.contains('voice')]data=data[~data['演员'].str.contains('Protester')]#取每部电影的前四名演员,部分影片特殊data_actor=data[['电影id','电影名称','演员']].drop_duplicates()data_actor_top4=data_actor[data_actor['电影名称']!='我和我的祖国'].groupby(['电影id','电影名称']).head(4)data_actor_top10=data_actor[data_actor['电影名称']=='我和我的祖国'].groupby(['电影id','电影名称']).head(10)data_actor_top4=pd.concat([data_actor_top4,data_actor_top10])#剔除外国演员data_actor_top4['演员名字长度']=data_actor_top4.apply(lambdax:len(x['演员']),axis=1)data_actor_top4=data_actor_top4[(data_actor_top4['演员名字长度']<=3)].copy()data_actor_top4.drop("演员名字长度",axis=1,inplace=True)#匹配data=pd.merge(data,data_actor_top4,how='inner',on=['电影id','电影名称','演员'])
然后,拆分每部电影的电影题材类型并进行转置,再汇总每个演员出演过的电影题材,排序后取前三个类型,作为演员的拿手题材。
#拆分电影题材data=data.join(data["电影题材"].str.split(",",expand=True).stack().reset_index(level=1,drop=True).rename("题材"))#取每位演员最擅长的电影题材TOP3data_type_actor=data[['电影id','电影名称','演员','题材']].drop_duplicates().groupby(['演员','题材']).agg({'电影id':'count'}).reset_index().sort_values(['演员','电影id'],ascending=False)data_type_actor=data_type_actor.groupby(['演员']).head(3)data_type_actor=data_type_actor.groupby(['演员'])['题材'].apply(list).reset_index()data_type_actor['题材']=data_type_actor['题材'].apply(lambdax:','.join(str(i)foriinlist(set(x))ifstr(i)!='nan'))data_type_actor.rename(columns={'题材':'演员_拿手题材'},inplace=True)data=pd.merge(data,data_type_actor,how='left',on=['演员'])
数据分析
目前只有“演员总票房”和“影片平均评分”两个字段,可用作描述一个演员综合能力,所以需要衍生一些字段:
电影数量:统计演员主演过的影片数量;
大于10亿票房影片数量:汇总单部影片票房大于10亿的数量;
大于10亿票房影片计分:按照不同票房区间赋予分值,再汇总;
由于部分演员只出演过一部影片,属于单样本,若不剔除,会影响各项指标的数值分布。
actor=result[['演员','总票房','用户评分']].drop_duplicates()#衍生字段:平均票房、大于10亿票房影片、大于10亿票房影片计分actor['用户评分']=actor.apply(lambdax:0ifx['用户评分']=='暂无评分'elsex['用户评分'],axis=1)actor['大于10亿票房影片数量']=actor.apply(lambdax:1ifx['总票房']>100000else0,axis=1)#按照票房赋予分值defgoal(x):ifx['总票房']<=100000:division_goal=0elifx['总票房']<=200000:division_goal=1elifx['总票房']<=300000:division_goal=2elifx['总票房']<=400000:division_goal=3elifx['总票房']<=500000:division_goal=4else:division_goal=5returndivision_goalactor['大于10亿票房影片计分']=actor.apply(goal,axis=1)actor['电影数量']=1actor['用户评分']=pd.to_numeric(actor['用户评分'])actor['大于10亿票房影片数量']=pd.to_numeric(actor['大于10亿票房影片数量'])actor['大于10亿票房影片计分']=pd.to_numeric(actor['大于10亿票房影片计分'])#汇总actor2=actor.groupby(['演员']).agg({'总票房':'sum','大于10亿票房影片数量':'sum','大于10亿票房影片计分':'sum','电影数量':'count','用户评分':'mean',}).reset_index()#筛选影片数量大于1的行——只有一部影片的演员设为单样本,会影响标准化的结果actor2=actor2[actor2['电影数量']>1].reset_index(drop=True)
最后,由于数值字段之间的量纲不同,需要进行标准化处理后才可以进行比较。“演员总票房”的高低是衡量一个演员能力的重要因素,这里笔者将“大于10亿票房影片数量”和“大于10亿票房影片计分”也作为两点重要因素,而“影片平均评分”和“电影数量”作为次要因素,最终标准化处理后的计算公式:
总分=演员总票房+大于10亿票房影片数量+大于10亿票房影片计分+0.5*影片平均评分+0.5*电影数量
这里笔者曾用K-means聚类算法将演员划分为四个集群,通过查看集群的分布情况后发现,划分结果与上述公式计算后的总分排名情况十分相似(比如,总分1-20名划分成集群1,21-50名划分成集群2),所以取消了用聚类算法的方式划分演员档次。
#复制一份副本actor_copy=actor2.copy()#标准化处理scaler=StandardScaler()numeric_features=actor2.dtypes[actor2.dtypes!='object'].indexscaler.fit(actor2[numeric_features])scaled=scaler.transform(actor2[numeric_features])fori,colinenumerate(numeric_features):actor2[col]=scaled[:,i]#划分演员档次:权重求和,根据分值排序result=actor2.apply(lambdax:x['总票房']+x['大于10亿票房影片数量']+x['大于10亿票房影片计分']+0.5*x['电影数量']+0.5*x['用户评分'],axis=1)##划分演员档次——方法2:采用聚类算法,自动分成4个组#actor_model=actor2[['总票房','大于10亿票房影片数量','大于10亿票房影片计分','电影数量','用户评分']].values#y_pred=KMeans(n_clusters=4,random_state=9).fit_predict(actor_model)#result2=pd.Series(y_pred)#合并两种结果model_actor_reuslt=pd.concat([actor_copy,result],axis=1)model_actor_reuslt.rename(columns={0:'总分'},inplace=True)model_actor_reuslt=model_actor_reuslt.sort_values('总分',ascending=False).reset_index(drop=True)
数据描述
由于工作上经常使用BI工具tableau进行图表制作,因此下列的图表均用tableau绘制。其实pyecharts生成的图表也十分美观,为了方便这里就不用这个库画图了,有兴趣的小伙伴也可以了解下这个库。
先从整体上对电影的概况进行描述分析,才能更好地理解演员各项指标高低的优劣程度。首先,2011年至今,国内上映的影片总共是2129部,其中10亿票房以上的影片只有39部,占了总体的0.02%。
图电影总数
目前国内影片最高票房已经到50-60亿之间,只有一部。40-50亿只有两部,大部分10亿以上的票房都集中在10-20亿之间。
图电影票房区间
整体上,剧情、喜剧和爱情类型的电影题材拍得最多,而灾难类型的电影最少。从热门和冷门的电影题材中,很好地诠释了“报喜不报忧”这句成语,毕竟每个走进电影院的人都希望能轻松愉快地度过这两个小时。所以10亿以上票房的影片中,喜剧类型的电影题材反而排在了第一位。
图电影题材
从电影上映时间轴中可以看出,整体上,17年之前上映的影片逐年增加,但在17年之后有所下降。而10亿以上票房的影片每年都在增加,侧面说明近几年国内电影影片质量有所上升。
图电影上映时间轴
最后,将全部图表放到同一个仪表板中,可以很方便地看到10亿以上票房的影片分布情况,以及具体的影片名称。其中,2012年的《人在囧途之泰囧》是国内第一部10亿+票房影片,2015年的《捉妖记》是首部20亿+票房影片,2016年的《美人鱼》是首部30亿+票影片,2017年的《战狼2》是首部50亿+票房影片,而2019年的《流浪地球》和《哪吒之魔童降世》是唯一两部40亿+票房影片。从这个时间轴可以看出,自2015年起,每年最高票房都比前年多出10亿以上。
图电影概况
根据上述的计算公式得到总分TOP10的名单,前三名分别是黄渤、吴京和沈腾。这也难怪笔者的同学会对吴京出演的影片信心那么高。
图演员总分排名
汇总每个演员主演的电影票房后,得到总票房TOP10的名单,目前国内百亿票房均是男演员,分别是吴京、黄渤、杜江和沈腾。其中吴京已经是150亿票房冠军,而让笔者比较意想不到的是杜江也上了百亿榜,虽然他参演的几部热门影片,如《红海行动》、《我和我的祖国》和《中国机长》都不是第一主演,但这几部都是10亿+票房影片,是不是能说明他存在某些旺票房特质呢?
图演员总票房
再来看看演员电影数量TOP10的分布情况,可以看到前几名都是香港演员,其中古天乐在7年内主演了36部影片,位列榜首。除了影片数量位列榜首外,其实平平无奇的古仔已经默默地捐赠了100多所学校,这也许就是他当上电影“劳模”的原因吧。
图演员电影数量
最后,将上述三张图表和详细列表放到同个仪表板中,就可以清楚地知道,能够位列前茅的演员都是主演过多部影片,并且拥有多部10亿+票房影片。其中有一个比较有趣的地方是王宝强的影片平均评分是6.3,但他仍然能够排到第七名,原因是他主演过几部评分在5分以下的影片,才导致他平均评分会这么低。
结语
本文旨在让大家了解一下国内电影的整体概况和演员概况,所以只是简单地对数据进行描述性分析,并没有运用到机器学习这方面的知识。一般地,描述性分析是做数据分析必不可少的一步,通过简单的几个图表就能直观地对数据有整体上的认知。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。