前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用Python告诉你,谁是这个夏天的最强乐队?

用Python告诉你,谁是这个夏天的最强乐队?

作者头像
刀刀老高
发布2019-08-16 10:50:27
4240
发布2019-08-16 10:50:27
举报
文章被收录于专栏:奇点大数据

文章转载自公众号

猪栏守望者 , 作者 数据守望者

虽然现在大众的兴趣非常的分散,乐队的夏天是否是今天最火的综艺节目,每个人心中的答案都是不一样的。但在我看来,我很感谢有这么一个节目,可以让我接触到不同类型的音乐,认识这么多优秀的乐队,知道坚持做自己喜欢的事是一件多么幸福的事。

我本身从事数据分析相关的工作,业余时间学习Python,今天应该是连续学习打卡的第84天,希望通过这个分析,可以提升代码水平,同时也想挖掘一些隐藏在排名,得分这些数据底下的结论,同时为喜欢的节目打call,最后我将预测最后一期Hot5的名单。写这篇文章的时候,距离播出还有3小时,时间紧迫哈哈,很快就要打脸了。

好了,说了这么多,那么开始吧!

第一步:数据采集

数据分析数据分析,没有数据就没有分析。网络上没有公开的详细得票、排名数据,只好自己整理了。首先购买爱奇艺会员

,不然很长时间都消耗在广告上了。然后用2.5倍速播放(这么听歌还挺带感的),然后看到这一幕,按住锁屏和音量键+,咔嚓,数据收集到了!

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

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

(如果想要原始数据,关注公众号回复“乐队的夏天”可以下载)

它大概长这个样子?

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

第二步:读取数据

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

代码语言:javascript
复制
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

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

代码语言:javascript
复制
# 配置乐队的夏天主题色

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) # 红色

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

代码语言:javascript
复制
# 读取数据

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')

观察一下数据吧

代码语言:javascript
复制
# 观察数据

data1.info()
data1.head()

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

第三步:数据清洗

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

代码语言:javascript
复制
# 可以看到有四只乐队是没有得分和排名的,把他们列出来

data1[data1['总得分'].isnull()]

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

代码语言:javascript
复制
data1 = data1.dropna(axis = 0)

这样就完成了,因为数据是自己手动录入的,所以其它没什么问题了,可以开始分析了。

第四步:数据分析

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

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

  1. Z_score 标准分
  2. 0-1 normalization 归一分

Z_score标准分的计算方法是用

(该乐队当场得分 - 当场所有乐队得分的平均数)/ 当场所有乐队得分的标准差

计算得到

代码语言:javascript
复制
# 标准分函数定义

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]

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 归一分的计算方法是用

乐队得票数/总票数 计算得到,也等于常说的得票率

代码语言:javascript
复制
# 定义归一化的函数

def normalize(series,x_max):

    return series.apply(lambda x: x/x_max)
# 对不同总分不同类别的得分应用归一化函数

for data in [data1,data2,data5]:
    data['超级乐迷_归一分'] = normalize(data['超级乐迷得分'],50)

data3['超级乐迷_归一分'] = normalize(data3['超级乐迷得分'],60)
data4['超级乐迷_归一分'] = normalize(data4['超级乐迷得分'],40)

for data in [data1,data2,data3,data4,data5]:
    data['专业乐迷_归一分'] = normalize(data['专业乐迷得分'],40)
    
for data in [data1,data2]:
    data['大众乐迷_归一分'] = normalize(data['大众乐迷得分'],100)
for data in [data3,data4,data5]:
    data['大众乐迷_归一分'] = normalize(data['大众乐迷得分'],360)

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

代码语言:javascript
复制
total_score

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

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

代码语言:javascript
复制
# 按照乐队这个标签分类计算,计算方式是平均值,计算字段是总得分_标准分,然后按照总得分_标准分排列

total_score_mean = total_score.groupby(['乐队'])[['总得分_标准分']].mean().sort_values(
    by = '总得分_标准分',ascending = False)
total_score_mean

(贴一部分成绩出来)

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

代码语言:javascript
复制
# 对乐队总得分_标准分做可视化

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。

代码语言:javascript
复制
# 把痛痒的成绩拉出来看一下 
total_score[total_score['乐队'] == '痛痒乐队']

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

代码语言:javascript
复制
total_score[total_score['乐队'] == '面孔乐队']

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

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

代码语言:javascript
复制
# 代码逻辑和前面选总得分作为计算字段的逻辑一样,只不过这次选取单个群体得分作为指标

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 = '大众乐迷得分_标准分')

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

代码语言:javascript
复制
fig,ax = plt.subplots(1,3,figsize = (16,6))

super_score_mean.tail(10).plot.barh(ax=ax[0],color = '#dc2624',alpha=0.7,title='超级乐迷心中TOP10',grid=False)
pro_score_mean.tail(10).plot.barh(ax=ax[1],color = '#2b4750',alpha=0.7,title='专业乐迷心中TOP10',grid=False)
public_score_mean.tail(10).plot.barh(ax=ax[2],color = '#649E7D',alpha=0.7,title='大众乐迷心中TOP10',grid=False)
代码语言:javascript
复制
同时在三个群体中位列心目前十的乐队是:
 {'九连真人', '海龟先生', '刺猬', '盘尼西林', '新裤子'}

