通过群集在Spotify上分析我最喜欢的歌曲

纵饮孤独 提交于 2020-10-30 09:07:45

作者 | John Koh

来源 | Medium

编辑 | 代码医生团队


感谢Spotify API,能够提取和探索喜欢听的歌曲 - 那些让我点击那个心形图标的歌曲。

 

建立

要从Spotify API获取数据,需要使用以下步骤进行初始设置:

 

1.登录Spotify for Developers并创建一个应用程序。

 https://developer.spotify.com/dashboard/

2.从应用程序仪表板页面中,选择编辑设置并将重定URI设置为

    http:// localhost:8888

3.记下客户端ID和客户端密钥。


收集数据

可以使用Spotpy Web APISpotipy来获取相关数据。要获取歌曲,需要生成授权令牌。

https://spotipy.readthedocs.io/en/latest/

import spotipy

import spotipy.util as util

from spotipy.oauth2 import SpotifyClientCredentials

cid = '<INSERT CLIENT ID>'

secret = '<INSERT CLIENT SECRET>'

username = ""

client_credentials_manager = SpotifyClientCredentials(client_id=cid, client_secret=secret)

sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

# Get read access to your library

scope = 'user-library-read'

token = util.prompt_for_user_token(username, scope)

if token:

    sp = spotipy.Spotify(auth=token)

else:

print("Can't get token for", username)

 

有两个APIcurrent_user_saved_tracksaudio_features,用于获取标题,艺术家,时间歌曲以及声学,舞蹈和乐器等功能。这些功能将帮助更好地理解播放列表。

 

这些功能的一些描述如下表所示:

 

 

要查看歌曲的完整功能,您可以查看此链接

https://developer.spotify.com/documentation/web-api/reference/tracks/get-audio-features/

 

#include timestamp added, title and artists of a song

df_saved_tracks['added_at'] = added_ts_list

df_saved_tracks['song_title'] = title_list

df_saved_tracks['artists'] = artist_list

df_saved_tracks = pd.DataFrame()

track_list = ''

added_ts_list = []

artist_list = []

title_list = []

more_songs = True

offset_index = 0

while more_songs:

    songs = sp.current_user_saved_tracks(offset=offset_index)

    for song in songs['items']:

        #join track ids to a string for audio_features function

        track_list += song['track']['id'] +','

        #get the time when the song was added

        added_ts_list.append(song['added_at'])

        #get the title of the song

        title_list.append(song['track']['name'])

        #get all the artists in the song

        artists = song['track']['artists']

        artists_name = ''

        for artist in artists:

            artists_name += artist['name']  + ','

        artist_list.append(artists_name[:-1])

    #get the track features and append into a dataframe

    track_features = sp.audio_features(track_list[:-1])

    df_temp = pd.DataFrame(track_features)

    df_saved_tracks = df_saved_tracks.append(df_temp)

    track_list = ''

    if songs['next'] == None:

        # no more songs in playlist

        more_songs = False

    else:

        # get the next n songs

        offset_index += songs['limit']

#include timestamp added, title and artists of a song

df_saved_tracks['added_at'] = added_ts_list

df_saved_tracks['song_title'] = title_list

df_saved_tracks['artists'] = artist_list

 

以下是获得的数据集的示例。

 

 

我对音乐的品味有所改变吗?

获取数据后,是时候了解功能如何随时间变化。可以按照添加的年份和月份对歌曲进行分组,获取每个功能随时间的平均值并将其可视化。

 

 

线图按年份分隔,以使其更具一口大小。多年来,语气(紫罗兰色)最接近0。这表明我一般都会听那些不那么说唱的歌。声学(蓝色)是波动的,这意味着我随着时间的推移混合了声学和非声学歌曲。

 

我最感兴趣的是工具性(绿色)。2015年和2016年,它稳定接近0.然而,从2017年开始,工具性开始波动。这可能表明我的音乐品味从2017年开始改变。可以将数据过滤为2017年添加的歌曲。

 

我在听什么类型的歌?


聚类

根据上面的图表,我知道我正在听更多的乐器歌曲。但它是有助于舞蹈的那种歌曲吗?还是更古典的歌曲?其他人怎么样?我目前对音乐的品味是什么?可以将具有相似特征的歌曲组合在一起,并分析每个群集。一种类型的聚类方法是K-means Clustering,我将用它来分析我的歌曲。

https://en.wikipedia.org/wiki/K-means_clustering

 

对于群集,希望同一群集中的点尽可能接近。还希望群集之间的距离尽可能远离彼此。这使得每个群集看起来紧凑,同时彼此间隔开。

 

以下是4个集群的聚类情况的可视化。绿点表示每个群集质心(群集的中心)。

 

