10 月 23 - 25 日,QCon 上海站即将召开,现在购票,享9折优惠 了解详情
写点什么

以乐队的夏天为例,用 Python 分析投票数据,选出真正的乐队 TOP 5

  • 2019-10-10
  • 本文字数:5893 字

    阅读完需:约 19 分钟

以乐队的夏天为例,用Python分析投票数据,选出真正的乐队TOP 5

在周六的盛大 party 后,《乐队的夏天》终于顺利收官。这个燃爆了整个夏天的综艺是否是今年最火的综艺节目虽然不得而知,但是不可否认,将乐队和摇滚又重新带到了公众面前。


至少对于我,很感谢有这么一个节目,可以让我接触到不同类型的音乐,认识这么多优秀的乐队,知道坚持做自己喜欢的事是一件多么幸福的事。


在昨天的终结篇中,马东根据现场的投票,顺利颁发出了杀出重围的 5 只最高票乐队。


当然,每个人心中一定都有一只自己觉得最强的乐队,我也一样。所以,我决定爬取所有场次参赛歌曲的投票数据,用 python 进行一次分析。然后参考数据分析的结果,给出我心目中,或许更加公允的另外一份 Hot5 名单。


当然,我也希望这份分析结果能够解答我自己对于乐队的夏天的一些疑问,比如,痛仰乐队的我愿意为何表现不佳?一直被专业乐迷和其他乐队奉为偶像的海龟先生,为什么最终止步 5 强?


还有一些有趣的小结论,一起看看吧!

第一步:数据采集

数据分析数据分析,没有数据就没有分析。


网络上没有公开的详细得票、排名数据,只好自己整理了。首先购买爱奇艺会员,不然很长时间都消耗在广告上了。然后用 2 倍速播放(这么听歌还挺带感的),然后看到这一幕,按住锁屏和音量键+,咔嚓,数据收集到了!



最后手机相册就变成现在这样👇



最后再填到一个 Excel 表里面,数据就有啦!


它大概长这个样子👇



一共有 6 个 sheet,对应 6 场比赛,字段分别是:[场数, 出场顺序, 乐队, 歌曲, 超级乐迷得分, 专业乐迷得分, 大众乐迷得分, 总得分, 排名, 是否晋级下一轮]

第二步:读取数据

在读取数据之前,先导入分析的工具包


import pandas as pdimport numpy as npimport matplotlib.pyplot as plt
复制代码


为了显得有一点点审美,我用取色器取了乐队的夏天主 KV 上面的颜色,便于后面可视化来使用。



# 配置乐队的夏天主题色purple = (0.22,0.09,0.59) # 紫色yellow = (0.99,0.89,0.27) # 黄色green = (0.36,0.94,0.55) # 绿色blue = (0.06,0.24,0.78) # 蓝色red = (0.98,0.31,0.36) # 红色
复制代码


环境设置完了,第一步是导入数据


# 读取数据data1 = pd.read_excel('/.../乐队的夏天.xlsx','第一场')data2 = pd.read_excel('/.../乐队的夏天.xlsx','第二场两两PK赛')data3 = pd.read_excel('/.../乐队的夏天.xlsx','第三场累计积分赛')data4 = pd.read_excel('/.../乐队的夏天.xlsx','第四场复活赛')data5 = pd.read_excel('/.../乐队的夏天.xlsx','第五场9进7')data6 = pd.read_excel('/.../乐队的夏天.xlsx','第六场总决赛')
复制代码


观察一下数据吧。


# 观察数据data1.info()data1.head()
复制代码



以第一场的数据为例为例,可以看到字段和数据的行数,其中得分有(31-27=4)行数据为空,进入第三步。

第三步:数据清洗

竟然有空数据,先看看是怎么回事。


# 可以看到有四只乐队是没有得分和排名的,把他们列出来
data1[data1['总得分'].isnull()]
复制代码



所以其实是有 31 只乐队表演的,但这四只乐队因为被剪掉了,所以没有具体成绩的数据,怎么办呢,只好把你们删了。


data1 = data1.dropna(axis = 0)
复制代码


此外第六场的总票数还没有给出,也有一部分空值,但不影响分析这样就完成了,因为数据是自己手动录入的,所以其它没什么问题了,可以开始分析了。

