美文网首页
Python大数据分析实战:豆瓣电影Top250中的最佳导演是谁

Python大数据分析实战:豆瓣电影Top250中的最佳导演是谁

作者: 木草zhg | 来源:发表于2019-05-07 01:57 被阅读0次

    在之前写的一篇文中中,已经采用urllib和BeautifulSoup的方式抓取了豆瓣电影TOP250的导演、编剧、演员、上映时间和地区、语言、短评数、影评数、多少人想看、多少人看过等22个字段。

    接下来,我们要对这些数据进行分析、挖掘,得到有价值的信息。

    下面是整个分析过程的思维导图:

    豆瓣电影Top250 的最佳导演.png

    一、获取数据

    先从csv文件中读取数据,观察一下:

    import pandas as pd
    
    df = pd.read_csv('exercise_douban_movie_Top250.csv')
    print(df.loc[0])
    

    输出为:

    QQ截图20190506164648.png
    print(df.loc[0, 'directors'])
    print(type(df.loc[0, 'directors']))
    

    输出为:

    ['弗兰克·德拉邦特']
    <class 'str'>
    

    通过观察可以发现,这些数据不能直接使用,有些数据的格式不符合后续操作的要求。

    比如:

    • 评分人数部分为字符串,且包含了汉字;
    • 多个字段的列表实际上被读取为字符串;
    • 百分比以字符串形式存储等
    • ……

    所以我们要对数据进行清洗,使得格式满足后续分析的要求。

    二、数据清洗

    # 2. 数据清洗,把数据转化成需要的格式
    #       评分人数:x人评价清洗为x,并调整为int类型
    df['score_cnt'] = df['score_cnt'].map(lambda x: int(x[:-3]))
    
    #       将字符串改为列表
    df_tmp = df[['directors', 'writers', 'actors', 'types', 'dates', 'play_location', 'rating_per', 'betters', 'tags']]
    df[['directors', 'writers', 'actors', 'types', 'dates', 'play_location', 'rating_per', 'betters', 'tags']] = \
        df_tmp.applymap(lambda x: eval(x))
    
    #       上映年份由字符串转换为int类型
    df['dates'] = df['dates'].map(lambda x: [int(i[:4]) for i in x])
    df['year'] = df['dates'].map(lambda x: min(x))
    
    #       五星比例/好评比例
    df['five_star_rate'] = df['rating_per'].map(lambda x: float(x[0][:-1])/100)
    df['favor_rate'] = df['rating_per'].map(lambda x:  (float(x[0][:-1])/100+ float(x[1][:-1])/100))
    
    #       比百分之多少同类电影好
    df['better_than'] = df['betters'].map(lambda x: sum([int(i.split('%')[0]) for i in x])/len(x))
    

    先进行一个简单的清洗,后续分析过程中有什么需要再进行添加。

    除了解决格式不符合要求的问题外,我们还额外创建了一些字段,比如五星比例、好多多少同类电影等,这些都是为后续分析提供帮助。

    三、进行分析

    先划定一个标准,那就是在TOP250中有不少于3部电影的导演,才可以参与最佳导演评选。

    先看一下一共有多少位导演:

    from functools import reduce
    
    # 消灭空格
    df['directors'] = df['directors'].map(lambda x: [i.strip() for i in x])
    
    # reduce迭代获取所有导演的列表
    director_list = reduce(lambda x, y: x + y, df.director)
    
    print(len(director_list))
    

    结果返回281,也就是说这250部影片有281位导演,存在联合执导的情况。那我们接着看一下影片数量大于3部的有哪些导演:

    from collections import Counter
    
    dire_counter = Counter(director_list)
    dire_counter = sorted(dire_counter.items(), key=lambda x: x[1], reverse=True)
    top_directors = list(filter(lambda x: x[1] >= 3, dire_counter))
    print(top_directors)
    

    输出为:

    [('宫崎骏', 7),
     ('克里斯托弗·诺兰', 7),
     ('史蒂文·斯皮尔伯格', 6),
     ('王家卫', 5),
     ('李安', 4),
     ('大卫·芬奇', 4),
     ('詹姆斯·卡梅隆', 3),
     ('朱塞佩·托纳多雷', 3),
     ('刘镇伟', 3),
     ('弗朗西斯·福特·科波拉', 3),
     ('姜文', 3),
     ('彼得·杰克逊', 3),
     ('彼特·道格特', 3),
     ('昆汀·塔伦蒂诺', 3),
     ('理查德·林克莱特', 3),
     ('李·昂克里奇', 3),
     ('理查德·柯蒂斯', 3),
     ('吴宇森', 3),
     ('是枝裕和', 3)]
    

    可以看到宫崎骏和诺兰的电影数最多。

    但这样我们无法确定谁才是最佳导演,接下来我们用两种方法对他们进行排序

    • 以平均豆瓣评分来进行排序
    • 以平均榜单位置进行排序
    from collections import defaultdict
    
    top_dire_score = defaultdict(list)
    top_dire_ind = defaultdict(list)
    for name, cnt in top_directors:
        for index, row in df.iterrows():
            if name in row['director']:
                top_dire_score[name].append(row['score'])
                top_dire_ind[name].append(row['top_no'])
    print(top_dire_score)
    print(top_dire_ind)
    

    输出为:

    # 评分
    defaultdict(list,
                {'宫崎骏': [9.3, 9.1, 9.0, 8.9, 8.8, 8.8, 8.5],
                 '克里斯托弗·诺兰': [9.3, 9.2, 9.1, 8.8, 8.6, 8.6, 8.9],
                 '史蒂文·斯皮尔伯格': [9.5, 8.9, 8.8, 8.7, 8.6, 8.5],
                 '王家卫': [8.8, 8.7, 8.6, 8.6, 8.5],
                 '李安': [9.0, 9.1, 8.7, 8.8],
                 '大卫·芬奇': [9.0, 8.8, 8.8, 8.7],
                 '詹姆斯·卡梅隆': [9.3, 8.6, 8.6],
                 '朱塞佩·托纳多雷': [9.2, 9.1, 8.8],
                 '刘镇伟': [9.2, 8.9, 8.7],
                 '弗朗西斯·福特·科波拉': [9.2, 9.1, 8.8],
                 '姜文': [9.2, 8.7, 8.8],
                 '彼得·杰克逊': [9.1, 9.0, 8.9],
                 '彼特·道格特': [8.9, 8.6, 8.7],
                 '昆汀·塔伦蒂诺': [8.8, 8.6, 8.5],
                 '理查德·林克莱特': [8.7, 8.8, 8.8],
                 '李·昂克里奇': [8.6, 9.0, 8.8],
                 '理查德·柯蒂斯': [8.5, 8.7, 8.6],
                 '吴宇森': [8.6, 8.7, 8.4],
                 '是枝裕和': [9.1, 8.7, 8.8]})
    
    # 榜单位置           
    defaultdict(list,
                {'宫崎骏': [7, 19, 36, 43, 88, 112, 191],
                 '克里斯托弗·诺兰': [9, 18, 27, 65, 137, 145, 192],
                 '史蒂文·斯皮尔伯格': [8, 70, 83, 118, 171, 222],
                 '王家卫': [80, 91, 132, 159, 181],
                 '李安': [30, 54, 94, 131],
                 '大卫·芬奇': [35, 62, 64, 104],
                 '詹姆斯·卡梅隆': [6, 96, 210],
                 '朱塞佩·托纳多雷': [13, 29, 66],
                 '刘镇伟': [15, 38, 101],
                 '弗朗西斯·福特·科波拉': [17, 50, 155],
                 '姜文': [32, 69, 87],
                 '彼得·杰克逊': [33, 51, 52],
                 '彼特·道格特': [37, 127, 173],
                 '昆汀·塔伦蒂诺': [73, 174, 218],
                 '理查德·林克莱特': [105, 113, 217],
                 '李·昂克里奇': [127, 129, 158],
                 '理查德·柯蒂斯': [140, 154, 231],
                 '吴宇森': [141, 151, 223],
                 '是枝裕和': [153, 206, 208]})
    
    

    接下来我们求一下均值,并将入榜电影数作为一个权重加进去:

    from math import log2
    from math import sqrt
    rank_score = []
    rank_ind = []
    
    for name, scores in top_dire_score.items():
        rank_score.append([name, sum(scores) / len(scores) * sqrt(log2(len(scores)))])
    
    for name, indexes in top_dire_ind.items():
        rank_ind.append([name, sum(indexes) / sqrt(log2(len(scores))) /len(indexes)])
        
    rank_score = sorted(rank_score, key=lambda x: x[1], reverse=True)
    rank_ind = sorted(rank_ind, key=lambda x: x[1])
    print(rank_score[:10])
    print(rank_ind[:10])
    
    

    输出为:

    # 加权得分榜
    [['克里斯托弗·诺兰', 14.959967098817579],
     ['宫崎骏', 14.936031151459467],
     ['史蒂文·斯皮尔伯格', 14.202073072976324],
     ['王家卫', 13.165523290477429],
     ['李安', 12.586500705120548],
     ['大卫·芬奇', 12.480434687942564],
     ['朱塞佩·托纳多雷', 11.372541542166006],
     ['弗朗西斯·福特·科波拉', 11.372541542166006],
     ['彼得·杰克逊', 11.330576444224434],
     ['刘镇伟', 11.24664624834129]]
     
    # 加权位置榜
    [['朱塞佩·托纳多雷', 28.59519121510834],
     ['彼得·杰克逊', 36.008759307914204],
     ['刘镇伟', 40.774624510432254],
     ['姜文', 49.776814337410805],
     ['大卫·芬奇', 52.6230949444702],
     ['宫崎骏', 56.282598582118],
     ['弗朗西斯·福特·科波拉', 58.77900416438936],
     ['李安', 61.36051448241997],
     ['克里斯托弗·诺兰', 67.28947774031447],
     ['詹姆斯·卡梅隆', 82.60833017697963]]
    
    

    可以看到,在我们的加权得分算法下,诺兰以微弱优势胜出,夺得豆瓣最佳导演奖。然而在我们的加权榜单位置算法中,朱塞佩·托纳多雷的电影平均能获得更靠前的豆瓣排名,夺得桂冠,而宫崎骏和诺兰的排名则分列6、9位。

    上面两个排名呈现出不同的结果,但是我更倾向于第一个。因为评分使用的是连续的数据,而位置数据是离散的,榜首和末尾的数据差了249,但是它们的实际表现并没有那么大的差距。

    注意一点,这个排名数据可能会随着时间的推移而发生变化,因为电影的评分和排行榜会发生变化。

    我们将上述代码中的列名调整下就可以得到演员的榜单,这一部分可以后续作为练习进行尝试。

    总结

    上面虽然是一个小的例子,但是它是一个完整的大数据分析过程,涉及到数据的读取,数据清洗和数据分析。可以把这个作为一个入门实战,然后在此基础上进行扩展,比如分析一下,哪一类电影更受豆瓣用户欢迎,可以做出词云图,可以在现有基础上为用户推荐电影。

    参考资料:Python大数据分析实战:豆瓣人的电影口味重吗?

    相关文章

      网友评论

          本文标题:Python大数据分析实战:豆瓣电影Top250中的最佳导演是谁

          本文链接:https://www.haomeiwen.com/subject/gscsoqtx.html