技术简书电影院用python做些有趣的事

(大)数据分析:豆瓣电影分析报告【1】

2016-10-11  本文已影响5565人  mrlevo520

Python 2.7
IDE Pycharm 5.0.3
PyExcelerator 0.6.4a
可视化 Plotly


前言

在上次爬完豆瓣的东西后,感觉锻(zhuang)炼(yi)能(xia)力(bi)之外,貌似并没有实际用处,说实话,我宁可去网页一页页浏览电影也不愿意面对这苍白的文字。所以,分析一下比较好。


目的

根据豆瓣所有的电影,分析各国各地区各类别时间年份评分数量等各个参数之间的联系,大体上进行分析。我会说谎,但是数据不会。


豆瓣的电影世界

这次爬取的电影总共6323部,因为豆瓣没有全部电影的列表,所以爬取的时候按照每类进行爬取,之后整合,去重,所剩参评影片4007部。(算法略简陋,最后列表大概有十部左右未爬取,但是综合各类别包含关系,误差会变得很小)

简单介绍下情况后,根据所需要的对比数据再进行再分割的处理,这个具体代码片段详见后半部分。好了,接下来轮到plotly大显身手的时候了。


今天要分析什么?

主要比较世界电影和中国,以及中国大陆和中国港台电影之间的差别,分析各参数之间是否存在关联性及对评分产生的影响;数据来源于豆瓣,我对评分不做主观表现,我只对数据进行分析展示,能力偏弱,但图像不弱。


能从年份&评分中看出点什么?

首先放上一张堪忧的世界电影好评趋势图

豆瓣世界电影的评分均值趋势 世界电影的评分Box箱线图趋势 豆瓣世界的均值图趋势

补充箱线图概念:(@ZhangHongju--箱线图(数据分布)分析 )

箱线图描述

世界电影趋势这样,那么中国呢?

豆瓣中国电影评分均值图趋势 中国评分均值和全世界之间的比较

接下来看下大陆和港台的电影趋势

豆瓣中国大陆港台的box图趋势 这里写图片描述

把时间轴推移到二十世纪八十年代

豆瓣中国大陆港台的box图趋势放大图1980-2000 豆瓣中国大陆港台的均值线趋势放大图1980-2000

把时间轴推移到近十余年

豆瓣中国大陆港台评分均值图趋势放大图2002-2016

豆瓣中国大陆港台的box图趋势放大图2002-2016

豆瓣中国大陆港台的box图趋势放大图2002-2016

对比近十余年同期世界电影

世界电影与中国电影均值箱线图2002-2016

再来看一下上世纪八十年代世界其他电影进展

上世纪八十年代同期对比 上世纪八十年代同期对比

影评数和年份又有什么关系呢?

全世界和中国电影影评数对比 中港电影产量对比 评分倒数几位

所以回到上一个话题,就是电影评论数和年份的关系,一个原因就是拍的片多了,评论会相应上升,但是,这些求得都是均值,所以数量而言并不是非常重要,我!觉!得!是!烂片太多!吐槽也越发严重!!!!!但看着烂片吐槽我赶脚着还是很有意思的哈哈

补充一张图:类型和评论数的关系

类型和评论数的关系 中国的西部电影 狗带

脑洞1:年份和时长有没有关系呢?

中国大陆电影时长

中国大陆电影时长 港台和大陆时长对比

吓得我把世界电影时长拿出来看一下

中国与世界电影时长对比 中国与世界电影时长对比近五年

脑洞2:时长不会和评分有关吧?

时长和评分

时长和评分

时长和类型探索

时长和类型对比

类型&评分分析

全世界类型及评分

全世界类型评分
超级八Super8,6.4,27856,科幻/悬疑/惊悚/儿童,美国,英语,2011/6/10,112

所以,这个标签是不是乱贴的呢,还是主演是孩子就是儿童电影呢,当然不是啦,反正我是没搞懂儿童电影和动画电影实质区别,动画电影有些并不适合儿童呢(脑补);


世界电影时长&类型&评分探索--最长时长

时长排名前五的类型

大陆和港台的时长&评分及类型分布--最长时长

大陆和港台的时长&评分及类型分布

