运行在jupyter notebook环境
)
-
-
- 一、 数据收集、加载数据 并查看
-
- 1.1 收集数据 爬虫详细过程请点击
- 1.2 抓取数据问题:
- 1.3 加载数据并查看:
-
- 二、数据合并(将这两个互有缺失值的DataFrame合并)
- 三、数据清洗(消耗40%时间)
-
- 3.1 查看所有数据 : 数据去重 df.duplicated()
- 3.2 数据格式,内容清洗
- 3.2.1 国家(地区)内容清洗
- 3.2.2 电影类型genre(类似于区域内容清洗)
- 3.2.3 电影语言:
- 3.2.4 导演
- 3.2.5 演员(cast)
- 3.2.5 时长(movie_duration)
- 3.2.6 电影标记(tags)
- 3.2.7 上映时间(init_year)
- 3.2 缺失值检查与查看
- 3.1 查看所有数据 : 数据去重 df.duplicated()
-
- 四、数据统计与分析
-
- 4.1 数值型列的数据统计
- 4.2 电影排名分析
- 4.3 按评分-top10分析
- 4.4 上榜次数统计分析
-
- 五、数据分析与可视化展示(matplotlib)
-
- 5.1 matplotlib 可视化包基本环境配置
- 5.2 评分 与排名
- 5.3 评论人数 与排名
- 5.4 电影时长 与排名
- 5.5 上映年份 与排名
- 5.6 国家/地区 与排名
- 5.7 语言 与排名
- 5.8 电影类型 与排名
- 5.9 电影标签热度词云统计 与排名
-
- 六、数据分析与可视化展示
-
- 6.1 安装pyecharts 可视化基本环境配置
- 6.2 电影类型-排名
- 6.3 按评分占比统计
- 6.4 国家地区-排名
-
- 一、 数据收集、加载数据 并查看
-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pyecharts import Bar,Line,Pie
from pandas import DataFrame,Series
一、 数据收集、加载数据 并查看
1.1 收集数据 爬虫详细过程请点击
抓取排名,电影名,导演,主演,上映日期,制片国家/地区,类型。 评分,评论数量,一句话评价,已经电影链接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
_numcomme
nt_numlang
uagedirector cast movie_
durationtags 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.dtypesdf['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'].tolistline = Line('国家地区电影排名') line.add('国家',attr,v1,mark_point = ['min','max'],is_smooth=True,mark_line['max','average']) line.render_notebook()