-- coding: utf-8 --
"""
Created on Tue Oct 16 16:40:16 2018
项目 11 国产烂片深度揭秘
@author: peng.jiang1
"""
"""
Note:
1 在绘制hist 直方图时分组的依据?bins=? 经验?
2 在绘制 box 箱型图时 箱型图的向 水平还是立着? 参数vert=True 默认垂直
3 .str.contains('obj') 可以计算字符串中是否包含指定的字符, 如果需要选择不包含
某些字符时 可以结合bool做选择(推荐bool 选择)
4 DataFrame 字段中的字符串中有空格 可以使用替换为空 replace()
5 在DataFrame中操作值 一定先转str再使用方法
6 当DF的值为列表时 如何计算此列表的长度 直接調用.str.len()的方法
7 用来存储数据的变量不要一起赋值, 因为指向问题 内存地址一致,会覆盖
8 需要存储数据可以直接存在series 和Df中 即重新索引赋值
9 在绘制子图时 通过add_subplot()新增 无需变量名
"""
导入模块
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from bokeh.plotting import show, output_file, figure
from bokeh.models import ColumnDataSource, HoverTool
import warnings
warnings.filterwarnings('ignore')
自定函数
def get_info(path):
'''
统计数据的基本信息:
1 数据量
2 数据的columns
3 数据中的缺失值数量
返回:读取后的DataFrame
'''
data = pd.read_excel(path, sheet_name=0, header=0)
print('数据量:%d'%len(data))
print('数据字段:', data.columns.tolist())
print('缺失值量:%d'%len(data[data.isnull().values == True]))
return data
def graph_comment(data):
'''
绘制豆瓣评分的分布 -- 直方图 箱型图
'''
fig = plt.figure(figsize=(10, 8))
fig.add_subplot(211)
data['豆瓣评分'].dropna().plot(kind='hist', bins=25, color='green',
alpha=0.6, edgecolor='gray')
plt.grid(linestyle='--', color='gray', axis='y', alpha=0.5)
plt.title('豆瓣评分-直方图')
plt.tight_layout()
fig.add_subplot(212)
data['豆瓣评分'].dropna().plot(kind='box', vert=False)
plt.grid(linestyle='--', color='gray', axis='x', alpha=0.5)
plt.title('豆瓣评分-箱型图')
plt.tight_layout()
plt.savefig('豆瓣评分分布情况.jpg', dpi=500)
def data_type(data_lp, data):
'''
统计电影的类型
'''
# 得到烂片的类型数据
data_lp = data_lp['类型'].dropna().str.replace(' ', '').tolist()
lst_type = []
for i in data_lp:
lst_type.extend(i.split('/'))
s = pd.Series(lst_type, name='lp').value_counts()
lp_type = pd.DataFrame(s)
# 得到总片的类型数据
data = data[data['豆瓣评分'].isnull() == False]
data = data['类型'].dropna().str.replace(' ', '').tolist()
data_type = []
for i in data:
data_type.extend(i.split('/'))
s = pd.Series(data_type, name='sum').value_counts()
d_type = pd.DataFrame(s)
# 合并数据
result = pd.merge(d_type, lp_type, left_index=True, right_index=True,
how='right')
result['lp_per'] = result['lp'] / result['sum']
result.sort_values(by='lp_per', ascending=False, inplace=True)
return result
def circle_graph(data, title):
'''
使用bokeh绘制散点
'''
output_file(title + '.html') # 创建html文件
source = ColumnDataSource(data) # 构建bokeh数据
# 创建显示标签
hover = HoverTool(tooltips=[('数据量', '@lp'),
('烂片比例', '@lp_per')])
# 创建工具栏
tools = '''
box_select, reset, wheel_zoom, pan
'''
index = data.index.tolist()
fig = figure(x_range=index, plot_width=300, plot_height=300,
toolbar_location='above', tools=[hover, tools]) # 设置绘图空间
fig.circle(data.index, data['lp'],
line_color='black', line_alpha=0.7,
fill_color='red', fill_alpha=0.7,
size=data['lp_per'], source=source)
show(fig)
def data_state(data):
'''
计算中国和哪些国家合拍出烂片
'''
# 数据清洗
data = data[['制片国家/地区', '豆瓣评分']]
data.dropna(inplace=True)
data = data[data['制片国家/地区'].str.contains('中国大陆')] # 剔除不包含中国
# 删除"中国大陆 "“中国”、“台湾”、“香港”等噪音数据
data = data[data['制片国家/地区'].str.contains('台湾') == False]
data = data[data['制片国家/地区'].str.contains('香港') == False]
data = data[data['制片国家/地区'].str.contains('/') == True]
state_lp = data[data['豆瓣评分'] < score] # 筛选烂片国家
return data, state_lp
def state_count(state, state_lp):
'''
统计合作国家烂片率
'''
state_lp = state_lp['制片国家/地区'].str.replace(' ', '').tolist()
lst_state = []
for i in state_lp:
lst_state.extend(i.split('/'))
s = pd.Series(lst_state, name='lp').value_counts()
lp_type = pd.DataFrame(s)
# 得到总片的国家数据
state = state['制片国家/地区'].str.replace(' ', '').tolist()
data_state = []
for i in state:
data_state.extend(i.split('/'))
s = pd.Series(data_state, name='sum').value_counts()
d_type = pd.DataFrame(s)
result = pd.merge(d_type, lp_type, left_index=True, right_index=True,
how='left')
result['lp_per'] = result['lp'] / result['sum']
result.sort_values(by='lp_per', ascending=False, inplace=True)
return result
def player(data):
'''
统计影片的主演人数
'''
# 数据清洗
data = data[['电影名称', '主演', '豆瓣评分']]
data = data[data['电影名称'].duplicated() == False]
data = data[data['电影名称'].notnull() == True]
data = data[data['豆瓣评分'].notnull() == True]
data = data[data['主演'].notnull() == True]
# 计算总的数据
data['主演'] = data['主演'].str.replace(' ','').str.split('/')
data['num'] = data['主演'].str.len()
# 分組
bins = [0, 2, 4, 6, 9, 100]
data['cut'] = pd.cut(data['num'], bins)
result1 = data.groupby(by='cut')['电影名称'].count()
result1 = pd.DataFrame(result1)
# 计算烂片的数量
data_lp = data[data['豆瓣评分'] < score]
result2 = data_lp.groupby(by='cut')['电影名称'].count()
result2 = pd.DataFrame(result2)
result = pd.merge(result1, result2, how='left', left_index=True,
right_index=True)
result.columns =['影片总数', '烂片总数']
result['per'] = result['烂片总数'] / result['影片总数']
result['主演人数分类'] = ['1-2人', '3-4人', '5-6人', '7-9人', '10人以上']
result.set_index('主演人数分类', inplace=True)
return result
def star_lp_per(data, name):
'''
按名字查询烂片率
'''
# 数据清洗
data = data[['电影名称', '主演', '豆瓣评分']]
data = data[data['电影名称'].duplicated() == False]
data = data[data['电影名称'].notnull() == True]
data = data[data['豆瓣评分'].notnull() == True]
# 筛选数据
data1 = data[data['主演'].str.contains(name) == True] # 主演的电影
data2 = data1[data1['豆瓣评分'] < score]
print('%s的烂片率:%.2f'%(name, len(data2)/len(data1)))
print('烂片如下:')
print(data2)
def film_count(data):
'''
统计每年不同导演的产量
'''
# 数据清洗
data = data[['电影名称', '导演', '豆瓣评分', '上映日期']]
data = data[data['电影名称'].duplicated() == False]
data = data[data['电影名称'].notnull() == True]
data = data[data['豆瓣评分'].notnull() == True]
data = data[data['上映日期'].notnull() == True]
data = data[data['导演'].notnull() == True]
data['year'] = data['上映日期'].str.replace(' ', '').str[:4]
# 统计导演
lst = []
for i in data['导演'].str.replace(' ', '').tolist():
lst.extend(i.split('/'))
lst = list(set(lst))
# 按导演统计
s1 = pd.Series(name='count')
s2 = pd.Series(name='count')
for name in lst:
datai = data[data['导演'].str.contains(name) == True]
dataj = datai[datai['豆瓣评分'] < score]
s1[name] = len(datai)
s2[name] = len(dataj)
df1 = pd.DataFrame(s1)
df2 = pd.DataFrame(s2)
df = pd.merge(df1, df2, left_index=True, right_index=True, how='left')
df = df[df['count_x'] >= 10]
df['per'] = df['count_y']/df['count_x']
# 按年份和导演统计影片产量
data_year = pd.DataFrame(columns=['电影名称', '导演', '豆瓣评分', '上映日期'])
# 统计烂片导演
lst_lp = df[df['count_y'] !=0 ].index.tolist()
for name in lst_lp:
data_name = data[data['导演'].str.contains(name) == True]
data_name['导演'] = name
data_year = pd.concat([data_year, data_name])
result = data_year.groupby(by=['year', '导演'])['豆瓣评分'].agg({
'count':'count',
'mean':np.mean
})
result.reset_index(inplace=True)
return df, result
def bokeh_circle(data, title):
'''
使用bokeh绘制散点
'''
output_file(title + '.html') # 创建html文件
data.rename(columns={'导演':'dy'}, inplace=True)
data['color'] = 'gray'
data['color'][data['dy'] == '王晶'] = 'blue'
data['color'][data['dy'] == '周伟'] = 'yellow'
data['color'][data['dy'] == '徐克'] = 'red'
source = ColumnDataSource(data) # 构建bokeh数据
# 创建显示标签
hover = HoverTool(tooltips=[('电影评分均值', '@mean'),
('该年电影产量', '@count')])
# 创建工具栏
tools = '''
box_select, reset, wheel_zoom, pan
'''
fig = figure(plot_width=300, plot_height=300,
toolbar_location='above', tools=[hover, tools]) # 设置绘图空间
data1 = data[data['dy'] == '王晶']
fig.circle(data1['year'], data1['mean'],
line_color=data1['color'], line_alpha=0.7,
fill_color=data1['color'], fill_alpha=0.7,
size=data1['count'])
data1 = data[data['dy'] == '周伟']
fig.circle(data1['year'], data1['mean'],
line_color=data1['color'], line_alpha=0.7,
fill_color=data1['color'], fill_alpha=0.7,
size=data1['count'])
data1 = data[data['dy'] == '徐克']
fig.circle(data1['year'], data1['mean'],
line_color=data1['color'], line_alpha=0.7,
fill_color=data1['color'], fill_alpha=0.7,
size=data1['count'])
data1 = data[data['dy'] == '邓衍成']
fig.circle(data1['year'], data1['mean'],
line_color=data1['color'], line_alpha=0.7,
fill_color=data1['color'], fill_alpha=0.7,
size=data1['count'])
show(fig)
if name == 'main':
path = r'C:\Users\pj2063150\Desktop\项目\项目11国产烂片深度揭秘'
os.chdir(path)
# 1 以“豆瓣评分”为标准,看看电影评分分布,及烂片情况
data = get_info('moviedata.xlsx') # 查看并获取数据
#graph_comment(data)
score = data['豆瓣评分'].dropna().describe()['25%'] # 烂片标准评分
data_lp = data[data['豆瓣评分'] < score].sort_values(by='豆瓣评分') # 筛选烂片
# 2 分析什么题材电影烂片最多
# 创建数据
lst_type = data_type(data_lp, data)
lst_type['size'] = (lst_type['lp']**0.5)*2
#circle_graph(lst_type, '烂片题材情况-散点图') # 绘制图表
# 3 与什么国家合拍更可能产生烂片
state = data_state(data)[0]
state_lp = data_state(data)[1]
state_count(state, state_lp) # 计算合作国家的烂片率
# 4 卡司数量是否和烂片有关(主演人数)
player_num = player(data)
# 按明星查询烂片率
star_lp_per(data, '吴亦凡')
# 5 不同导演每年电影产量情况如何
data5 = film_count(data)
data5_dir = data5[0]
data5_year = data5[1]
# 绘制图表
bokeh_circle(data5_year, '不同导演每年电影产量及评分均值')
print('Finished!')