大陆和港台的时长&评分及类型分布--时长最短

大陆和港台的时长&评分及类型分布

中国大陆和中国港台类型和时长

中国大陆和中国港台类型和时长

时长&年份&评分炫酷看下

中国大陆时长&评分&年份三维分布

中国大陆时长&评分&年份三维分布

中国港台时长&评分&年份三维分布

中国港台时长&评分&年份三维分布

脑洞3:标签数目大家都是怎样的呢?

这个大家可能没注意,但是经过我分析(凑巧)发现,中国和世界的标签数目都是不一样的呢,差别还挺大的呢,还特么会影响评分呢!!(科幻/恐怖 这样算两个标签)

全世界的类别标签数目比例

全世界的类别标签数目比例

中国的类型标签数目比例

中国的类型标签数目比例

美国的类型标签数目比例

美国的类型标签数目比例

类别和词频

类别和词频

标签数和评分的关系

标签数和评分的关系 厉害了我的哥

末世纪爆潮 95年的科幻片,有空我得去看看集成科幻动作悬疑惊悚犯罪音乐奇幻的电影到底是个啥


mdzz

接下来要分析什么?

时间间隔有点长,我脑子差不多糊了,还有什么想知道的,相分析的请留言,可能会得出很有意思结论呢,搞不好还能被大导演看到然后走上人生巅峰赢取白富美呢

请大家开脑洞,我来帮你验证你的想法

福利环节

最后奉上豆瓣评分9分以上并且评论超过25万的不看就浪费生命系列电影。

TOP27

还有豆瓣评分6分以下并且有25k人忍着被侮辱的心灵写下影评,看了就浪费生命系列电影。

-TOP21

BTW-祖国总算为我们挣了口气呢~话说我赶脚独立日还是挺好看的啊0.0


好了,接下来就是程序员世界了


程序实现部分


douban_Crawl_Parts codes

代码贴了太长,需要的请下载[源码下载][1]
[1]: http://download.csdn.net/detail/mrlevo520/9650050

注意:原始代码我基本不怎么用,但是能用;对于类别的连续爬取,其实写个循环就可以了,我再爬电视剧的事后才想到,然后在之后的写入txt也好,写入excel也好,都是用了批量处理的代码,这样就不用查岗了,要知道,一个类别460部电影,即使用静态爬也爬了我25分钟,我还得看着它,爬完一类爬下一类。

内容格式:

殿下,这是利息!殿、利息でござる!  7.2  579  喜剧  日本  日语  2016-05-14  129

代码格式爬取形式:

操作形式

数据清洗过程

*** -去重:***因为我爬十六个种类全部爬完,然后再聚合起来,其中肯定有重合部分,所以使用set函数去重,当然,你会发现,set函数也无法完全去重,因为爬的时候,评论数目还在变化,只要有一项不同,set就无法去重,结果还是excel直接去重。

爬取的电影和存储

- 格式规范化:因为使用plotly展现图形,所以最好的方式就是将其写成excel的,至于怎么写,我下面有代码。

*** - 缺失数据处理:***对于此类型数据,我的方法是剔除,当然我用的是最暴力的方法,剔除之后肯定不会对分析有点影响,但是这样的电影很少。比如说各种这样的电影,只要主要信息都在,我还是会爬取的,主要信息是指殿下,这是利息!殿、利息でござる! 7.2 579 喜剧 日本 日语 2016-05-14 129名字,评分,评论数,类型,国家,语言,时间,时长八个参数。

这里写图片描述

放上一个标准页面:

这里写图片描述

douban_Analysis_Parts codes

#计算总标签数,以及各类所占比例
import re
dicttype = {}
def TypeCount(line):
    line = re.sub("\t",",",line)
    line = line.split(",")
    typeline = line[3]
    typelines = typeline.split("/")

    for i in typelines:
        if i not in dicttype:dicttype[i]=0
        dicttype[i] +=1
    return dicttype

#测试的line格式,中间是tab键隔开的,制表符
#line = "诺斯费拉图Nosferatu/eineSymphoniedesGrauens 8.3 4202    恐怖/科幻   德国  德语  1922/3/4    94"
f = open("C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\ALLMovie.txt")
fr = open("C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\ALLMovie_typenum.txt","a")
k=0
lines = f.readlines()
for line in lines:
    k +=1
    dicttype = TypeCount(line)

