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

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

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

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

分析过程的思维导图

一、获取数据

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

import pandas as pd

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

输出为:

QQ截图20190506164648

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大数据分析实战:豆瓣人的电影口味重吗?

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值