案例背景
最近總看到《消失的她》票房多少多少,《孤注一擲》票房又破了多少多少.....
于是我就想自己爬蟲一下獲取中國高票房的電影數(shù)據(jù),然后分析一下。
數(shù)據(jù)來源于淘票票:影片總票房排行榜 (maoyan.com)
爬它就行。
不會爬蟲的同學(xué)要這代碼演示數(shù)據(jù)可以參考:數(shù)據(jù)
?
代碼實現(xiàn)
首先爬蟲獲取數(shù)據(jù):
數(shù)據(jù)獲取
導(dǎo)入包
import requests; import pandas as pd
from bs4 import BeautifulSoup
?傳入網(wǎng)頁和請求頭
url = 'https://piaofang.maoyan.com/rankings/year'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.62'}
response1 = requests.get(url,headers=headers)
response.status_code
200表示獲取網(wǎng)頁文件成功
然后解析網(wǎng)頁文件,獲取電影信息數(shù)據(jù)
%%time
soup = BeautifulSoup(response.text, 'html.parser')
soup=soup.find('div', id='ranks-list')
movie_list = []
for ul_tag in soup.find_all('ul', class_='row'):
movie_info = {}
li_tags = ul_tag.find_all('li')
movie_info['序號'] = li_tags[0].text
movie_info['標(biāo)題'] = li_tags[1].find('p', class_='first-line').text
movie_info['上映日期'] = li_tags[1].find('p', class_='second-line').text
movie_info['票房(億)'] = f'{(float(li_tags[2].text)/10000):.2f}'
movie_info['平均票價'] = li_tags[3].text
movie_info['平均人次'] = li_tags[4].text
movie_list.append(movie_info)
數(shù)據(jù)獲取完成了! 查看字典數(shù)據(jù):
?
movie_list
可以,很標(biāo)準(zhǔn),沒什么問題,然后把它變成數(shù)據(jù)框,查看前三行
movies=pd.DataFrame(movie_list)
movies.head(3)
對數(shù)據(jù)進行一定的清洗,我們看到上映日期里面的數(shù)據(jù)有“上映”兩個字,我們要去掉,然后把它變成時間格式,票房,票價,人次都要變成數(shù)值型數(shù)據(jù)。
我們只取票房前250的電影,對應(yīng)豆瓣250.,,,,中國票房250好叭
然后我們還需要從日期里面抽取年份和月份兩列數(shù)據(jù),方便后面分析。
#清洗
movies=movies.set_index('序號').loc[:'250',:]
movies['上映日期']=pd.to_datetime(movies['上映日期'].str.replace('上映',''))
movies[['票房(億)','平均票價','平均人次']]=movies.loc[:,['票房(億)','平均票價','平均人次']].astype(float)
movies['年份']=movies['上映日期'].dt.year ; movies['月份']=movies['上映日期'].dt.month
movies.head(2)
數(shù)據(jù)處理完畢,開始畫圖分析!
畫圖分析
導(dǎo)入畫圖包
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams ['font.sans-serif'] ='SimHei' #顯示中文
plt.rcParams ['axes.unicode_minus']=False
?對票房排名前20的電影畫柱狀圖
top_movies = movies.nlargest(20, '票房(億)')
plt.figure(figsize=(7, 4),dpi=128)
ax = sns.barplot(x='票房(億)', y='標(biāo)題', data=top_movies, orient='h',alpha=0.5)
#plt.xticks(rotation=80, ha='center')
# 在柱子上標(biāo)注數(shù)值
for p in ax.patches:
ax.annotate(f'{p.get_width():.2f}', (p.get_width(), p.get_y() + p.get_height() / 2.),
va='center', fontsize=8, color='gray', xytext=(5, 0),
textcoords='offset points')
plt.title('票房前20的電影')
plt.xlabel('票房數(shù)量(億)')
plt.ylabel('電影名稱')
plt.tight_layout()
plt.show()
還不錯,很好看,可以看到中國歷史票房前20 的電影名稱和他們的票房數(shù)量。
對平均票價和平均人次進行分析:
?
plt.figure(figsize=(7, 6),dpi=128)
# 繪制第一個子圖:平均票價點圖
plt.subplot(2, 2, 1)
sns.scatterplot(y='平均票價', x='年份', data=movies,c=movies['年份'],cmap='plasma')
plt.title('平均票價點圖')
plt.ylabel('平均票價')
#plt.xticks([])
plt.subplot(2, 2, 2)
sns.boxplot(y='平均票價', data=movies)
plt.title('平均票價箱線圖')
plt.xlabel('平均票價')
plt.subplot(2, 2, 3)
sns.scatterplot(y='平均人次', x='年份', data=movies,c=movies['年份'],cmap='plasma')
plt.title('平均人次點圖')
plt.ylabel('平均人次')
plt.subplot(2, 2, 4)
sns.boxplot(y='平均人次', data=movies)
plt.title('平均人次箱線圖')
plt.xlabel('平均人次')
plt.tight_layout()
plt.show()
先看柱狀圖,可以看到平均票價和平均人次都是有一些離群點的,然后我們在左邊畫了他們和年份的的散點圖,可以明細(xì)看到,隨著年份越大,電影的平均人次越來越低,平均票價越來越高.....也就是最近的電影比起之前的電影來說,越來越貴,而且平均每場看的人越來越少......也側(cè)面反映了我國電影業(yè)的一些“高票價”,‘幽靈劇場刷票房’ 等等亂象...
我注意到2000年之前有一個電影每場人次特別高,票價很低,它是什么電影我很好奇我就查看了一下:
movies[movies['年份']<2000]
原來是國民級別的《泰坦尼克號》,那沒事了,名副實歸。
不同年份的高票房電影數(shù)量:
plt.figure(figsize=(7, 3), dpi=128)
year_count = movies['年份'].value_counts().sort_index()
sns.lineplot(x=year_count.index, y=year_count.values, marker='o', lw=1.5, markersize=3)
plt.fill_between(year_count.index, 0, year_count, color='lightblue', alpha=0.8)
plt.title('不同年份高票房電影數(shù)量')
plt.xlabel('年份')
plt.ylabel('電影數(shù)量')
# 在每個數(shù)據(jù)點上標(biāo)注數(shù)值
for x, y in zip(year_count.index, year_count.values):
plt.text(x, y+0.2, str(y), ha='center', va='bottom', fontsize=8)
plt.tight_layout()
plt.show()
可以看到,我國高票房的電影,從2010年開始高速增長,到2017年到達(dá)峰值,著名的《戰(zhàn)狼2》就是2017年上映的,然后2018和2019略微下降,2020年斷崖下跌,,為什么,懂得懂得,疫情原因嘛。
對高票房電影不同月份的占比百分比分析:
plt.figure(figsize=(4, 4),dpi=128)
month_count = movies['月份'].value_counts(normalize=True).sort_index()
# 繪制餅圖
sns.set_palette("Set3")
plt.pie(month_count, labels=month_count.index, autopct='%.1f%%', startangle=140, counterclock=False,
wedgeprops={'alpha': 0.9})
plt.axis('equal') # 保證餅圖是正圓形
plt.text(-0.3,1.2,'不同月份高票房電影數(shù)量',fontsize=8)
plt.tight_layout()
plt.show()
我們可以看到,高票房電影主要集中在2月,7月,12月,三個月份區(qū)間。
理由也很簡單,2月春節(jié),7月暑假,12月跨年.....電影都喜歡這三個時間段上映。
自定義評價指標(biāo)
我們上面都是之間拿票房進行分析的,我們發(fā)現(xiàn),票房高的電影真的是反映了看的人多嘛?它真的是受觀眾喜歡的好電影嘛?
數(shù)據(jù)有限,雖然我們無法剔除宣傳,時間熱點,導(dǎo)演,社會風(fēng)氣等等影響因素,但是我們可以把票價進行一定的控制。因為票房高的電影也有可能是票價過高造成的,所以我們用‘票房/平均票價’,然后和‘平均人次’進行一個加權(quán)求和。
票房/平均票價 表示看電影的人群量,給7成權(quán)重,平均人次 給一個3層的權(quán)重,然后都進行標(biāo)準(zhǔn)化統(tǒng)一數(shù)據(jù)單位,加起來就成為我們自己的評價指標(biāo):
為了方便標(biāo)準(zhǔn)化我們先導(dǎo)入一個機器學(xué)習(xí)庫里面sklearn的標(biāo)準(zhǔn)化函數(shù)
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
?計算指標(biāo):
movies['我的評價指標(biāo)']=(movies['票房(億)'].astype(float)/movies['平均票價'].astype(float))
data1=scaler.fit_transform(movies[['我的評價指標(biāo)', '平均人次']])
movies['我的評價指標(biāo)']=0.7*data1[:,0]+0.3*data1[:,1]
movies=movies.sort_values(by='我的評價指標(biāo)',ascending=False)
畫圖查看:
?
my_top_movies = movies.nlargest(20, '我的評價指標(biāo)')
plt.figure(figsize=(7, 4),dpi=128)
ax = sns.barplot(x='我的評價指標(biāo)', y='標(biāo)題', data=my_top_movies, orient='h',alpha=0.6,palette='rainbow_r')
#plt.xticks(rotation=80, ha='center')
# 在柱子上標(biāo)注數(shù)值
for p in ax.patches:
ax.annotate(f'{p.get_width():.2f}', (p.get_width(), p.get_y() + p.get_height() / 2.),
va='center', fontsize=8, color='gray', xytext=(5, 0),
textcoords='offset points')
plt.title('前20電影')
plt.xlabel('我的評價指標(biāo)')
plt.ylabel('電影名稱')
plt.tight_layout()
plt.show()
和之前的最高票房前20 的作對比,這樣我們能比較哪些是票房過高的電影,哪些是可能被低估的電影。
def get_unique_elements(list1, list2):
# 獲取每個列表中的唯一元素
set1 = set(list1) ; set2 = set(list2)
unique_to_list1 = list(set1 - set2)
unique_to_list2 = list(set2 - set1)
common_elements = list(set1 & set2)
return unique_to_list1, common_elements, unique_to_list2
票價過高的電影,確實是好電影,被低估的電影=get_unique_elements(top_movies['標(biāo)題'].to_list(), my_top_movies['標(biāo)題'].to_list())
?這個函數(shù)的作用是選出第一個列表特有的元素,兩個列表共有的元素,第二個列表特有的元素。
若這個電影在票房前20里面,也在我們的評價指標(biāo)前20里面,那么就是好電影。若它在在票房前20里面,不在我們的評價指標(biāo)前20里面,那可能就是票價過高的“水分電影”。
print(f'票價過高的電影:{票價過高的電影},\n\n確實是好電影:{確實是好電影},\n\n低估的電影:{被低估的電影}')
票價過高的電影:['八佰', '我和我的家鄉(xiāng)', '獨行月球', '流浪地球2'],emmmm
這幾個電影,我都沒怎么深入了解就不評價了......
詞云圖
加個詞云圖吧,好看些:
先自定義一個隨機顏色函數(shù):
import numpy as np
def randomcolor():
colorArr = ['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
color ="#"+''.join([np.random.choice(colorArr) for i in range(6)])
return color
[randomcolor() for i in range(3)]
然后畫詞云圖:這里用了墊圖掩碼,原始圖片形狀為這樣的六角星:——?
from wordcloud import WordCloud
from matplotlib import colors
from imageio.v2 import imread #形狀設(shè)置
mask = imread('詞云.png')
# 將'標(biāo)題'和'票房'列合并為字典,以便生成詞云圖
word_freq = dict(zip(movies['標(biāo)題'], movies['票房(億)']))
color_list=[randomcolor() for i in range(20)]
wordcloud = WordCloud(width=1000, height=500, background_color='white',font_path='simhei.ttf',
max_words=50, max_font_size=50,random_state=42,mask = mask,
colormap=colors.ListedColormap(color_list)).generate_from_frequencies(word_freq)
plt.figure(figsize=(10, 5),dpi=256)
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()
總結(jié)
本次演示了從數(shù)據(jù)爬蟲獲取,到清洗整理,再到計算和可視化分析的全流程,再多加點圖和文字分析角度,加點模型,作為大多數(shù)的本科生的論文算是差不多的工作量了。文章來源:http://www.zghlxwxcb.cn/news/detail-713878.html
創(chuàng)作不易,看官覺得寫得還不錯的話點個關(guān)注和贊吧,本人會持續(xù)更新python數(shù)據(jù)分析領(lǐng)域的代碼文章~(需要定制代碼可私信)文章來源地址http://www.zghlxwxcb.cn/news/detail-713878.html
到了這里,關(guān)于Python數(shù)據(jù)分析案例30——中國高票房電影分析(爬蟲獲取數(shù)據(jù)及分析可視化全流程)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!