x=0
for j in dicttype.values():
    x +=j
print "参评影片总数:%s;所有标签总数:%s"%(k,x)
for i in dicttype:
    print "%s:%s;类型所占比例:%.2f;标签词频比例:%.2f"%(i,dicttype[i],(dicttype[i])/(k*0.01),(dicttype[i])/(x*0.01))
    fr.write("%s,%s,%.2f,%.2f"%(i,dicttype[i],(dicttype[i])/(k*0.01),(dicttype[i])/(x*0.01)))
    fr.write('\n')

最后得出如下记录,存入txt或者excel中就可以后续绘图处理了:

这里写图片描述
# 获取各个种类电影及存储分割,这里是对全部电影的切割,单独国家电影种类切割同理
def Write2txt(line,txtname):
    fr = open(txtname,"a")
    if line :
        fr.write(line)
        fr.write("\n")
        fr.close()
readpath = "C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\ALLMovie.txt"
writepath = "C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\%s.txt"
typelist = ["犯罪","动作","歌舞","家庭","鬼怪","剧情","音乐","武侠","运动","战争","黑色电影","传记","历史","情色","儿童","悬疑","灾难","爱情","冒险","奇幻","科幻","古装","惊悚","恐怖","喜剧","动画","同性","西部"]
f = open(readpath)
lines = f.readlines()
for line in lines:
    line = line.strip() # 记得去除空格,不然输出存在空格行
    lineSplit = line.split("\t")
    for type1 in typelist:
        if type1 in lineSplit[3]:# 列表第四个为种类
            lineCsv = line.replace("\t",",").strip()
            Write2txt(lineCsv,writepath%(type1.decode('utf-8')))
            
各类电影分割存储

上述的式子只需要略微修改参数即可用于分类各个国家的各电影种类并单独存储,接下来是将存储在txt中的数据批量转化存储在excel中(有人会说为啥不一次性写入excel中,因为我懒啊,哈哈,其实,模块化我感觉挺好用,要不是为了能在plotly上用,我才懒得存excel)

# 以"中国大陆爱情.txt"的txt文件为例,其中存在txt中的格式为:苏州河,7.8,80931,剧情/爱情,中国大陆,汉语普通话,2000,83
from pyExcelerator import *
readpath = "C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\%s.txt"
writepath = "C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\%s.xls"
typelist = ["犯罪","动作","歌舞","家庭","鬼怪","剧情","音乐","武侠","运动","战争","黑色电影","传记","历史","情色","儿童","悬疑","灾难","爱情","冒险","奇幻","科幻","古装","惊悚","恐怖","喜剧","动画","同性","西部"]
for type1 in typelist:
    try:
        f = open(readpath%(u"中国大陆"+type1.decode('utf-8')))
        lines = f.readlines()
        w = Workbook()
        sheet1 = w.add_sheet("Sheet1")
        i = 0
        for line in lines:
            linesplist = line.split(",")
            j = 0
            for linesp in linesplist:
                sheet1.write(i,j,linesp.strip().decode('utf-8')) # 需要转化成unicode才能存储
                j += 1
            i +=1
        w.save(writepath%(u"中国大陆"+type1.decode('utf-8')+u"xls")) # 解码成unicode码
    except:
        print "No type: %s"%type1

# 分割月份单独存储
def Write2txt(line,txtname):
    fr = open(txtname,"a")
    if line :
        fr.write(line)
        fr.write("\n")
        fr.close()