第四步:数据分析

整体的分析思路遵循从整体到局部的顺序,分为乐队和歌曲两个部分,再细分超级乐迷,专业乐迷和大众乐迷三个角度。同时会展示乐队在每期比赛的排名升降情况。


另外由于每场比赛的总票数不同,不同评委票数比例不同,为了使得不同场次之间的得票数据具备可比性,需要用到两种数据标准化的方法,分别是:


  • Z_score 标准分

  • 0-1 normalization 归一分


Z_score 标准分的计算方法是用“(该乐队当场得分-当场所有乐队得分的平均数)/ 当场所有乐队得分的标准差”计算得到:


# 标准分函数定义def z_score_normalize(series):  mean = series.mean()  std_dv = series.std()  return series.apply(lambda x:(x - mean) / std_dv)  # 用循环的方式批量对每场比赛的得分做处理competition = [data1,data2,data3,data4,data5,data6]for period in competition:    period['超级乐迷得分_标准分'] =  z_score_normalize(period['超级乐迷得分'])    period['专业乐迷得分_标准分'] =  z_score_normalize(period['专业乐迷得分'])    period['大众乐迷得分_标准分'] =  z_score_normalize(period['大众乐迷得分'])    period['总得分_标准分'] =  z_score_normalize(period['总得分'])
复制代码


0-1 normalization 归一分的计算方法是用“乐队得票数/总票数”计算得到,也等于常说的得票率:


# 定义归一化的函数def normalize(series,x_max):    return series.apply(lambda x: x/x_max)# 对不同总分不同类别的得分应用归一化函数for data in [data1,data2,data5,data6]:    data['超级乐迷_归一分'] = normalize(data['超级乐迷得分'],50)data3['超级乐迷_归一分'] = normalize(data3['超级乐迷得分'],60)data4['超级乐迷_归一分'] = normalize(data4['超级乐迷得分'],40)for data in [data1,data2,data3,data4,data5,data6]:    data['专业乐迷_归一分'] = normalize(data['专业乐迷得分'],40)    for data in [data1,data2]:    data['大众乐迷_归一分'] = normalize(data['大众乐迷得分'],100)for data in [data3,data4,data5,data6]:    data['大众乐迷_归一分'] = normalize(data['大众乐迷得分'],360)
复制代码


做完上面两步,再把每场的数据拼成一个表,大功告成。(此处省略拼接代码)


total_score
复制代码


PART I :这些宝藏乐队你不应该错过!

首先我们分析乐队,通过 27 只乐队在目前 5 场比赛中所表演的曲目的总得分的标准分的平均分,来衡量乐队的整体表现。


这个数据首先反映乐队的歌在该场比赛中的表现,其次结合多场比赛歌曲的表现,体现乐队的整体成绩。


# 按照乐队这个标签分类计算,计算方式是平均值,计算字段是总得分_标准分,然后按照总得分_标准分排列total_score_mean = total_score.groupby(['乐队'])[['总得分_标准分']].mean().sort_values(    by = '总得分_标准分',ascending = False)total_score_mean
复制代码



然后把这个结果可视化看看。


# 对乐队总得分_标准分做可视化y = np.arange(len(total_score_mean.index))x = np.array(list(total_score_mean['总得分_标准分']))fig,ax = plt.subplots(figsize = (12,12))total_score_mean.plot.barh(ax=ax,alpha=0.7,title='27只乐队场均表现',color = 'g')for a,b in zip(x,y):    plt.text(a, b, '%.2f' % a, ha='center', va= 'center',fontsize=12)ax.grid(False)
复制代码



新裤子排名第一,这也是在意料之中,“生命因你而火热”,“花火”这几首歌在朋友圈都爆了,其他的像刺猬、九连真人、盘尼西林、旅行团、Click#15 都表现很稳定,在目前的晋级名单中。但有两支乐队比较奇怪,一个是一度被淘汰的痛仰乐队,竟然排在第二,另一个是一直在线,还把痛仰 PK 掉的面孔,排名甚至不在前 10。


# 把痛仰的成绩拉出来看一下 total_score[total_score['乐队'] == '痛仰乐队']
复制代码



