誰纔是天朝最厲害的演員?讓Python來爲你揭曉!

1、項目背景

上個月筆者的一個同窗開了間影視投資公司,出於對創業人員的仰慕和影視投資行業的好奇,我就跟他寒暄了幾句,聊天當中他說起到國慶節有部《攀登者》即將上映,預計票房會大好,由於吳京是這部片的主演。而後我就想,目前吳京在國內演員中位列幾何呢?正好以前爬了貓眼電影數據,基於python數據分析的方式,分析中國演員排名狀況。python

2、數據導入

導入以前爬取到的貓眼數據,因爲爬取過程不是本文的主要內容,因此簡單描述下數據狀況:20110101至20191019年在中國上映,而且有用戶評分和票房的影片,總共是2923部。算法

import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
# 加載數據
def load_data():
    # 加載電影票房
    open_filepath = 'D:\pythondata\\三、貓眼電影\\box_result.csv'
    movie_box = pd.read_csv(open_filepath)
    movie_box = movie_box[['電影id', '電影名稱','首映日期','總票房']].drop_duplicates()
    # 加載電影信息
    open_filepath = 'D:\pythondata\\三、貓眼電影\\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(lambda x: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'])
    return data

 

3、數據處理

因爲這次只分析中國演員,因此須要剔除國外影片,並將每部影片的演員列表從字段「導演/演員/編劇」中分割出來。app

# 只篩選中國的電影
data = data[data['國家'].str.contains('中國')]
# 剔除空值
data = data.dropna(subset=["導演/演員/編劇"])
# 將演員列表從字段「導演/演員/編劇」中分割出來
data['演員'] = data.apply(lambda x:x['導演/演員/編劇'] if '演員' in x['導演/演員/編劇'] else None,axis=1)
data['演員list'] = data.apply(lambda x:  ''.join(x['演員'].split('yyyyy')[1].split('xxxxx')[2:]) if pd.notnull(x['演員']) else None,axis=1)
# 剔除無演員列表的行
data = data.dropna(subset=["演員list"])
# 剔除無用字段
data.drop(['導演/演員/編劇'],axis=1,inplace=True)
data.drop(['演員'],axis=1,inplace=True)

 

由於考慮到配音類型的影片是看不到演員本人的,因此須要剔除配音類型影片。再將演員列表從行轉置列,使得每行電影名稱和演員是一一對應的。因爲貓眼電影已經按照演員的出場頻率進行排序,因此每部影片取前四名演員,做爲影片主演,其中多明星合拍的影片,如《我和個人祖國》就改成取前十名。echarts

# 拆分演員列表,並轉置成一列
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(lambda x: x['演員'].split('飾:')[0] if '飾:' in x['演員'] else x['演員'], 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(lambda x: 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','電影名稱','演員'])

 

而後,拆分每部電影的電影題材類型並進行轉置,再彙總每一個演員出演過的電影題材,排序後取前三個類型,做爲演員的拿手題材。dom

# 拆分電影題材
data = data.join(data["電影題材"].str.split(",",expand = True).stack().reset_index(level = 1,drop = True).rename("題材"))
# 取每位演員最擅長的電影題材TOP3
data_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(lambda x: ','.join(str(i) for i in list(set(x)) if str(i) != 'nan'))
data_type_actor.rename(columns={'題材': '演員_拿手題材'}, inplace=True)
data = pd.merge(data,data_type_actor,how='left',on=['演員'])

 

4、數據分析

目前只有「演員總票房」和「影片平均評分」兩個字段,可用做描述一個演員綜合能力,因此須要衍生一些字段:機器學習

電影數量:統計演員主演過的影片數量;工具

大於10億票房影片數量:彙總單部影片票房大於10億的數量;學習

大於10億票房影片計分:按照不一樣票房區間賦予分值,再彙總;url

因爲部分演員只出演過一部影片,屬於單樣本,若不剔除,會影響各項指標的數值分佈。spa

##Python學習羣 592539176
actor = result[['演員','總票房','用戶評分']].drop_duplicates()
# 衍生字段:平均票房、大於10億票房影片、大於10億票房影片計分
actor['用戶評分'] = actor.apply(lambda x:0 if x['用戶評分']=='暫無評分' else x['用戶評分'],axis=1)
actor['大於10億票房影片數量'] = actor.apply(lambda x:1 if x['總票房']>100000 else 0,axis=1)
# 按照票房賦予分值
def goal(x):
    if x['總票房']<=100000:
        division_goal = 0
    elif x['總票房']<=200000:
        division_goal = 1
    elif x['總票房'] <= 300000:
        division_goal = 2
    elif x['總票房'] <= 400000:
        division_goal = 3
    elif x['總票房'] <= 500000:
        division_goal = 4
    else:
        division_goal = 5
    return division_goal
actor['大於10億票房影片計分'] = actor.apply(goal,axis=1)
actor['電影數量'] = 1
actor['用戶評分'] = 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),因此取消了用聚類算法的方式劃分演員檔次。

#Python學習羣 592539176
#免費領取資料
# 複製一份副本
actor_copy = actor2.copy()
# 標準化處理
scaler = StandardScaler()
numeric_features = actor2.dtypes[actor2.dtypes != 'object'].index
scaler.fit(actor2[numeric_features])
scaled = scaler.transform(actor2[numeric_features])
for i, col in enumerate(numeric_features):
    actor2[col] = scaled[:, i]
# 劃分演員檔次:權重求和,根據分值排序
result = actor2.apply(lambda x: 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)

 

5、數據描述

因爲工做上常用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分如下的影片,才致使他平均評分會這麼低。
演員概況

 

寫在最後

本文旨在讓你們瞭解一下國內電影的總體概況和演員概況,因此只是簡單地對數據進行描述性分析,並無運用到機器學習這方面的知識。通常地,描述性分析是作數據分析必不可少的一步,經過簡單的幾個圖表就能直觀地對數據有總體上的認知。

相關文章
相關標籤/搜索