K-means聚类


由于聚类依赖于距离,因此数据规模将影响结果。例如如果想按高度聚集,从1.5米到1.9米,重量从60公斤到80公斤。因此这些点在高度轴上扩展0.4,权重在20上扩散。这意味着权重将在确定集群时占主导地位。

 

可以标准化数据范围,使特征影响结果。

cluster_features = ['acousticness''danceability''instrumentalness''energy''speechiness']

df_cluster = df_recent[cluster_features]

X = np.array(df_cluster)

scaler = StandardScaler()

scaler.fit(X)

X = scaler.transform(X)

 

在了解了群集的功能之后,会听到多少种类型/群组的歌曲?一种方法是根据自己的知识进行有根据的猜测。如果你聆听从edmhip hop到爵士乐等所有类型的音乐,你可以提供更高的数字,比如... 7也许吧?因为K-means聚类需要指定想要的聚类数量,可以设置k = 7,其中k是聚类的数量。

 

另一种方法是使用肘方法的帮助来确定簇的数量。在弯头方法中,可以对一系列设定的簇数进行聚类,例如k = 1k = 2...k = 9k = 10。对于每个k,将获取每个点并测量其与群集质心的平方距离,并将它们相加。这称为平方距离之和(SSD)。SSD测量每个点与群集质心的接近程度。因此SSD越小,相同群集中的点越近。 

ss_dist = []

K = range(111)

for k in K:

    km = KMeans(n_clusters=k, init='k-means++', random_state=123)

    km = km.fit(X)

    ss_dist.append(km.inertia_)

plt.plot(K, ss_dist, 'bx-')

plt.xlabel('k')

plt.ylabel('Sum of squared distances')

plt.title('Elbow Method For Optimal k')

plt.show()

 

因此如果为每个k绘制SSD,将得到如下所示的曲线:

 

 

从上图可以看出,随着k的增加,SSD减少了。这是有意义的,因为点可能具有更近的群集,从而导致SSD更低。

 

早些时候,我提到希望每个集群中的点尽可能接近。但是不能选择k = 10,因为它是最低的。想象一下。如果选择k = N,其中N是歌曲的数量,将每首歌曲作为自己的群集,因此SSD将为0.这是因为每个点的群集质心是该点本身。

 

相反将选择k,这样如果添加另一个集群,SSD会略有下降。这被称为肘法。如果将曲线看作我们的手臂,会在开始时获得一个陡峭的斜坡,中间突然变得温和。这使它具有“肘部”形状。

 

基于肘法,推荐的簇数为4,因为从k = 4k = 5,线条变得平缓。然而,我也玩了k = 5,发现我喜欢给出的簇。因此,在这篇文章中,我将分享我得到的k = 5的结果。

 

集群可视化

那集群怎么样?不幸的是,在此还无法查看它。这是因为簇使用5个特征形成。如果您将每个要素视为维度,则可获得5-D。由于可以查看高达3-D的图像,需要执行一种称为降维的技术。这使可以从5-D减少到更低的任何尺寸。

 

为了尽可能直观地尝试解释它,降维旨在从较高维度制作低维度的特征集,同时保留尽可能多的信息。如果您希望更好地了解它的作用,您可以观看有关主成分分析(PCA)的视频,这是降维的方法之一。

 

如果使用PCA来减少维度,让我们看看保留了多少数据。

 

 

蓝色条显示每个主要组件(PC)对数据的贡献量。第一台PC贡献了40%的数据信息。第二个和第三个每个贡献20%。红线显示PC的数据累积信息。通过从5维减少到2,保留了60%的数据信息。同样,如果我们要减少到3维,则保留80%的数据信息。

 

现在看看聚类在二维和三维散点图上的样子。

 

 

二维散点图中的点彼此重叠,看起来可能看起来没有很好地完成聚类。但是如果从三维视角来看它,可以更好地看到这些集群。

 

尝试另一种叫做t-Distributed Stochastic Neighbor Embeddingt-SNE)的方法。t-SNE在可视化高维数据方面表现良好。

 

 

在这种情况下,2-D t-SNE散点图能够很好地可视化5个簇。还可以粗略地告诉群集3是最大的群集,群集01是最小的群集。看看如何使用条形图分布集群。

 

 

群集分析

现在可以了解不同集群的特征。比较群集中的要素分布。 

# set binning intervals of 0.1

bins = np.linspace(0,1,10)

# create subplots for number of clusters(Rows) and features(Cols)

num_features = len(cluster_features)

