Kaggle——TMDB 5000 Movie Dataset电影数据分析
一、碎碎念
????因為工作上有用到Excel做數據分析,之后慢慢接觸到了Python做分析,做挖掘等。再然后就遇到了Kaggle這個網站,發現這里真是讓人提升技能的圣地。一直在找些可以提升自己數據分析技能、思維的項目來練習,下面主要會展示一些自己的分析思路,可視化圖表,以及代碼。
? ? 我的分析環境是win7 64位 ,anaconda-spyder(Python3.6)
? ? 看了kaggle上這個項目各路大神的代碼思路,然后自己也躍躍欲試要操刀一練。分析完這個項目,給自己的領悟是對于部分的語法,函數,有個進一步的理解,對于分析項目應該怎么一步步的分析也有了更新,在初識這個項目的時候是直接杠正面各種嘗試,各種推理,畢竟一個人閉門造車有時候會造不出車。
? ? 寫這篇文章也算是對這個項目的一個回顧和總結。
? ? 提醒一點,在kaggle上注冊賬號是可以的,但是要通過郵箱激活賬戶的時候需要一個VPN。(我用的163的郵箱)
二、項目背景
本文中用到的數據文件:tmdb_5000_movies.csv、tmdb_5000_credits.csv是Kaggle平臺上的項目TMDB(The Movie Database),共計4803部電影,主要為美國地區一百年間(1916-2017)的電影作品。
本文通過對電影數據的分析,利用數據可視化的方法,發現流行趨勢,找到投資方向,為本行業新入局者提供一定參考建議。同時也為了提升自己的數據分析能力,在遇到類似項目可以觸類旁通。
三、項目概覽
點擊下圖可以直接鏈接到Kaggle對應的項目:
下面是官網內容簡介:
Background
What can we say about the success of a movie before it is released? Are there certain companies (Pixar?) that have found a consistent formula? Given that major films costing over $100 million to produce can still flop, this question is more important than ever to the industry. Film aficionados might have different interests. Can we predict which films will be highly rated, whether or not they are a commercial success?
This is a great place to start digging in to those questions, with data on the plot, cast, crew, budget, and revenues of several thousand films.
We (Kaggle) have removed the original version of this dataset per a?DMCA?takedown request from IMDB. In order to minimize the impact, we're replacing it with a similar set of films and data fields from The Movie Database (TMDb) in accordance with?their terms of use. The bad news is that kernels built on the old dataset will most likely no longer work.
The good news is that:
You can port your existing kernels over with a bit of editing.?This kernel?offers functions and examples for doing so. You can also find?a general introduction to the new format here.
The new dataset contains full credits for both the cast and the crew, rather than just the first three actors.
Actor and actresses are now listed in the order they appear in the credits. It's unclear what ordering the original dataset used; for the movies I spot checked it didn't line up with either the credits order or IMDB's stars order.
The revenues appear to be more current. For example, IMDB's figures for Avatar seem to be from 2010 and understate the film's global revenues by over $2 billion.
Some of the movies that we weren't able to port over (a couple of hundred) were just bad entries. For example,?this IMDB entry?has basically no accurate information at all. It lists Star Wars Episode VII as a documentary.
Several of the new columns contain json. You can save a bit of time by porting the load data functions from this kernel.
Even in simple fields like runtime may not be consistent across versions. For example, previous dataset shows the duration for Avatar's extended cut while TMDB shows the time for the original version.
There's now a separate file containing the full credits for both the cast and crew.
All fields are filled out by users so don't expect them to agree on keywords, genres, ratings, or the like.
Your existing kernels will continue to render normally until they are re-run.
If you are curious about how this dataset was prepared, the code to access TMDb's API is posted?here.
四、前置思路
? ? “運籌帷幄,決勝千里。”古時候老司機的話對我們進行數據分析時依然有用。
? ? 我的習慣看到一個項目,先打開數據文件看看其中的數據是什么樣子的,大概有多少字段,每個字段里的數據是個什么類型。
俗話說得好,讓自己有點B數。
????Kaggle平臺上下載2個原始數據集:tmdb_5000_movies.csv和tmdb_5000_credits.csv,前者存放電影的基本信息,后者存放電影的演職員名單。
????不管怎么樣的數據分析任務都需要遵從一個標準流程,有了流程指導,分析思路和處理過程才不會讓自己進入迷失森林。
????數據分析的流程:1.提出問題2.理解數據3.數據清洗4.建立模型5.數據可視化6.形成數據分析報告
五、提出問題
????如果我是電影行業的數據分析師,一定要讓自己身臨其境站在制作公司的角度出發去思考。(這一點很關鍵)
????現在公司要制作電影,想知道電影預算、評分與票房的關系,各種電影類型隨時間變化的趨勢圖,電影產量、票房的趨勢,哪些風格電影最受歡迎等問題,則可提出如下問題:?
問題1:電影風格隨時間的變化趨勢?
問題2:不同風格電影的收益能力
問題3:比較行業內Universal Pictures與Paramount Pictures兩家巨頭公司的業績
問題4:票房收入與哪些因素最相關
六、理解數據
下面的變量名是數據中出現的,也是2個數據表格中的列名。????
????七、數據清洗
數據清洗主要分三步:1.數據預處理;2.特征提取;3.特征選取。
7.1 數據預處理
在數據預處理時,主要包括:發現和填補缺失值、數據類型轉換、異常值刪除等。數據中release_date列缺失1條數據,runtime列缺失2條數據,均可通過索引的方式找到具體是哪一部電影,然后上網搜索準確的缺失數據,將其填補(詳見后續代碼)。對于release_date列,需將其轉換為日期類型,然后提取出“年份”數據。
7.2 特征提取
在我們處理數據的過程中:通過json.loads先將JSON字符串轉換為字典列表"[{},{},{}]"的形式,再遍歷每個字典,取出鍵(key)為‘name’所對應的值(value),并將這些值(value)用“|”分隔,形成一個“多選題”的結構。在進行具體問題分析的時候,再將“多選題”編碼為虛擬變量,即所有多選題的每一個不重復的選項,拿出來作為新變量,每一條觀測包含該選項則填1,否則填0。
7.3 特征選取
在分析每一個小問題之前,最重要的步驟是需要通過特征選取,構造出適合分析的結構,只有結構“造”對了,后續的可視化才能得出正確的圖形。
這里的小竅門就是:分析每一個小問題時,盡量新建一個數據框,存放要分析的變量,而不是在原始數據框上“亂涂亂畫”,否則最后必定抓狂。
八、數據可視化
本次使用到的圖形類型有:柱狀圖、餅圖、散點圖。
九、代碼部分
????首先我們需要代入一些用到的包,并不是一下子就要導入pandas、numpy、matplotlib等等,包是在寫代碼的時候遇到問題一個個添加的,然后寫到最前面。
9.1理解數據
import numpy as np import pandas as pd import matplotlib.pyplot as plt import matplotlib #%matplotlib inline import json import warnings warnings.filterwarnings('ignore')import seaborn as sns sns.set(color_codes=True)#設置表格用什么字體 font = {'family' : 'SimHei' } matplotlib.rc('font', **font)#導入數據 movies = pd.read_csv('C:\\kaggle_from0\\tmdb_5000_movies\\tmdb_5000_movies.csv') creditss = pd.read_csv('C:\\kaggle_from0\\tmdb_5000_movies\\tmdb_5000_credits.csv')#查看movies中數據 movies.head()#查看movies中所有列名,以字典形式存儲 movies.columns##查看creditss中數據 creditss.head()#查看creditss中所有列名,以字典形式存儲,一共4個列名 creditss.columns#兩個數據框中的title列重復了,刪除credits中的title列,還剩3個列名 del creditss['title'] #movies中的id列與credits中的movie_id列實際上等同,可當做主鍵合并數據框 full = pd.merge(movies, creditss, left_on='id', right_on='movie_id', how='left')#某些列不在本次研究范圍,將其刪除 full.drop(['homepage','original_title','overview','spoken_languages','status','tagline','movie_id'],axis=1,inplace=True)#查看數據信息,每個字段數據量。 full.info()9.2數據清洗
首先,判斷哪些列有缺失值,以Ture=缺失, False=不缺失,得到release_date,runtime有缺失值。
full.isnull().any()release_date列有1條缺失數據,將其查找出來
full.loc[full['release_date'].isnull()==True]根據title經上網搜索,該影片上映日期為2014年6月1日,填補該值
full['release_date'] = full['release_date'].fillna('2014-06-01')runtime列有2條缺失數據,將其查找出來
full.loc[full['runtime'].isnull()==True]根據title經上網搜索,影片時長分別為94分鐘和240分鐘,填補缺失值
full['runtime'] = full['runtime'].fillna(94, limit=1)#limit=1,限制每次只填補一個值 full['runtime'] = full['runtime'].fillna(240, limit=1)將release_date列轉換為日期類型
full['release_date'] = pd.to_datetime(full['release_date'], format='%Y-%m-%d', errors='coerce').dt.yeargenres,keywords,production_companies,production_countries,cast,crew列為json類型
需要解析json數據,分兩步:
1. json本身為字符串類型,先轉換為字典列表
2. 再將字典列表轉換為,以'|'分割的字符串
定義一個json類型的列名列表
將各json列轉換為字典列表
for column in json_column:full[column]=full[column].map(json.loads)函數功能:將字典內的鍵‘name’對應的值取出,生成用'|'分隔的字符串
def getname(x):list = []for i in x:list.append(i['name'])return '|'.join(list) 對genres,keywords,production_companies,production_countries列執行函數for column in json_column[0:4]:full[column] = full[column].map(getname)
定義提取2名主演的函數:
def getcharacter(x):list = []for i in x:list.append(i['character'])return '|'.join(list[0:2])對cast列執行函數
full['cast']=full['cast'].map(getcharacter)定義提取導演的函數:
def getdirector(x):list=[]for i in x:if i['job']=='Director':list.append(i['name'])return "|".join(list)對crew列執行函數
full['crew']=full['crew'].map(getdirector)重命名列
rename_dict = {'release_date':'year','cast':'actor','crew':'director'} full.rename(columns=rename_dict, inplace=True)查看full表格中前2行數據
full.head(2)備份原始數據框original_df
original_df = full.copy()到此為止,我們的數據預處理告一段落。
9.3數據可視化
9.3.1問題1:研究電影風格隨時間的變化趨勢,提取所有的電影風格,存儲在有去重功能的集合中。
genre_df = pd.DataFrame() # 創建空的數據框 for genre in genre_set:#如果一個值中包含特定內容,則編碼為1,否則編碼為0genre_df[genre] = full['genres'].str.contains(genre).map(lambda x:1 if x else 0)
將原數據集中的year列,添加至genre_df數據框中
genre_df['year']=full['year']將genre_df按year分組,計算每組之和。groupby之后,year列通過默認參數as_index=True自動轉化為df.index
genre_by_year = genre_df.groupby('year').sum() genresum_by_year = genre_by_year.sum().sort_values(ascending=False)計算每個風格genre的電影總數目,并降序排列,再可視化
fig = plt.figure(figsize=(15,11)) #設置畫圖框的大小 ax = plt.subplot(1,1,1) #設置框的位置 ax = genresum_by_year.plot.bar() plt.xticks(rotation=60) plt.title('Film genre by year', fontsize=18) #設置標題的字體大小,標題名 plt.xlabel('count', fontsize=18) #X軸名及軸名大小 plt.ylabel('genre', fontsize=18) #y軸名及軸名大小 plt.show() #可以用查看數據畫的圖。 #保存圖片 fig.savefig('film genre by year.png',dpi=600)篩選出電影風格TOP8
genre_by_year = genre_by_year[['Drama','Comedy','Thriller','Romance','Adventure','Crime', 'Science Fiction','Horror']].loc[1960:,:] year_min = full['year'].min() #最小年份 year_max = full['year'].max() #最大年份可視化電影風格genre隨時間的變化趨勢(1960年至今)
fig = plt.figure(figsize=(10,8)) ax1 = plt.subplot(1,1,1) plt.plot(genre_by_year) plt.xlabel('Year', fontsize=12) plt.ylabel('Film count', fontsize=12) plt.title('Film count by year', fontsize=15) plt.xticks(range(1960, 2017, 10)) #橫坐標每隔10年一個刻度 #plt.legend(loc='best',ncol=2) #https://blog.csdn.net/you_are_my_dream/article/details/53440964 plt.legend(['Drama(戲劇類)','Comedy(喜劇類)','Thriller(驚悚類)','Romance(浪漫類)','Adventure(Adventure)','Crime(犯罪類)', 'Science Fiction(科幻類)','Horror(驚恐類)'], loc='best',ncol=2) #設置說明標簽 fig.savefig('film count by year.png',dpi=200)可以看出,從上世紀90年代開始,整個電影市場呈現爆發式增長。其中,排名前五的戲劇類(Drama)、喜劇類(Comedy)、驚悚類(Thriller)、浪漫類(Romance)、冒險類(Adventure)電影數量增長顯著。
9.3.2問題2:不同風格電影的收益能力
增加收益列
創建收益數據框
profit_df = pd.DataFrame()#創建空的數據框 profit_df = pd.concat([genre_df.iloc[:,:-1],full['profit']],axis=1) #合并 profit_df.head()#查看新數據框信息創建一個Series,其index為各個genre,值為按genre分類計算的profit之和
profit_by_genre = pd.Series(index=genre_set) for genre in genre_set:profit_by_genre.loc[genre]=profit_df.loc[:,[genre,'profit']].groupby(genre, as_index=False).sum().loc[1,'profit'] print(profit_by_genre) 創建一個Series,其index為各個genre,值為按genre分類計算的budget之和budget_df = pd.concat([genre_df.iloc[:,:-1],full['budget']],axis=1) budget_df.head(2) budget_by_genre = pd.Series(index=genre_set) for genre in genre_set:budget_by_genre.loc[genre]=budget_df.loc[:,[genre,'budget']].groupby(genre,as_index=False).sum().loc[1,'budget'] print(budget_by_genre)
向合并數據框
profit_rate = pd.concat([profit_by_genre, budget_by_genre],axis=1) profit_rate.columns=['profit','budget'] #更改列名加收益率列
profit_rate['profit_rate'] = (profit_rate['profit']/profit_rate['budget'])*100 profit_rate.sort_values(by=['profit','profit_rate'], ascending=False, inplace=True) #print(profit_rate)x為索引長度的序列
x = list(range(len(profit_rate.index)))可視化不同風格電影的收益(柱狀圖)和收益率(折線圖)
fig = plt.figure(figsize=(18,13)) ax1 = fig.add_subplot(111) plt.bar(x, profit_rate['profit'],label='profit',alpha=0.7) plt.xticks(x,xl,rotation=60,fontsize=12) plt.yticks(fontsize=12) ax1.set_title('Profit by genres', fontsize=20) ax1.set_ylabel('Film Profit',fontsize=18) ax1.set_xlabel('Genre',fontsize=18) ax1.set_ylim(0,1.2e11) ax1.legend(loc=2,fontsize=15)次縱坐標軸標簽設置為百分比顯示
import matplotlib.ticker as mtick ax2 = ax1.twinx() ax2.plot(x, profit_rate['profit_rate'],'ro-',lw=2,label='profit_rate') fmt='%.2f%%' yticks = mtick.FormatStrFormatter(fmt) ax2.yaxis.set_major_formatter(yticks) plt.xticks(x,xl,fontsize=12,rotation=60) plt.yticks(fontsize=15) ax2.set_ylabel('Profit_rate',fontsize=18) ax2.legend(loc=1,fontsize=15) plt.grid(False) #保存圖片 fig.savefig('profit by genres.png')9.3.3問題3:比較Universal Pictures與Paramount Pictures兩家巨頭公司的業績
創建公司數據框
創建巨頭對比數據框
Uni_vs_Para = pd.DataFrame(index=['Universal Pictures', 'Paramount Pictures'],columns=company_df.columns[2:])計算兩家公司各自收益總額
Uni_vs_Para.loc['Universal Pictures']=company_df.groupby('Universal Pictures',as_index=False).sum().iloc[1,2:] Uni_vs_Para.loc['Paramount Pictures']=company_df.groupby('Paramount Pictures',as_index=False).sum().iloc[1,2:]可視化兩公司票房收入對比
fig = plt.figure(figsize=(4,3)) ax = fig.add_subplot(111) Uni_vs_Para['revenue'].plot(ax=ax,kind='bar') plt.xticks(rotation=0) plt.title('Universal VS. Paramount') plt.ylabel('Revenue') fig.savefig('Universal vs Paramount by revenue.png')"""Universal Pictrues總票房收入高于Paramount Pictures"""
Uni_vs_Para = Uni_vs_Para.T分解兩公司數據框
universal = Uni_vs_Para['Universal Pictures'].iloc[:-1] paramount = Uni_vs_Para['Paramount Pictures'].iloc[:-1]將universal數量排名9之后的加和,命名為others
universal['others']=universal.sort_values(ascending=False).iloc[8:].sum() universal = universal.sort_values(ascending=True).iloc[-9:] 將paramount數量排名9之后的加和,命名為othersparamount['others']=paramount.sort_values(ascending=False).iloc[8:].sum() paramount = paramount.sort_values(ascending=True).iloc[-9:]
可視化兩公司電影風格數量占比
fig = plt.figure(figsize=(13,6)) ax1 = plt.subplot(1,2,1) ax1 = plt.pie(universal, labels=universal.index, autopct='%.2f%%',startangle=90,pctdistance=0.75) plt.title('Universal Pictures',fontsize=15)ax2 = plt.subplot(1,2,2) ax2 = plt.pie(paramount, labels=paramount.index, autopct='%.2f%%',startangle=90,pctdistance=0.75) plt.title('Paramount Pictures',fontsize=15)9.3.4問題4:看看票房與哪些因素有關
計算相關系數矩陣 full[['runtime','popularity','vote_average','vote_count','budget','revenue']].corr() 受歡迎度和票房相關性:0.64評價次數和票房相關性:0.78
電影預算和票房相關性:0.73
創建票房收入數據框
可視化票房收入分別與受歡迎度(藍)、評價次數(綠)、電影預算(紅)的相關性散點圖,并配線性回歸線。
fig = plt.figure(figsize=(17,5)) ax1 = plt.subplot(1,3,1) ax1 = sns.regplot(x='popularity', y='revenue', data=revenue, x_jitter=.1) ax1.text(400,2e9,'r=0.64',fontsize=15) plt.title('revenue by popularity',fontsize=15) plt.xlabel('popularity',fontsize=13) plt.ylabel('revenue',fontsize=13)ax2 = plt.subplot(1,3,2) ax2 = sns.regplot(x='vote_count', y='revenue', data=revenue, x_jitter=.1,color='g',marker='+') ax2.text(6800,1.1e9,'r=0.78',fontsize=15) plt.title('revenue by vote_count',fontsize=15) plt.xlabel('vote_count',fontsize=13) plt.ylabel('revenue',fontsize=13)ax3 = plt.subplot(1,3,3) ax3 = sns.regplot(x='budget', y='revenue', data=revenue, x_jitter=.1,color='r',marker='^') ax3.text(1.6e8,2.2e9,'r=0.73',fontsize=15) plt.title('revenue by budget',fontsize=15) plt.xlabel('budget',fontsize=13) plt.ylabel('revenue',fontsize=13) fig.savefig('revenue.png')電影評次與票房收入最相關(綠色),電影預算與票房收入高度相關(紅色),受歡迎度與評次高度相關,因此與票房收入相關性較高。
建議:增加電影預算 用于電影本身、多用于渠道宣傳
十、一些分析中用到的語法,當時查閱了資料整理一下。
(下次補充)
總結
以上是生活随笔為你收集整理的Kaggle——TMDB 5000 Movie Dataset电影数据分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决问题:vscode中文乱码(亲测有效
- 下一篇: C语言队列的出队