下面一起来读绕口令:

在超级乐迷心中前十,但不在专业乐迷心中的前十乐队是:
 {'痛痒乐队', '面孔乐队', '鹿先森'}

在超级乐迷心中前十,但不在大众乐迷心中的前十乐队是:
 {'Mr.WooHoo', 'Click#15', '面孔乐队', '鹿先森'}

在专业乐迷心中前十,但不在超级乐迷心中的前十乐队是:
 {'Mr.Miss', '和平和浪', '皇后皮箱'}

在专业乐迷心中前十,但不在大众乐迷心中的前十乐队是:
 {'Click#15', '皇后皮箱', 'Mr.Miss', '和平和浪', 'Mr.WooHoo'}

在大众乐迷心中前十,但不在超级乐迷心中的前十乐队是:
 {'旅行团乐队', '黑撒乐队', '葡萄不愤怒', '南无乐队'}

在大众乐迷心中前十,但不在专业乐迷心中的前十乐队是:
 {'旅行团乐队', '葡萄不愤怒', '南无乐队', '痛痒乐队', '黑撒乐队'}

(上面的内容是通过对三个数据做集合运算得出的,完整代码在点击阅读原文)

需要说明的是,因为有些乐队在第一轮就被淘汰了,例如鹿先森、和平和浪、葡糖不愤怒,使得他们单场表现的成绩就代表了他们的整体水平,这是有失偏颇的,因为比赛本身是淘汰和晋级的形式,越往后面对的竞争环境会越加激烈,所以得分会更能代表乐队实力。

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

新裤子的发挥是较为稳定的,除了第三场上和Cindy合作的音乐形式较为新颖,让观众一时难以接受之外,在各个场次都获得非常靠前的成绩。

同样稳定的还有九连真人,一直稳稳的在中间,此外第二场改编李宗盛大哥的凡人歌,现场炸裂,表现超出期待。

表现越来越好的有两只乐队:

1.刺猬

2.Click#15

刺猬可谓是低开高走,复活赛中凭借白日梦蓝稳稳防守住黑撒乐队的挑战,女神赛中和斯斯与帆的合作更是获得了全场最佳。

Click#15虽然在第二场和面孔的PK赛中被淘汰,但又杀了回来,而且第五场演绎beyond的碑面派对,首次赢得第一名。

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

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

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

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

(此处省略了一部分代码,完整代码在点击阅读原文

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

代码语言:javascript
复制
# 看看数据整体的描述
total_nor_score.describe()

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

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

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

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

截止第五期,最受欢迎的10首歌分别是: ['一场游戏一场梦', "Don't break my heart", '红河谷', '凡人歌', 'How come u leave me like this', '生命因你而火热', '椑面派对', '西湖', '花火', 'Bye Bye']

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

代码语言:javascript
复制
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,专业乐迷最喜欢Bye Bye Bye,大众乐迷最喜欢西湖。

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

代码语言:javascript
复制
total_nor_score[total_nor_score['歌曲'] == '我愿意']

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

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

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

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

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

代码语言:javascript
复制
total_nor_score_t[total_nor_score_t['乐队'] == '海龟先生'].mean()
代码语言:javascript
复制
超级乐迷_归一分    0.836000
专业乐迷_归一分    0.690000
大众乐迷_归一分    0.779444
总得分_归一分     0.778734

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

最后,我要来预测今晚谁是这个夏天的Hot5,感谢你坚持看到这里!

预测方式很简单,将归一分和标准分均排名前五的乐队,拉出来看一下:

代码语言:javascript
复制
total_nor_score_t.groupby('乐队').mean().sort_values(by = '总得分_归一分',ascending = False).head(9)
total_score_mean.sort_values(by = '总得分_标准分',ascending= False).head(9)
代码语言:javascript
复制
# 取前五的交集
hot5_nor = total_nor_score_t.groupby('乐队').mean().sort_values(by = '总得分_归一分',ascending = False).head(5).index
hot5_z = total_score_mean.sort_values(by = '总得分_标准分',ascending= False).head(5).index
set(hot5_nor) & set(hot5_z)
代码语言:javascript
复制
{'九连真人', '刺猬', '新裤子', '痛痒乐队'}

结果只有4只乐队是重合的,剩余的三只乐队中,旅行团在归一分排序中在盘尼西林前面,而标准分落后,Click#15两种计算方式结果均在最后。因此,第五名的悬念应该是在旅行团乐队和盘尼西林之间,至于最后是谁,就让今晚拭目以待吧!

写在最后,因为这是我的第一篇推文,以后还会写更多数据分析方面的,以及一些读书笔记,Python学习笔记,还有美剧推荐,哲学,历史,音乐等。之所以起名为猪栏守望者,灵感来自麦田守望者,是因为希望能够给大家一些不一样的东西,一些经过独立思考和分析的东西,让资讯不全是低级的消遣娱乐。喜欢记得点在看关注

点击阅读原文可以前往github获取完整分析代码

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 智能工场AIWorkshop 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档