“再见杰克”和“西湖”都在当轮比赛中取得非常突出的表现,但“我愿意”真的可惜了。


total_score[total_score['乐队'] == '面孔乐队']
复制代码



较于其他只表演了一场但排名中等的队伍,面孔因被“张三的歌”垫底,一举拖垮,也因此惨遭淘汰。


接下来我想研究,在超级乐迷、专业乐迷和大众乐迷各自眼里,哪些乐队是他们喜欢的,他们共同喜欢的,和差异很大的乐队分别是哪些?


# 代码逻辑和前面选总得分作为计算字段的逻辑一样,只不过这次选取单个群体得分作为指标super_score_mean = total_score.groupby(['乐队'])[['超级乐迷得分_标准分']].mean().sort_values(    by = '超级乐迷得分_标准分')pro_score_mean = total_score.groupby(['乐队'])[['专业乐迷得分_标准分']].mean().sort_values(    by = '专业乐迷得分_标准分')public_score_mean = total_score.groupby(['乐队'])[['大众乐迷得分_标准分']].mean().sort_values(    by = '大众乐迷得分_标准分')
复制代码


对前 5 的乐队进行数据可视化。


fig,ax = plt.subplots(1,3,figsize = (16,6))super_score_mean.tail(5).plot.barh(ax=ax[0],color = '#dc2624',alpha=0.7,title='超级乐迷心中TOP5',grid=False)pro_score_mean.tail(5).plot.barh(ax=ax[1],color = '#2b4750',alpha=0.7,title='专业乐迷心中TOP5',grid=False)public_score_mean.tail(5).plot.barh(ax=ax[2],color = '#649E7D',alpha=0.7,title='大众乐迷心中TOP5',grid=False)
复制代码



同时在三个群体中位列心目前五的乐队是:“新裤子”。


下面一起来读绕口令:


在超级乐迷心中前五,但不在专业乐迷心中的前五乐队是:


{‘海龟先生’, ‘盘尼西林’, ‘痛仰乐队’}


在超级乐迷心中前五,但不在大众乐迷心中的前五乐队是:


{‘Click#15’, ‘海龟先生’, ‘盘尼西林’}


在专业乐迷心中前五,但不在超级乐迷心中的前五乐队是:


{‘Mr.WooHoo’, ‘Mr.Miss’, ‘九连真人’}


在专业乐迷心中前五,但不在大众乐迷心中的前五乐队是:


{‘Mr.WooHoo’, ‘Mr.Miss’, ‘Click#15’}


在大众乐迷心中前五,但不在超级乐迷心中的前五乐队是:


{‘九连真人’, ‘葡萄不愤怒’, ‘刺猬’}


在大众乐迷心中前五,但不在专业乐迷心中的前五乐队是:


{‘刺猬’, ‘葡萄不愤怒’, ‘痛仰乐队’}

PART II :乐队的排名就像人生,它会起起落落落落落

接下来对比较熟悉的 9 只乐队的每期排名做可视化,直观地展现他们在每期表现的升降。



新裤子的发挥是较为稳定的,除了第三场上和 Cindy 合作的音乐形式较为新颖,让观众一时难以接受之外,在各个场次都获得非常靠前的成绩。同样稳定的还有九连真人,一直稳稳的在中间,此外第二场改编李宗盛大哥的凡人歌,现场炸裂,表现超出期待。


表现越来越好的有两只乐队:刺猬和 Click#15


刺猬可谓是低开高走,复活赛中凭借白日梦蓝稳稳防守住黑撒乐队的挑战,女神赛中和斯斯与帆的合作更是获得了全场最佳。Click#15 虽然在第二场和面孔的 PK 赛中被淘汰,但又杀了回来,而且第五场演绎 beyond 的碑面派对,首次赢得第一名。


另外面孔乐队的处境一直比较尴尬,看他们的音乐对这一代人确实存在一些隔阂。


最后还有我很喜欢的乐队,海龟先生。第一场比赛在 31 只乐队中位列第一,后面他们做了许多创意,还有想通过音乐表达自己的想法,可惜没有被 buy in.


对乐队的分析暂时告一段落,接下来看看歌曲。

PART III :如果你只有十首歌的时间,我建议你听这些歌

通过前面提到的归一化计算,可以得到以下数据



首先对数据整体有一个把握


# 看看数据整体的描述total_nor_score.describe()# 运用箱型图可以看到各组给分的分布,其中蓝线是平均分,圆圈是最小值fig,ax = plt.subplots(1,1,figsize = (8,4))total_nor_score.boxplot(ax = ax,grid=False)
复制代码




从上面的图和数据不难看出,超级乐迷给分的范围相对较高,也就是所谓的手松,而专业乐迷擅长给低分,最低的时候只给出了 20%比例的票,大众乐迷相对克制,最高分也仅仅给出了 93%的票,所谓的众口难调。总得分的平均数是 0.72,意味着所有歌曲平均下来能拿到 72%的票,也是挺不容易的。


再来看看,得票率前 10 的歌曲吧!


top10_songs = total_nor_score.sort_values(by = '总得分_归一分').tail(10)top10_songs.plot.barh(x='歌曲',y='总得分_归一分',color=purple)print('截止第六期,最受欢迎的10首歌分别是:',list(top10_songs['歌曲']))
复制代码



截止第六期,最受欢迎的 10 首歌分别是:


  • 夏日终曲

  • 凡人歌

  • How come u leave me like this

  • 生命因你而火热

  • 椑面派对

  • 西湖

  • 花火

  • Bye Bye

  • 公路之歌

  • 没有理想的人不伤心


下面看看在每组评委心目中前 10 的歌曲:


total_nor_score.sort_values(by = '超级乐迷_归一分').tail(10).plot.barh(x='歌曲',y='超级乐迷_归一分',color=red)total_nor_score.sort_values(by = '专业乐迷_归一分').tail(10).plot.barh(x='歌曲',y='专业乐迷_归一分',color=yellow)total_nor_score.sort_values(by = '大众乐迷_归一分').tail(10).plot.barh(x='歌曲',y='大众乐迷_归一分',color=green)
复制代码





超级乐迷最喜欢“Don’t break my heart”,专业乐迷和大众乐迷最喜欢“没有理想的人不伤心”。

PART IIII:灵魂拷问:“我愿意”为什么跳水?谁在不喜欢海龟先生?

整体回顾完了,最后单独分析两个问题。第一个是为什么“我愿意”这首歌表现不好呢?


total_nor_score[total_nor_score['歌曲'] == '我愿意']
复制代码



可以看到虽然在节目中,矛头似乎指向了专业乐迷,但实际上,专业乐迷给票的比例比大众乐迷是要高的,真正不喜欢的是大众乐迷,只给出了一半的票数。


第二个问题是,谁在不喜欢海龟先生?


total_nor_score_t = pd.merge(total_nor_score, total_score[['乐队','歌曲']], on='歌曲')total_nor_score_t[total_nor_score_t['乐队'] == '海龟先生']
复制代码



“咿呀呀”这首歌拖累了海龟的整体平均分,而在这首歌中,专业乐迷给票的比例是最低的。


看看每组分别对海龟先生的作品给出的平均分:


total_nor_score_t[total_nor_score_t['乐队'] == '海龟先生'].mean()超级乐迷_归一分    0.836000
复制代码


  • 专业乐迷_归一分 0.690000

  • 大众乐迷_归一分 0.779444

  • 总得分_归一分 0.778734


可以看到是专业乐迷,所以李红旗啊,如果专业乐迷们说什么喜欢你们,你们千万不要相信。

PART IV:不要情感,拒绝同情票,我只想告诉你真相

最后,我说出我心目中真正的 Hot5,感谢你坚持看到这里!


第六期也就是决赛的这一期,临时增加了一轮投票环节,在歌手演出结束后,一人一票,投出你喜欢的乐队。两轮票数相加得到总票数,前五名的留下。


最终成绩如下:


data6.iloc[:,:-9]
复制代码



新的规则带来很大的争议,有人会给出“同情票”,使得真正的排名不能体现乐队的实力。


因此,我心目中的 Hot5 应该是结合每场每首歌的成绩,不考虑作品以外单独的投票的干扰来评判。因此选用前面提到的标准分的方法来计算最后决赛夜的 7 只乐队全部六场成绩,得到最终的排名。


# 选中7只队伍final_7 = ['新裤子','痛仰乐队','九连真人','Click#15','刺猬','盘尼西林','旅行团乐队']# 分别计算标准分final_7_total_score = total_score_mean.loc[final_7,].sort_values(by='总得分_标准分')# 可视化fig,ax = plt.subplots(1,1,figsize = (10,20))final_7_total_score.plot.barh(ax=ax,color = yellow,alpha=0.7,title='我心中Hot5',grid=False)
复制代码



从这个结果来看,其实盘尼西林是排在最后一位的,但因为增加了投票而被捞了回来。赛制的改变,使得结果有人欢喜有人愁。


但不管结局,排名,还是很高兴,这个夏天遇见这么多好听的音乐,同时也用数据更好的察觉一些真相。


本文转载自公众号七牛云(ID:qiniutek)。


原文链接:


https://mp.weixin.qq.com/s/M0tSMiFuQXMPZVeu_-g_ag


2019-10-10 17:051293

评论

发布
暂无评论
发现更多内容

撸一串趣图,给晚上加班打个鸡血

码农神说

程序员 加班 段子

『PyTorch』使用指定GPU的方法

kraken0

人工智能 学习 图像识别

redis持久化RDB与AOF

wjchenge

redis

我们是活着,而不是活过

小天同学

个人感想 生活,随想 随笔杂谈 日常思考

GcExcel:比 Apache POI 速度更快、性能更高

葡萄城技术团队

Apache POI GCExcel

面试题:教你如何吃透RocketMQ

奈学教育

架构 RocketMQ 架构设计

收藏!如何有效实施devops?

禅道项目管理

DevOps 运维 持续集成 开发 自动化测试

深入理解ContextClassLoader

Skye

深入理解JVM ContextClassLoader

产品周刊 | 第 17 期(20200531)

八味阁

产品 设计 产品经理 产品设计 产品推荐

CEO或业务负责人应该具备的数据分析能力

花生

工具 数据 CEO

CI/CD - Python Django 项目在 Jenkins 上的实践

meta-algorithmX

Python django TDD CI/CD

SpringBatch系列入门之Tasklet

稻草鸟人

spring SpringBatch 批处理

万恶的NPE如何避免,几种你必须知道的方案!!!

不才陈某

后端

安全做到首位 统信UOS后激勃发

统小信uos

网络安全 操作系统

美国黑客曝出政府惊天内幕,看区块链如何解决!

CECBC

CECBC 区块链技术 民生 不可篡改 信息公开

Vim使用总结

JDoe

vim

Docker 搭建 Postgres + pgAdmin 环境

姜雨生

Docker DevOps postgres

游戏夜读 | 什么是黑色一分钟?

game1night

运维日志里隐藏的安全危机,你知道怎么挖吗?听听专家怎么说

secisland

态势感知 关联分析 SOC

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (十四)编写测试-显示名

编程道与术

Java 编程 TDD 单元测试 JUnit

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (十五)编写测试-断言\假设\使测试失效

编程道与术

Java 编程 TDD 单元测试 JUnit

深入理解JVM内存管理 - 方法区

Skye

深入理解JVM 方法区 老年代

学习没进步?也许反馈有问题

KAMI

学习 认知提升

ARTS-week one

Jokky💫

ARTS 打卡计划

【译】业务转型是什么?

涛哥 数字产品和业务架构

业务中台 数字化转型

Vue生成AST算法的解析

djknight

Java Vue AST

Java是不是慢半拍?

X.F

Java 架构 编程语言

霸榜18年,作者连续20年获得微软MVP,这本SQL书凭什么成为畅销经典

图灵社区

数据库 SQL语法 sql查询

奈学大数据开发工程师分享787个技术,快来收割

奈学教育

大数据

手机是21世纪最成功的毒品

Neco.W

学习 提升效率 工作

Hive底层执行引擎的深度剖析(免费)

奈学教育

大数据 hive

以乐队的夏天为例,用Python分析投票数据,选出真正的乐队TOP 5_文化 & 方法_数据守望者_InfoQ精选文章