1. 程式人生 > >Pandas-Numpy-Matplotlib-PyEcharts——綜合案例(豆瓣電影Top_250資料分析)

Pandas-Numpy-Matplotlib-PyEcharts——綜合案例(豆瓣電影Top_250資料分析)

豆瓣電影Top_250_Data_analysis(執行在jupyter notebook環境)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pyecharts import Bar,Line,Pie
from pandas import DataFrame,Series

一、 資料收集、載入資料 並檢視

抓取排名,電影名,導演,主演,上映日期,製片國家/地區,型別。
評分,評論數量,一句話評價,已經電影連結

top250 網址:https://movie.douban.com/top250
選用Python3 引入 url.requests BeautifulSoup4 來抓取
1.2 抓取資料問題:
    原來頁面的缺失資訊(如:導演,演員等)
    原來頁面的本來就沒有電影語言,時長,tag
解決方法:
    取出當前資料的最後一列的url
    解析url取出電影唯一的id
    根據id得到詳細頁面,抓取資訊
    https://api.douban.com/v2/movie/id
1.3 載入資料並檢視:
df_1 = pd.read_csv('./csv/top250_f1.csv',sep = '#')
df_2 = pd.read_csv('./csv/top250_f2.csv',sep = '#')
df_1.head()     #檢視前五條資料
#df_2.head() #檢視前五條資料
num title director role init
_year
area genre rat
ing_
num
com
ment_
num
comment url
0 1 肖申克的救贖 弗蘭克·德拉邦特 Frank Darabont 蒂姆·羅賓斯 Tim Robbins 1994 美國 [‘犯罪 劇情’] 9.6 964842 希望讓人自由。 https://movie.
douban.com
/subject/1292052/
1 2 霸王別姬 陳凱歌 Kaige Chen 張國榮 Leslie Cheung 1993 中國大陸 香港 [‘劇情 愛情 同性’] 9.5 699930 風華絕代。 https://movie.
douban.com
/subject/1291546/
2 3 這個殺手不太冷 呂克·貝鬆 Luc Besson 讓·雷諾 Jean Reno 1994 法國 [‘劇情 動作 犯罪’] 9.4 912435 怪蜀黍和小蘿莉不得不說的故事。 https://movie.
douban.com
/subject/1295644/
3 4 阿甘正傳 Robert Zemeckis Tom Hanks 1994 美國 [‘劇情 愛情’] 9.4 775889 一部美國近現代史。 https://movie.
douban.com/
subject/1292720/
4 5 美麗人生 羅伯託·貝尼尼 Roberto Benigni 羅伯託·貝尼尼 Roberto Beni…’] 1997 義大利 [‘劇情 喜劇 愛情 戰爭’] 9.5 453651 最美的謊言。 https://movie.
douban.com/
subject/1292063/

二、資料合併(將這兩個互有缺失值的DataFrame合併)

將df_1與df_2合併資料

資料分佈在兩個檔案中:
取 top250_f1.csv 中的 num(排名),title(電影名),init_year(上映時間),area(國家/地區)
和 top250_f2.csv 中的 language(語言),director(導演),cast(主演),movie_duration(時長),\
tags(標籤)這些列進行分析。

df_1_cut = df_1[['num','title','init_year','area','genre','rating_num','comment_num']]
df_2_cut = df_2[['num','language','director','cast','movie_duration','tags']]
df = df.merge(df_1_cut,df_2_cut,how = 'outer',on = 'num')   #外連線,合併標準on = 'num'
df.head()           #檢視前五條資訊
       #df.tail()   檢視後五條資訊
       #df.info()   檢視整個資料集的資訊
