虽然现在大众的兴趣非常的分散,乐队的夏天是否是今天最火的综艺节目,每个人心中的答案都是不一样的。但在我看来,我很感谢有这么一个节目,可以让我接触到不同类型的音乐,认识这么多优秀的乐队,知道坚持做自己喜欢的事是一件多么幸福的事。
我本身从事数据分析相关的工作,业余时间学习Python,今天应该是连续学习打卡的第84天,希望通过这个分析,可以提升代码水平,同时也想挖掘一些隐藏在排名,得分这些数据底下的结论,同时为喜欢的节目打call,最后我将预测最后一期Hot5的名单。写这篇文章的时候,距离播出还有3小时,时间紧迫哈哈,很快就要打脸了。
好了,说了这么多,那么开始吧!
第一步:数据采集
数据分析数据分析,没有数据就没有分析。网络上没有公开的详细得票、排名数据,只好自己整理了。首先购买爱奇艺会员
,不然很长时间都消耗在广告上了。然后用2.5倍速播放(这么听歌还挺带感的),然后看到这一幕,按住锁屏和音量键+,咔嚓,数据收集到了!
最后手机相册就变成现在这样
最后再填到一个Excel表里面,数据就有啦!
(如果想要原始数据,关注公众号回复“乐队的夏天”可以下载)
它大概长这个样子?
一共有5个sheet,对应5场比赛,字段分别是:[场数, 出场顺序, 乐队, 歌曲, 超级乐迷得分, 专业乐迷得分, 大众乐迷得分, 总得分, 排名, 是否晋级下一轮]
第二步:读取数据
在读取数据之前,先导入分析的工具包
import pandas as pd
import numpy as np
import 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')
观察一下数据吧
# 观察数据
data1.info()
data1.head()
以第一场的数据为例为例,可以看到字段和数据的行数,其中得分有(31-27=4)行数据为空,进入第三步。
第三步:数据清洗
既然有空数据,先看看是怎么回事
# 可以看到有四只乐队是没有得分和排名的,把他们列出来
data1[data1['总得分'].isnull()]
所以其实是有31只乐队表演的,但这四只乐队因为被剪掉了,所以没有具体成绩的数据,怎么办呢,只好把你们删了。
data1 = data1.dropna(axis = 0)
这样就完成了,因为数据是自己手动录入的,所以其它没什么问题了,可以开始分析了。
第四步:数据分析
整体的分析思路遵循从整体到局部的顺序,分为乐队和歌曲两个部分,再细分超级乐迷,专业乐迷和大众乐迷三个角度。同时会展示乐队在每期比赛的排名升降情况。
另外由于每场比赛的总票数不同,不同评委票数比例不同,为了使得不同场次之间的得票数据具备可比性,需要用到两种数据标准化的方法,分别是:
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]
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]:
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)
做完上面两步,再把每场的数据拼成一个表,大功告成。(此处省略拼接代码)
total_score
首先我们分析乐队,通过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 = '大众乐迷得分_标准分')
对前10的乐队进行数据可视化
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)
同时在三个群体中位列心目前十的乐队是:
{'九连真人', '海龟先生', '刺猬', '盘尼西林', '新裤子'}
下面一起来读绕口令:
在超级乐迷心中前十,但不在专业乐迷心中的前十乐队是:
{'痛痒乐队', '面孔乐队', '鹿先森'}
在超级乐迷心中前十,但不在大众乐迷心中的前十乐队是:
{'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.
对乐队的分析暂时告一段落,接下来看看歌曲。
通过前面提到的归一化计算,可以得到一下数据
(此处省略了一部分代码,完整代码在点击阅读原文)
首先对数据整体有一个把握
# 看看数据整体的描述
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的歌曲吧!
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的歌曲:
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,大众乐迷最喜欢西湖。
整体回顾完了,最后单独分析两个问题。第一个是为什么<我愿意>这首歌表现不好呢?
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
可以看到是专业乐迷,所以李红旗啊,如果专业乐迷们说什么喜欢你们,你们千万不要相信。
最后,我要来预测今晚谁是这个夏天的Hot5,感谢你坚持看到这里!
预测方式很简单,将归一分和标准分均排名前五的乐队,拉出来看一下:
total_nor_score_t.groupby('乐队').mean().sort_values(by = '总得分_归一分',ascending = False).head(9)
total_score_mean.sort_values(by = '总得分_标准分',ascending= False).head(9)
# 取前五的交集
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)
{'九连真人', '刺猬', '新裤子', '痛痒乐队'}
结果只有4只乐队是重合的,剩余的三只乐队中,旅行团在归一分排序中在盘尼西林前面,而标准分落后,Click#15两种计算方式结果均在最后。因此,第五名的悬念应该是在旅行团乐队和盘尼西林之间,至于最后是谁,就让今晚拭目以待吧!
写在最后,因为这是我的第一篇推文,以后还会写更多数据分析方面的,以及一些读书笔记,Python学习笔记,还有美剧推荐,哲学,历史,音乐等。之所以起名为猪栏守望者,灵感来自麦田守望者,是因为希望能够给大家一些不一样的东西,一些经过独立思考和分析的东西,让资讯不全是低级的消遣娱乐。喜欢记得点在看和关注。
点击阅读原文可以前往github获取完整分析代码
本文分享自 智能工场AIWorkshop 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!