f, axes = plt.subplots(num_clusters, num_features,

                       figsize=(2010), sharex='col'

row = 0

for cluster in np.sort(df_recent['cluster'].unique()):

    df_cluster = df_recent[df_recent['cluster'] == cluster]

    col = 0

    for feature in cluster_features:

        rec_grp = df_recent.groupby(pd.cut(df_recent[feature], bins)).size().reset_index(name='count')

        cluster_grp = df_cluster.groupby(pd.cut(df_cluster[feature], bins)).size().reset_index(name='count')



        sns.barplot(data=rec_grp, x=feature, y='count',

                    color='grey', ax=axes[row, col])

        sns.barplot(data=cluster_grp, x=feature, y='count',

                    color='red', ax=axes[row, col])

        axes[row, col].set_xlabel('')

        axes[row, col].set_xticklabels(range(1,10))

        if col > 0:

            axes[row, col].set_ylabel('')

        if row == 0:

            axes[row, col].set_title(feature)

        col += 1



    row += 1



f.suptitle('Profile for each clusters')



plt.show()

 


每行代表集群,04,每列代表特征。灰色条表示要素的分布。这使可以大致了解该功能的分布。红色条表示该群集中要素的分布,用于与其他群集进行比较。

 

当查看每个群集的分布时,可以看到每个群集在某些特征中是高还是低。这是通过红色条相对于灰色条位于右侧(高侧)还是左侧(低侧)来识别的。从这些特征中,可以对它们进行分析,甚至可以提出一个集群标识。


Cluster 0 (Instrumental): Highinstrumentalness. Low speechiness.


Cluster 1 (Lyrical): High danceability, energy, speechiness. Low acousticness, instrumentalness.


Cluster 2 (Chill vibes): High danceability. Low energy, instrumentalness, speechiness.


Cluster 3 (Dance): High danceability, energy. Low acousticness, instrumentalness, speechiness.


Cluster 4 (Wind down): Highacousticness. Low danceability, instrumnetalness, energy, speechiness.


还可以通过获取群集特征的平均值并将其绘制到雷达图上来进行分析。这可能更容易一目了然地查看所有群集之间的差异。

 

 

雷达图的读数与上面给出的曲线相似。还可以看到第2组和第4组具有类似的统计数据。不同之处在于群集2更侧重于可舞蹈性,而群集4更侧重于声学。

 

集群样本

看看每个群集中的歌曲是否适合群集配置文件。每个群集中有3首歌曲,你可以听一听,看看是否有意义:

 

Cluster 0 (Instrumental): 

Go Back Home by FKJ

Hypnotised by Coldplay

Libertango by Astor Piazzolla, Bond


Cluster 1 (Lyrical):

September Rose by Cailin Russo

Candlelight by Zhavia Ward

BBIBBI by IU


Cluster 2 (Chill vibes):

Drop the Game by Flume, Chet Faker

Livid by ELIZA

Find a Way by Matt Quentin, Rinca Yang


Cluster 3 (Dance):

Ultralife by Oh Wonder

Little Man by The Pb Underground

Finesse (Remix) [feat. Cardi B] by Bruno Mars,Cardi B


Cluster 4 (Wind down):

Frozen by Sabrina Claudio

Break the Distance 2.0 by Ashton Edminster

Someone To Stay by Vancouver Sleep Clinic

 

结论

首先看一下不同的功能,并试着弄清楚音乐品味是否有所改变。从过滤后的数据集中,进行了聚类分析。然后可视化以大致了解它的外观并确保聚类很好。最后绘制了每个特征的分布并对其进行了分析。在一天结束时,能够更好地理解喜欢的歌曲类型。

 

数据的收集,可以发现在这里,可以找到分析在Github上。

https://github.com/jkwd/spotify/blob/master/Code/Spotify%20Get%20Data.ipynb

https://github.com/jkwd/spotify/blob/master/Code/Favourite%20songs%20EDA.ipynb

 

参考

绘制构面图:

https://seaborn.pydata.org/examples/many_facets.html

主成分分析(PCA)的分步指南:

https://www.youtube.com/watch?v = FgakZw6K1QQ

关于t-SNE的教程:

https://www.datacamp.com/community/tutorials/introduction-t-sne

绘制雷达/蜘蛛图:

https://python-graph-gallery.com/392-use-faceting-for-radar-chart/


推荐阅读


使用CNN和RNN进行音乐流派识别


关于图书

《深度学习之TensorFlow:入门、原理与进阶实战》和《Python带我起飞——入门、进阶、商业实战》两本图书是代码医生团队精心编著的 AI入门与提高的精品图书。配套资源丰富:配套视频、QQ读者群、实例源码、 配套论坛:http://bbs.aianaconda.com   。更多请见:aianaconda.com


点击“阅读原文”配套图书资源


本文分享自微信公众号 - 相约机器人(xiangyuejiqiren)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!