MathorCup 高校數學建模挑戰賽——大資料競賽
MathorCup 高校數學建模挑戰賽——大資料競賽
練習題:觀影大資料分析
王 S 聰想要在海外開拓萬 D 電影的市場,這次他在考慮:怎麼拍商業電影才能賺錢?畢竟一些製作成本超過 1 億美元的大型電影也會失敗。這個問題對電影業來說比以往任何時候都更加重要。 所以,他就請來了你(資料分析師)來幫他解決問題,給出一些建議,根據資料分析一下商業電影的成功是否存在統一公式?以幫助他更好地進行決策。
解決的終極問題是:電影票房的影響因素有哪些? 接下來我們就分不同的維度分析:
- 觀眾喜歡什麼電影型別?有什麼主題關鍵詞?
- 電影風格隨時間是如何變化的?
- 電影預算高低是否影響票房?
- 高票房或者高評分的導演有哪些?
- 電影的發行時間最好選在啥時候?
- 拍原創電影好還是改編電影好?
本次使用的資料來自於 Kaggle 平臺(TMDb 5000 Movie Database)。收錄了美國地區 1916-2017 年近 5000 部電影的資料,包含預算、導演、票房、電影評
分等資訊。原始資料集包含 2 個檔案:
- tmdb_5000_movies:電影基本資訊,包含 20 個變數
- tmdb_5000_credits:演職員資訊,包含 4 個變數請使用 Python 程式設計,完成下列問題:
(1) 使用附件中的 tmdb_5000_movies.csv 和 tmdb_5000_credits.csv 資料集,進行資料清洗、資料探勘、資料分析和資料視覺化等,研究電影票房的影響因素有哪些?從不同的維度分析電影,討論並分析你的結果。
(2) 附件 tmdb_1000_predict.csv 中包含 1000 部電影的基本資訊,請你選擇合適的指標,進行特徵提取,建立機器學習的預測模型,預測 1000 部電影的vote_average 和 vote_count,並儲存為 tmdb_1000_predicted.csv。
資料清洗
1 匯入資料
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來顯示中文
plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負號
import json
import warnings
warnings.filterwarnings('ignore')
pd.set_option('display.width', 1000) # 加了這一行那表格的一行就不會分段出現了
# 顯示所有列
pd.set_option('display.max_columns', None)
# 顯示所有行
pd.set_option('display.max_rows', None)
movies = pd.read_csv('D:\\installed\\python\\document\\tmdb_5000_movies.csv', encoding='utf_8')
credits = pd.read_csv('D:\\installed\\python\\document\\tmdb_5000_credits.csv', encoding='utf_8')
movies.info() # 檢視資訊
credits.info()
# 兩個資料框都有title列,以及movies.riginal_title
# 以上三個資料列重複,刪除兩個
del credits['title']
del movies['original_title']
# 連線兩個csv檔案
merged = pd.merge(movies, credits, left_on='id', right_on='movie_id', how='left')
# 刪除不需要分析的列
df = merged.drop(['homepage', 'overview', 'spoken_languages', 'status', 'tagline', 'movie_id'], axis=1)
df.info()
2 缺失值處理
缺失記錄僅 3條,採取網上搜索,補全資訊。
2.1 補全 release_date
查詢release_date是空
print("查詢缺失值記錄-release_date +++++++++++++++++++++++++++++++")
n = df[df.release_date.isnull()]
print(n)
缺失記錄的電影標題為《 America Is Still the Place》,日期為 2014-06-01。
2.2 補全 runtime
查詢runtime是空的資料
n2 = df[df.runtime.isnull()]
print(n2)
缺失記錄的電影 runtime 分別為 94min 和 240min。
3 重複值處理
print("重複值處理+++++++++++++++++++++++++++++++")
n3 = len(df.id.unique())
print(n3)
執行結果:有 4803個不重複的 id,可以認為沒有重複資料。
4 日期值處理
將 release_date 列轉換為日期型別:
print("release_date 列轉換為日期型別+++++++++++++++++++++++++++++++++")
df['release_year'] = pd.to_datetime(df.release_date, format = '%Y-%m-%d',errors='coerce').dt.year
df['release_month'] = pd.to_datetime(df.release_date).apply(lambda x: x.month)
df['release_day'] = pd.to_datetime(df.release_date).apply(lambda x: x.day)
df.info()
5 篩選資料
使用資料分析師最喜歡的一個語法:
n4 = df.describe()
print(n4)
票房、預算、受歡迎程度、評分為 0的資料應該去除;
評分人數過低的電影,評分不具有統計意義,篩選評分人數大於 50的資料。
df = df[(df.vote_count >= 50) & (df.budget * df.revenue * df.popularity * df.vote_average !=0)].reset_index(drop = 'True')
df.info()
此時剩餘 2961條資料,包含 19個欄位。
6 json 資料轉換
**說明:**genres,keywords,production_companies,production_countries,cast,crew 這 6 列都是
json 資料,需要處理為列表進行分析。處理方法:
json 本身為字串型別,先轉換為字典列表,再將字典列表轉換為,以’,'分割的字串
print("+++++++++++++++++++++++++pppppppppppppp")
json_column = ['genres', 'keywords', 'production_companies', 'production_countries', 'cast', 'crew']
# 1-json本身為字串型別,先轉換為字典列表
for i in json_column:
df[i] = df[i].apply(json.loads)
# 2-將字典列表轉換為以','分割的字串
def get_name(x):
return ','.join([i['name'] for i in x])
df['cast'] = df['cast'].apply(get_name)
# 3.提取derector
def get_director(x):
for i in x:
if i['job'] == 'Director':
return i['name']
df['crew'] = df['crew'].apply(get_director)
for j in json_column[0:4]:
df[j] = df[j].apply(get_name)
# 命名字典
rename_dict = {'cast': 'actor', 'crew': 'director'}
df.rename(columns=rename_dict, inplace=True)
df.info()
df.head(5)
7 資料備份
print("++++++++++++++++++++++++++++++++")
# 備份原始資料框original_df
org_df = df.copy()
df.reset_index().to_csv("TMDB_5000_Movie_Dataset_Cleaned.csv")
df.info()
5 資料分析
5.1 why
想要探索影響票房的因素,從電影市場趨勢,觀眾喜好型別,電影導演,發行時間,評分與關鍵詞等維度著手,給從業者提供合適的建議。
5.2 what
5.2.1 電影型別:定義一個集合,獲取所有的電影型別
genre = set()
for i in df['genres'].str.split(','): # 去掉字串之間的分隔符,得到單個電影型別
genre = set().union(i, genre) # 集合求並集
# genre.update(i) #或者使用update方法
print(genre)
注意到集合中存在多餘的元素:空的單引號,所以需要去除。
genre.discard('')
print("去除多餘的元素")
print(genre)
5.2.1.1 電影型別數量(繪製條形圖)
# 將genre轉變成列表
genre_list = list(genre)
# 建立資料框-電影型別
genre_df = pd.DataFrame()
# 對電影型別進行one-hot編碼
for i in genre_list:
# 如果包含型別 i,則編碼為1,否則編碼為0
genre_df[i] = df['genres'].str.contains(i).apply(lambda x: 1 if x else 0)
# 將資料框的索引變為年份
genre_df.index = df['release_year']
genre_df.head(5)
# 計算得到每種型別的電影總數目,並降序排列
grnre_sum = genre_df.sum().sort_values(ascending=False)
# 視覺化
colors = ['cyan', 'red']
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來顯示中文
grnre_sum.plot(kind='bar', label='genres', color=colors, figsize=(12, 9))
plt.title('不同型別的電影數量總計', fontsize=20)
plt.xticks(rotation=60)
plt.xlabel('電影型別', fontsize=16)
plt.ylabel('數量', fontsize=16)
plt.grid(False)
plt.savefig("不同電影型別數量-條形圖.png", dpi=300) # 在 plt.show() 之前呼叫 plt.savefig()
plt.show()
5.2.1.2 電影型別佔比(繪製餅圖)
5.2.1.3 電影型別變化趨勢(繪製折線圖)