nu
m
title init
_year
area genre rat
ing_
num
com
ment_
num
lang
uage
director cast movie_
duration
tags
0 1 肖申克的救贖 1994 美國 [‘犯罪 劇情’] 9.6 964842 [‘英語’] [‘弗蘭克·德拉邦特 Frank Darabont’] [‘蒂姆·羅賓斯 Tim Robbins’, ‘摩根·弗里曼 Morgan Freeman’… [‘142 分鐘’] [{‘count’: 197742, ‘name’: ‘經典’}, {‘count’: 16…
1 2 霸王別姬 1993 中國大陸 香港 [‘劇情 愛情 同性’] 9.5 699930 [‘漢語普通話’] [‘陳凱歌 Kaige Chen’] [‘張國榮 Leslie Cheung’, ‘張豐毅 Fengyi Zhang’, ‘鞏俐 … [‘171 分鐘’] [{‘count’: 124150, ‘name’: ‘經典’}, {‘count’: 63…
2 3 這個殺手不太冷 1994 法國 [‘劇情 動作 犯罪’] 9.4 912435 [‘英語’, ‘義大利語’, ‘法語’] [‘呂克·貝鬆 Luc Besson’] [‘讓·雷諾 Jean Reno’, ‘娜塔莉·波特曼 Natalie Portman’, … [‘110分鐘(劇場版)’, ‘133分鐘(國際版)’] [{‘count’: 150097, ‘name’: ‘經典’}, {‘count’: 85…
3 4 阿甘正傳 1994 美國 [‘劇情 愛情’] 9.4 775889 [‘英語’] [‘Robert Zemeckis’] [‘Tom Hanks’, ‘Robin Wright Penn’, ‘Gary Sinis… [‘142 分鐘’] [{‘count’: 179046, ‘name’: ‘勵志’}, {‘count’: 13…
4 5 美麗人生 1997 義大利 [‘劇情 喜劇 愛情 戰爭’] 9.5 453651 [‘義大利語’, ‘德語’, ‘英語’] [‘羅伯託·貝尼尼 Roberto Benigni’] [‘羅伯託·貝尼尼 Roberto Benigni’, ‘尼可萊塔·布拉斯基 Nicolet… [‘116分鐘’] [{‘count’: 70710, ‘name’: ‘義大利’}, {‘count’: 67…

三、資料清洗(消耗40%時間)

3.1 檢視所有資料 : 資料去重 df.duplicated()
df.duplicated().head() #返回 True,則有重複項,反之亦然
df.duplicated().value_counts()
df.title.unique()      #檢查某一列是否有重複電影名
df.num.unique()        #檢查某一列是否有並列排名
3.2 資料格式,內容清洗
◆去除多餘欄位-去除欄位兩側['']形式,可以用str分數字符串
df['genre'] = df['genre'].str[2:-2]
df['language'] = df['language'].str[2:-2]
df['director'] = df['director'].str[2:-2]
df['cast'] = df['cast'].str[2:-2]
df['movie_duration'] = df['movie_duration'].str[2:-2]
df.head()
num genre rating
_num
comme
nt_num
lang
uage
director cast movie_
duration
tags
0 1 犯罪 劇情 9.6 964842 英語 弗蘭克·德拉邦特 Frank Darabont 蒂姆·羅賓斯 Tim Robbins’, ‘摩根·弗里曼 Morgan Freeman’, … 142 分鐘 [{‘count’: 197742, ‘name’: ‘經典’}, {‘count’: 16…
1 2 劇情 愛情 同性 9.5 699930 漢語普通話 陳凱歌 Kaige Chen 張國榮 Leslie Cheung’, ‘張豐毅 Fengyi Zhang’, ‘鞏俐 Li… 171 分鐘 [{‘count’: 124150, ‘name’: ‘經典’}, {‘count’: 63…
2 3 劇情 動作 犯罪 9.4 912435 英語’, ‘義大利語’, ‘法語 呂克·貝鬆 Luc Besson 讓·雷諾 Jean Reno’, ‘娜塔莉·波特曼 Natalie Portman’, ‘加… 110分鐘(劇場版)’, ‘133分鐘(國際版) [{‘count’: 150097, ‘name’: ‘經典’}, {‘count’: 85…
3 4 劇情 愛情 9.4 775889 英語 Robert Zemeckis Tom Hanks’, ‘Robin Wright Penn’, ‘Gary Sinise’… 142 分鐘 [{‘count’: 179046, ‘name’: ‘勵志’}, {‘count’: 13…
4 5 劇情 喜劇 愛情 戰爭 9.5 453651 義大利語’, ‘德語’, ‘英語 羅伯託·貝尼尼 Roberto Benigni 羅伯託·貝尼尼 Roberto Benigni’, ‘尼可萊塔·布拉斯基 Nicoletta… 116分鐘 [{‘count’: 70710, ‘name’: ‘義大利’}, {‘count’: 67…
3.2.1 國家(地區)內容清洗
 #對於area列,由多個國家地區之間合作的電影,中間用空格隔開,
 #用str.split()分列,再應用apply(pd.Series)作用到每一行或列

area_split = df['area'].str.split('').apply(pd.Series)
area_split.head()

 #對每列的值重合的作了一個彙總統計,同時NaN用0填充
a = area_split.apply(df.value_counts).fillna('0')

 #更改列名,轉換資料型別(object->int)
a.columns = ['area_1','area_2','area_3','area_4','area_5']
a['area_1'] = a['area_1'].astype(int)
a['area_2'] = a['area_2'].astype(int)
a['area_3'] = a['area_3'].astype(int)
a['area_4'] = a['area_4'].astype(int)
a['area_5'] = a['area_5'].astype(int)

 #將每一行的資料彙總後,變成一列顯示(行彙總)
a = a.apply(lambda x:x.sum().axis=1)

 #包裝成一個標準的 DataFrame 
area_c = df.DataFrame(a,column = ['counts'])
area_c.head()
這裡寫圖片描述
3.2.2 電影型別genre(類似於區域內容清洗)
 #對於genre列,中間用空格隔開的,用str.split()分列,再應用apply(pd.split)作用到每一行或列
genre_split = df['genre'].str.split('').apply(pd.Series)
genre_split.head()

 #拆分列,Na 用 0 填充
genre_split = genre_split.apply(pd.value_counts).fillna(0)
genre_split.head()

 #統計電影型別
g = genre_split.apply(lambda row : row.sum(),axis = 1)
g.head()

 #將Series轉成DataFrame
g = DataFrame(g,columns = ['counts'])
g.head()
-------------------------------方法2----------------------------------
 #對每列的值重合的作了一個彙總統計
a = genre_split.apply(df.value_counts)

 #利用 unstack() 函式做一個行列轉換,同時刪除NaN,轉換成DataFrame
g = g.unstack().dropna().reset_index()
g.head()

 #資料行列重新命名
g.columns = ['level_0','level_1','counts']
 #刪除(level_0)第一列,同時按照'level_1'欄位的值進行分組,同時彙總
genre_c = g.drop(['level_0'],axis = 1).groupby('level_1').sum()
 #按 'counts' 欄位降序排列
genre_c.sort_values('counts'.ascending = False).head()
這裡寫圖片描述
3.2.3 電影語言:
 #類似的方法處理 language 列
language_split = df['language'].str.replace("\', \'",' ').str.split(' ').apply(pd.Series)
l = language_split.apply(pd.value_counts).stack().dropna().reset_index()
language = ['level_0','level_1','counts']
language_c = l.groupby('level_0').sum()
language_c = language_c.drop(['level_1'],axis = 1)
language_c.head()
3.2.4 導演
df.director
director_split = df['director'].str.replace("\', \'",'#').str.split('#').apply(pd.Series)
director_split.head()
director = director.split[0].str.strip()
df['director'] = director
df['director'].head()
3.2.5 演員(cast)
df.cast
cast_split = df['cast'].str.replace("\', \'",'#').str.split('#').apply(pd.Series)
 #[[0,1,2,3]].column = ['performar_1','performar_2','performar_3','performar_4']
out_split.head()

選取六位演員分析
c = cast_split[[0,1,2,3,4,5]]   #column = ['performar_1','performar_2'...'performar_6']
c.columns = ['performar_1','performar_2','performar_3','performar_4','performar_5','performar_6']
c = cast_split.unstack().dropna().reset_index()
c.head()

c.columns = ['level_0','level_1','performars']
c['performars'] = c['performars'].str.strip()
c.head()

 #演員表中名字有:中英文,只有中文,只有英文
 #下面是單獨找出中文/英文命,並將其補全
for i in c['performars']:
    for j in [c['performars'].str.contains(i)]['performars']:
        if (len(j) > len(i)):
            row = c[c['performars'] == i]
            level_0 = row['level_0']
            level_1 = row['level_1']
            c[c['performars'] == i] = [level_0,level_1,j]
        else:
            continue
c.head()

 #根據演員名臣進行分組並計數
c = c.groupby('performars').count()
c.head()

 #此時,'level_0''level_1'的資料完全是一樣的,刪除'level_0'列
c = c.drop(['level_0'],axis = 1)
c.columns = ['counts']
cats_c = c
3.2.5 時長(movie_duration)
df['movie_duration']
movie_duration_split = df['movie_duration'].str.strip().str.replace('\',\'','#').str.split('#').apply(pd.Series)
movie_duration_split.head()

 #有些電影存在多種版本,一般情況下,第一個版本觀看數量較多,因此取第一個
duration = movie_duration_split[0].str.split('分').apply(pd.Series)[0].str.strip()
duration.head()

 #觀看數量發現:
 #duration.str.len().value_counts() 檢查放映時間是否大於三位數
duration[duration.str.len() > 3]

 #放映時間大於三位數,資料異常,要額外處理
duration[244] = duration[244].split(' ')[1]

 #現在更改資料型別:
duration = duration.astyle(int)
duration.dtypes

df['movie_duration'] = duration
df['movie_duration'].head()
3.2.6 電影標記(tags)
先檢視'tags'列,先看一下基本情況
df['tags'][0]   

tags_split = df['tags'].str.replace('count\':',' ').str.replace(',\'name\':\'',' ').str.replace('\'},{\'','').str.split(' ').apply(pd.Series)
tags_split
 #刪除第一列
del tags_split[0]
 #處理掉最後一列的特殊字元:'}]
tags_split[] = tags_split[16].str.replace('\}]','')
tags_split.head()

 #一般閱讀習慣是先看標籤類別,再看標籤數量,調整一下位置比較便於閱讀
tags_split = tags_split.reindex(columns = [2,1,3,6,5,8,7,10,9,12,11,14,13,16,15])
tags_split.head()

 #更改列名
tags_split.columns= [
                    'tags_1','tags_count_1','tags_2','tags_count_2',
                    'tags_3','tags_count_3','tags_4','tags_count_4',
                    'tags_5','tags_count_5','tags_6','tags_count_6',
                    'tags_7','tags_count_7','tags_8','tags_count_8',
                    ]
tags_split.head()
3.2.7 上映時間(init_year)
 #有的電影給出多個不同上映時間,為方便,我們取第一個。

year_split = df['init_year'].str.split('/').apply(pd.Series)[0].str.strip()
 #主要為了處理第78條:大鬧天宮:1961(中國大陸)/1964(中國大陸)/1978(中國大陸)/2004(中國大陸)/
year_split = year_split.str.slice(0,4)

df['init_year'] = year_split.astyle(int)
df['init_year'].head()
3.2 缺失值檢查與檢視
df[df.isnull().values == True] 
df.info()

四、資料統計與分析

4.1 數值型列的資料統計
    df.describe()           #用 describe() 看數值型資料的統計資訊
4.2 電影排名分析
    df[['num','title']].head(10)   #先看資料(檢視前10名資料)
4.3 按評分-top10分析
Top10_rating_num = df[['rating_num','title']].sort_values(by = ['rating_num'],ascending = False).head(10).reset_index()
 #Top10_rating_num.index = [1,2,3,4,5,6,7,8,9,10]
Top10_rating_num

按評價數量排名-top10分析
Top10_comment_num = df[['comment_num','title']].srot_values(by = ['comment_num'],ascending = False).head(10).reset_index()
 #Top10_comment_num.index = [1,2,3,4,5,6,7,8,9,10]
Top10_comment_num
4.4 上榜次數統計分析
4.4.1上榜次數最多的導演
df['director'].value_counts().head()

4.4.2 上榜次數最多的演員
cast_c.sort_values(by = ['counts'],ascending = False).head()

五、資料分析與視覺化展示(matplotlib)

5.1 matplotlib 視覺化包基本環境配置
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.family'] = 'SimHei'   #配置中文字型
matplotlib.rcParams['font.size'] = 15           #更改預設字型大小
5.2 評分 與排名
plt.scatter(df['rating_num'].df['num']) #繪製散點圖
plt.xlabel('rating_num')                # x 軸標籤
plt.ylabel('ranking list')              # y 軸標籤
plt.show()

由於觀看不便,可以通過 invert_yaxis() 改變y軸標籤順序
重構:
    plt.figure(figsize = (14,6))            #畫布大小(14,6)
    plt.subplot(1,2,1)
    plt.scatter(df['rating_num'].df['num']) #繪製散點圖
    plt.xlabel('rating_num')                # x 軸標籤
    plt.ylabel('ranking list')              # y 軸標籤
    plt.gca().invert_yaxis()                #更改y軸標籤順序

    plt.subplot(1,2,2)
    plt.hist(df['rating_num'],bins = 15)
    plt.xlabel('rating_num')

    plt.show()
這裡寫圖片描述
    df['num'].corr(df['rating_num'])    #利用 泊松分佈 顯示相關性
5.3 評論人數 與排名
plt.figure(figsize = (14,6))                #畫布大小(14,6)
plt.subplot(1,2,1)
plt.scatter(df['comment_num'].df['num'])    #繪製散點圖
plt.xlabel('comment_num')                   # x 軸標籤
plt.ylabel('ranking list')                  # y 軸標籤
plt.gca().invert_yaxis()                    #更改y軸標籤順序

plt.subplot(1,2,2)
plt.hist(df['comment_num'])
plt.xlabel('comment_num')

plt.show()
這裡寫圖片描述
df['num'].corr(df['comment_num'])           #利用 泊松分佈 顯示相關性
5.4 電影時長 與排名
plt.figure(1)
plt.figure(figsize = (14,6))                #畫布大小(14,6)
plt.subplot(1,2,1)
plt.scatter(df['movie_duration'].df['num']) #繪製散點圖
plt.xlabel('movie_duration')                # x 軸標籤
plt.ylabel('ranking list')                  # y 軸標籤
plt.gca().invert_yaxis()                    #更改y軸標籤順序

plt.subplot(1,2,2)
plt.hist(df['movie_duration']bins = 50)
plt.xlabel('movie_duration')

plt.show()
這裡寫圖片描述
df['num'].corr(df['movie_duration'])       #利用 泊松分佈 顯示相關性
5.5 上映年份 與排名
plt.figure(1)
plt.figure(figsize = (14,6))            #畫布大小(14,6)
plt.subplot(1,2,1)
plt.scatter(df['init_year'].df['num'])  #繪製散點圖
plt.xlabel('init_year')                 # x 軸標籤
plt.ylabel('ranking list')              # y 軸標籤
plt.gca().invert_yaxis()                #更改y軸標籤順序

plt.subplot(1,2,2)
plt.hist(df['init_year']bins = 30)
plt.xlabel('init_year')

plt.show()

df['num'].corr(df['init_year'])        #利用 泊松分佈 顯示相關性
5.6 國家/地區 與排名
area_c.sort_values(by='counts',ascending = False).plot(king='bar',figsize = (12,6))
plt/show()

這裡寫圖片描述

5.7 語言 與排名
language_c.sort_values(by = 'counts',ascending = False)[:30].plot(king='bar',figsize = (12,6))
plt.show()
5.8 電影型別 與排名
genre_c.sort_values(by = 'counts',ascending = False).plot(king='bar',figsize = (12,6))
plt.show()
5.9 電影標籤熱度詞雲統計 與排名
tag_name = tags_split[['tags_1','tags_2','tags_3','tags_4','tags_5','tags_6','tags_7','tags_8']]
tag_name = tag_name.values.flatten()
len(tag_name)

from pyecharts import WordCloud
values=np.arange(10000,step=5)
wordcloud = WordCloud(width=1300, height=620)  #板塊
wordcloud.add("",tag_name,values, 
              word_size_range=[20, 100])#單詞大小區間範圍
wordcloud.render("wordcloud.html")
這裡寫圖片描述

六、資料分析與視覺化展示

6.1 安裝pyecharts 視覺化基本環境配置
import pip
def import(package):
    pip.main(['install',package])
install('pyecharts==0.1.8')
6.2 電影型別-排名
from pyecharts import Bar
mybar = Bar('電影型別分析')
new_g = g.sort_values(by = 'counts',ascending = False)
attr = new_g.index
value = new_g.counts
mybar.add('電影型別',attr,value,mark_line = ['max'],mark_point = ['average'])
mybar.render('movie_01.html')
mybar
這裡寫圖片描述
6.3 按評分佔比統計
from pyecharts import Pie
Top10_rating_num = df[['rating_num','title']].sort_values(by = 'rating_num',ascending = False).head(10).reset_index()
sttr = data['level_1'].tolist()
v1 = data['rating_num'].tolist()

pie = Pie('排名前10電影評分佔比',title_pos = 'center')
pie.add('',sttr,v1,is_label_show = True,legend_orient = 'vertical',legend_pos = 'right')
bar.render_notebook()
6.4 國家地區-排名
from pyecharts import Line
areas = area_c.reset_index()
v1 = area['counts'].tolist()
attr = area['index'].tolist

line = Line('國家地區電影排名')
line.add('國家',attr,v1,mark_point = ['min','max'],is_smooth=True,mark_line['max','average'])
line.render_notebook()