1、读取数据,以“豆瓣评分”为标准,看看电影评分分布,及烂片情况
要求:
① 读取数据“moviedata.xlsx”
② 查看“豆瓣评分”数据分布,绘制直方图、箱型图
③ 判断“豆瓣评”数据的“烂片标准” → 这里以上四分位数(该样本中所有数值由小到大排列后第25%的数字)评分为“烂片标准”
④ 筛选出烂片数据,并做排名,找到TOP20
提示:
① 读取数据之后去除缺失值
② score = (豆瓣评分 + imdb评分)/2
2、什么题材的电影烂片最多?
要求:
① 按照“类型”字段分类,筛选不同电影属于什么题材
② 整理数据,按照“题材”汇总,查看不同题材的烂片比例,并选取TOP20
③ 将得到的题材烂片比例TOP20制作散点图 → 横坐标为“题材”类型,纵坐标为烂片比例,点大小为样本数量
** 用bokeh制图
** 按照烂片比例做降序排列
提示:
① 删除“类型”字段空值的数据
② 由于一个电影“类型”会有多个,这里需要将一个电影每个“类型”都识别出来,在统计某个题材时都需要计算,例如:
如果一个电影的类型为:“喜剧/爱情”,则在计算“喜剧”、“爱情”题材的烂片比例时,都需要将该电影算上
③ 注意类型字段中,要删除空格字符
④ bokeh图设置点大小,这里通过开方减小数据差距 → size = count**0.5*系数
3、和什么国家合拍更可能产生烂片?
要求:
① 按照“制片国家/地区”字段分类,筛选不同电影的制片地
② 整理数据,按照“题材”汇总,查看不同题材的烂片比例,并选取TOP20
提示:
① 删除“制片国家/地区”字段空值的数据
② 删除“制片国家/地区”中不包括“中国大陆”的数据
③ 制片地删除“中国大陆”、“中国”、“台湾”、“香港”等噪音数据
④ 筛选合作电影大于等于3部以上的国家
4、卡司数量是否和烂片有关?
要求:
① 计算每部电影的主演人数
② 按照主演人数分类,并统计烂片率
** 分类:‘1-2人’,‘3-4人’,‘5-6人’,‘7-9人’,‘10以上’
③ 查看烂片比例最高的演员TOP20
提示:
① 通过“主演”字段内做分列来计算主演人数
② 需要分别统计不同主演人数的电影数量及烂片数量,再计算烂片比例
③ 这里可以按照明星再查看一下他们的烂片率,比如:吴亦凡、杨幂、黄晓明、甄子丹、刘亦菲、范冰冰…
5、不同导演每年电影产量情况是如何的?
要求:
① 通过“上映日期”筛选出每个电影的上映年份
② 查看不同导演的烂片比例、这里去除掉拍过10次电影以下的导演
③ 查看不同导演每年的电影产量制作散点图 → 横坐标为年份,纵坐标为每年电影平均分,点大小为该年电影数量
** 用bokeh制图
** 横坐标限定为2007-2017年
** 绘制散点图只需要用产出过烂片的导演数据
提示:
① 注意要删除“上映日期”中的空格字符
② 绘制图表时,分开建立数据绘制
豆瓣国产烂片解析项目更多偏向于数据清洗和数据整合,相对简单一些,只需要处理后进行简单的描述总结即可。数据来源于2017年采集的豆瓣数据。
1 导入模块,读取数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
from bokeh.plotting import figure,show,output_file
from bokeh.models import ColumnDataSource,HoverTool
import os
os.chdir('/Users/eleven/Desktop/python/项目11国产烂片深度揭秘/')
df = pd.read_excel('moviedata.xlsx')
df = df[df['豆瓣评分']>0]
#读取数据“moviedata.xlsx”
2 以“豆瓣评分”为标准,查看评分分布及烂片情况
这里先简单查看数据分布,绘制直方图、箱型图。
print(df['豆瓣评分'].describe())
#查看“豆瓣评分”数据分布
fig = plt.figure(figsize = (12,8))
plt.subplots_adjust(hspace = 0.5)
ax1 = fig.add_subplot(2,1,1)
df['豆瓣评分'].plot.hist(bins = 20,color = 'green',histtype = 'bar',alpha = 0.8)
plt.title('豆瓣评分数据分布-直方图')
ax2 = fig.add_subplot(2,1,2)
df['豆瓣评分'].plot.box(vert = False,grid = True)
plt.title('豆瓣评分数据分布-箱型图')
#绘制直方图、箱型图
数据一共有2306条。具体情况如下:
count 2306.000000
mean 5.604250
std 1.595514
min 2.100000
25% 4.300000
50% 5.700000
75% 6.800000
max 9.300000
直方图和箱型图如图,初步判断大致符合正态分布:
这里可以简单的做一个ks检验,判断是否符合正态分布。
from scipy import stats
u = df['豆瓣评分'].mean()
std = df['豆瓣评分'].std()
print(stats.kstest(df['豆瓣评分'],'norm',(u,std)))
#ks检验
#判断是否符合正态分布,p值大于0.05,为正态分布
结果:KstestResult(statistic=0.06149387008971552>0.05, pvalue=5.050684159790819e-08)。符合正态分布。
查看烂片情况,我们以样本数据上四分位数4.3为烂片评判标准,筛选出烂片数据,并做排名,找到TOP20
data_lp = df[df['豆瓣评分']<4.3].reset_index()
top20_lp = data_lp[['电影名称','豆瓣评分','主演','导演']].sort_values(by = '豆瓣评分').iloc[:20].reset_index()
del top20_lp['index']
3 什么题材的电影烂片最多
题材其实和数据里的“类型”是相对应的。在这里我们需要按照类型分类进行统计,计算出烂片比例。值得注意的是,有的电影不止属于一种类型,那在分类型计算的时候,需要都纳入所属类型进行统计。
(1)删除空值,筛选不同的题材类型
df2 = df[df['类型'].notnull()]
#删除“类型”字段空值的数据
typelst = []
for i in df2['类型'].str.replace(' ','').str.split('/'):#去除空格,用/分隔
typelst.extend(i)
typelst = list(set(typelst))
#筛选出不同的题材类型并去重
最后得到一共有35种题材。
(2)接下来可以进行统计了
可以先创建函数,筛选有指定类型的电影,计算符合条件的电影中的烂片数量和比例。接下来遍历题材列表即可。
def f1(data,typei):
dic_lp = {}
datai = data[data['类型'].str.contains(typei)]
lp_per_i = len(datai[datai['豆瓣评分']<4.3])/len(datai)
dic_lp['typename'] = typei
dic_lp['typecount'] = len(datai)
dic_lp['type_lp_per'] = lp_per_i
return(dic_lp)
#创建函数,计算不同题材的烂片比例
lst_type_lp = []
for i in typelst:
dici = f1(df2,i)
print(dici)
lst_type_lp.append(dici)
#遍历df2
df_type_lp = pd.DataFrame(lst_type_lp)
type_lp_top20 = df_type_lp.sort_values(by = 'type_lp_per',ascending = False).iloc[:20]
#选取TOP20
简单看看top10
(3)bokeh制图
# bokeh制图
type_lp_top20['size'] = type_lp_top20['typecount']**0.5*2
source = ColumnDataSource(data = type_lp_top20)
#创建数据
lst_type = type_lp_top20['typename'].tolist()
hover = HoverTool(tooltips = [('数据量','@typecount'),('烂片比例','@type_lp_per')])
#设置标签
p = figure(plot_width = 800,plot_height = 400,x_range = lst_type,
title = '不同题材烂片比例TOP20',
tools = [hover,'pan,reset,crosshair,zoom_in,zoom_out,box_select'])
p.circle(x = 'typename',y = 'type_lp_per',source = source,size = 'size',
line_color = 'black',line_dash = 'dashed',fill_color = 'blue',fill_alpha = 0.6)
#绘制散点图
p.xgrid.grid_line_dash = [10,4]
p.ygrid.grid_line_dash = [10,4]
show(p)
bokeh图设置点大小时,因为数据相差太大了,所以这里通过开方减小数据差距 → size = count**0.5*2
4 和什么国家合拍更可能产生烂片
(1)筛选不同电影的制片地
这里和上文操作类似,就是在’制片国家/地区’这个字段中,需要处理的地方多一些。因为是合拍,所以必须包括“中国大陆”。在生成localst后,“中国大陆”、“中国”、“台湾”、“香港”等噪音数据也需要删除,最后得到23个合拍国家。
df3 = df[df['制片国家/地区'].notnull()]#删除“制片国家/地区”字段空值的数据
df3 = df3[df3['制片国家/地区'].str.contains('中国大陆')]#删除“制片国家/地区”中不包括“中国大陆”的数据
df3 = df3[['电影名称','制片国家/地区','类型','豆瓣评分']]
localst = []
for i in df3['制片国家/地区'].str.replace(' ','').str.split('/'):
localst.extend(i)
localst = list(set(localst))
localst.remove('中国大陆')
localst.remove('中国')
localst.remove('台湾')
localst.remove('香港')#删除“中国大陆”、“中国”、“台湾”、“香港”等噪音数据
print(localst)
(2)按地区计算烂片比例,选取TOP20
这里的操作同上文,创建函数,遍历列表,进行计数。
def f2(data,loci):
dic_lp = {}
datai = data[data['制片国家/地区'].str.contains(loci)]
dic_lp['loc_count'] = len(datai)
dic_lp['loc_lp_per'] = len(datai[datai['豆瓣评分']<4.3])/len(datai)
dic_lp['loc'] = loci
return(dic_lp)
#创建函数,计算不同地区的烂片比例
lst_loc_lp = []
for i in localst:
dic = f2(df3,i)
lst_loc_lp.append(dic)
#遍历df3
lst_loc_lp = pd.DataFrame(lst_loc_lp)
lst_loc_lp = lst_loc_lp[lst_loc_lp['loc_count']>=3]#筛选合作电影大于等于3部以上的国家
top20_loc_lp = lst_loc_lp.sort_values(by = 'loc_lp_per',ascending = False).iloc[:20]
#选取TOP20
这里选了合拍3部以上电影的国家来查看烂片比例,一共只有9个国家。韩日拍片多,但是烂片比例还蛮低的。反而是美国拍得多烂的也多。
5 卡司数量是否和烂片有关
这里与上文不同的是,需要把主演人数进行归类。
(1)计算每部电影的主演人数
df4 = df[['电影名称','豆瓣评分','主演']]
df4['主演人数'] = df4['主演'].str.split('/').str.len()
#计算主演人数
df4_1 = df4[['主演人数','豆瓣评分']].groupby('主演人数').count()
df4_2 = df4[['主演人数','豆瓣评分']][df4['豆瓣评分']<4.3].groupby('主演人数').count()
#按主演人数分组,分别统计电影数量及烂片数量
df4_per = pd.merge(df4_1,df4_2,left_index = True,right_index = True)
df4_per.columns = ['电影数量','烂片数量']
#合并数据
(2)按照主演人数分类,并统计烂片率
df4_per.reset_index(inplace = True)
df4_per['主演人数分类'] = pd.cut(df4_per['主演人数'],
[0,2,4,6,9,50],
labels = ['1-2人','3-4人','5-6人','7-9人','10人及以上'])
df4_per2 = df4_per[['主演人数分类','电影数量','烂片数量']].groupby('主演人数分类').sum()
df4_per2['烂片率'] = df4_per2['烂片数量']/df4_per2['电影数量']
#按照主演人数分类,并统计烂片率
这个得出的结果是这样的。整体趋势是主演人数越多,烂片比率越高的。
(3)查看烂片比例最高的演员TOP20
这个思路不再赘述,与上文类似。
lst_role = []
lst_role1 = df[['电影名称','豆瓣评分','主演']][df['主演'].notnull()]
lst_role2 = lst_role1[lst_role1['豆瓣评分']<4.3]
for i in lst_role2['主演'].str.replace(' ','').str.split('/'):
lst_role.extend(i)
#取出所有电影的主演,并整理成列表
lst_role = list(set(lst_role))
#去重
def f3(data,rolei):
lst_role_per = {}
datai = data[data['主演'].str.contains(rolei)]
lst_role_per['主演'] = rolei
lst_role_per['烂片数量'] = len(datai[datai['豆瓣评分']<4.3])
lst_role_per['电影数量'] = len(datai)
return(lst_role_per)
#定义函数
lst_role_per2 = []
for i in lst_role:
m = f3(lst_role1,i)
if m['电影数量']>2:
lst_role_per2.append(m)
#遍历数据,得到超过三部戏的各个演员数据
lst_role_per2 = pd.DataFrame(lst_role_per2)
lst_role_per2['烂片比例'] = lst_role_per2['烂片数量']/lst_role_per2['电影数量']
#计算烂片比例
top20_role_lp = lst_role_per2.sort_values(by = '烂片比例',ascending = False).iloc[:20]
#筛选出烂片比例TOP20的演员
查看吴亦凡的烂片。
#m = input('请输入要查看的演员名字')
m = '吴亦凡'
lst = lst_role1[lst_role1['主演'].str.contains(m)]
per = lst_role_per2[lst_role_per2['主演'] == m]['烂片比例']
print(per,lst)
#查看特定演员的烂片率和参演列表
输出为:
0.666667
Name: 烂片比例, dtype: float64
电影名称 … 主演
38 爵迹 …
范冰冰 / 吴亦凡 / 陈学冬 / 陈伟霆 / 郭采洁 / 杨幂 / 林允 / 严屹宽 /…
57 致青春·原来你还在这里
吴亦凡 / 刘亦菲 / 金世佳 / 李沁 / 李梦 / 郝劭文 /陈燃 / 乔任梁
350 有一个地方只有我们知道 …
吴亦凡 / 王丽坤 / 徐静蕾 / 戈登·亚历山大 / 丛珊 / 张超 / 热依扎
6 不同导演每年电影产量情况如何
这里需要提取年份,按照不同导演每一年分组查看烂片产生情况。
(1)筛选出每个电影的上映年份
#通过“上映日期”筛选出每个电影的上映年份
df5 = df[['电影名称','上映日期','导演','豆瓣评分']][df['导演'].notnull()]
df5 = df5[df5['上映日期'].notnull()]
df5['上映年份'] = df5['上映日期'].str.replace(' ','').str[:4]
#删除“上映日期”中的空格字符,选取年份数据
df5 = df5[df5['上映年份'].str[0]=='2']
#删除不合理的数据
df5['上映年份'] = df5['上映年份'].astype(np.int)
df5 = df5[df5['上映年份']>2006]
df5 = df5[df5['上映年份']<2018]
#设置年份数据格式为int,上映年份局限于2007-2017
(2)查看不同导演的烂片比例
lst_dy = []
df5_1 = df5['导演'].str.replace(' ','').str.split('/')
for i in df5_1:
lst_dy.extend(i)
lst_dy = list(set(lst_dy))
#筛选出导演列表并去重
def f4(data,dyi):
dyi_count = {}
datai = df5[df5['导演'].str.contains(dyi)]
dyi_count['电影数'] = len(datai)
dyi_count['导演'] = dyi
dyi_count['烂片数量'] = len(datai[datai['豆瓣评分']<4.3])
return(dyi_count)
#定义函数,提取相关数据
dy_count = []
for i in lst_dy:
m = f4(df5,i)
if m['电影数'] > 9:
dy_count.append(m)
#遍历数据,选出拍片十次及以上的导演
dy_count = pd.DataFrame(dy_count)
dy_count['烂片比例'] = dy_count['烂片数量']/dy_count['电影数']
#查看不同导演的烂片比例
能满足条件的导演就很少了,毕竟十年十部以上效率很高哈。王晶烂片率真是不出所料,遥遥领先。
(3)计算导演每年的电影产量和平均分
要把导演数据拿到最开始的数据中,查看每年的产量和平均分。
lst_dy_lp = []
for i in lst_dy:
m = f4(df5,i)
if m['烂片数量']>0:
lst_dy_lp.append(m)
lst_dy_lp = pd.DataFrame(lst_dy_lp)
lst_dy_lp = lst_dy_lp['导演']
#确定产出过烂片的导演列表
def f5(data,dyi):
datai = data[data['导演'].str.contains(dyi)]
datai_count = datai[['上映年份','电影名称']].groupby('上映年份').count()
datai_mean = datai[['上映年份','豆瓣评分']].groupby('上映年份').mean()
data = pd.merge(datai_count,datai_mean,left_index = True,right_index = True)
data.columns = ['count','score']
data['size'] = data['count']*5
return(data)
#创建函数计算导演每年的电影产量和平均分
dy1 = f5(df5,'徐克')
dy2 = f5(df5,'王晶')
dy3 = f5(df5,'周伟')
#分别得到不同导演的数据
抽了三个烂片导演来看看bokeh制图的结果。
#bokeh制图
from bokeh.models.annotations import BoxAnnotation
#导入BoxAnnotation模块
hover = HoverTool(tooltips = [('该年电影平均分','@score'),
('该年电影数量','@count')])
#设置标签显示内容
p = figure(plot_width = 800,plot_height = 400,
title = '不同导演每年电影产量及平均分',
tools = [hover,'pan,zoom_in,zoom_out,crosshair,reset,save'])
source1 = ColumnDataSource(data = dy1)
p.circle(x = '上映年份',y = 'score',source = source1,size = 'size',legend = '徐克',fill_color = 'blue',fill_alpha = 0.6)
source2 = ColumnDataSource(data = dy2)
p.circle(x = '上映年份',y = 'score',source = source2,size = 'size',legend = '王晶',fill_color = 'red',fill_alpha = 0.6)
source3 = ColumnDataSource(data = dy3)
p.circle(x = '上映年份',y = 'score',source = source3,size = 'size',legend = '周伟',fill_color = 'yellow',fill_alpha = 0.6)
bg = BoxAnnotation(top=4.3,fill_alpha=0.1, fill_color='gray')
p.add_layout(bg)
#绘制烂片分隔区域
p.xgrid.grid_line_dash = [10,4]
p.ygrid.grid_line_dash = [10,4]
p.legend.location = "top_right"
# 设置其他参数
show(p)
结果如下。整体上来看这几位导演的电影评分呈现了越来越低的趋势,王晶其实偶尔会有点上扬的苗头。2014年开始三位导演拍片数量变少了,个中因素还可以通过与其他好口碑、普通口碑导演的情况进行对比分析,来看看是否受到了烂片拍太多的影响。
来源:https://blog.csdn.net/mangoday/article/details/100105983