readpath = "C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\AllOverTheWorld_alltype_splite\\%s.txt"
writepath = "C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\AllOverTheWorld_alltype_splite\\%s.txt"
typelist = ["犯罪","动作","歌舞","家庭","鬼怪","剧情","音乐","武侠","运动","战争","黑色电影","传记","历史","情色","儿童","悬疑","灾难","爱情","冒险","奇幻","科幻","古装","惊悚","恐怖","喜剧","动画","同性","西部"]
    for typelist1 in typelist:
        try:
            f = open(readpath%(u"港台"+typelist1.decode('utf-8')))
            lines = f.readlines()
            for line in lines:
                line = line.strip() # 记得去除空格,不然输出存在空格行
                lineSplit = line.split(",")
                try:
                    newline ="%s,%s,%s,%s,%s,%s"%(lineSplit[1],lineSplit[2],lineSplit[4],lineSplit[5],lineSplit[6].split("/")[1],lineSplit[7])
                    Write2txt(newline,writepath%(u"港台"+typelist1.decode('utf-8')+u"OnlyMonth"))
                except:
                    print "Only year No month:%s"%lineSplit[0]
        except:
            print "No Type :%s"%typelist1

对照一下,粗略看一下有没有处理正确,ok,没什么错误。

对照原数据
# 计算不同年份的评分,评论数,时长平均值并存储excel
from pyExcelerator import *
def Write2txt(line,txtname):
    fr = open(txtname,"a")
    if line :
        fr.write(line)
        fr.write("\n")
        fr.close()
def txt2excel():
        try:
            f = open("C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\ChinaAllmovieOnlyYearWithAverage.txt")
            lines = f.readlines()
            w = Workbook()
            sheet1 = w.add_sheet("Sheet1")
            i = 0
            for line in lines:
                linesplist = line.split(",")
                j = 0
                for linesp in linesplist:
                    sheet1.write(i,j,linesp.strip().decode('utf-8')) # 需要转化成unicode才能存储
                    j += 1
                i +=1
            w.save("C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\ChinaAllmovieOnlyYearWithAverage.xls") # 解码成unicode码
        except:
            print "Something wrong"
path = "C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\ChinaAllmovieOnlyYear.txt"

lines = open(path).readlines()
for years in range(1900,2017):
    TotalStar,TotalComment,TotalTime,i = 0.0,0.0,0.0,0.0
    for line in lines:
        lineSplit = line.split("\t")
        if lineSplit[6] == str(years):
            TotalStar +=float(lineSplit[1])
            TotalComment +=float(lineSplit[2])
            TotalTime +=float(lineSplit[7])
            i +=1
    try:
        if i>4: # 设置影片数目阈值
            print "%s:Average star %s"%(years,TotalStar/i)
            print "%s:Average comment %s"%(years,TotalComment/i)
            print "%s:Average time %s"%(years,TotalTime/i)
            print "%s: movieNum %s"%(years,i)
            writeline = "%s,%s,%s,%s,%s"%(years,i,TotalStar/i,TotalComment/i,TotalTime/i)
            Write2txt(writeline,"C:\\Users\\MrLevo\\PycharmProjects\\test\\M&TCleanData\\ChinaAllmovieOnlyYearWithAverage.txt")
            txt2excel()
    except:
        print "No movie this year %s"%years

之后效果应该是这样的

1981:Average star 7.6125
1981:Average comment 2312.25
1981:Average time 97.0
1981:movieNum 8.0
...

最后

总结这一次的小项目, 经历了数据的收集爬取-数据的清洗规范-数据存储-数据可视化-数据分析,虽然对大神来说非常浅显而没有太多价值,但这也是我这种菜鸡必须需要经历的一步,完完整整,虽有各种波折,所幸全部解决,从中也学到很多,以后编代码思考也会成熟,共勉各位。


撰写记录

  1. 2016.10.2-19:49-第一次撰写
  2. 2016.10.4-21:12-第二次撰写
  3. 2016.10.5-11:21-第三次撰写
  4. 2016.10.7-22:21-第四次撰写
  5. 2016.10.10-18:10-第五次撰写

致谢

python对excel的读取操作
@MrLevo520--Python自定义豆瓣电影种类,排行,点评的爬取与存储(基础)
@MrLevo520--Python自定义豆瓣电影种类,排行,点评的爬取与存储(初级)
@MrLevo520--Python自定义豆瓣电影种类,排行,点评的爬取与存储(进阶上)
@MrLevo520--Python自定义豆瓣电影种类,排行,点评的爬取与存储(进阶下)
@MrLevo520--Python自定义豆瓣电影种类,排行,点评的爬取与存储(高阶上)

上一篇下一篇

猜你喜欢

热点阅读