Анализ с использованием аудиофункций Spotify

Я буду просматривать плейлисты еженедельных песенных чартов, которые создаются Spotify каждую неделю и к которым легко получить доступ. Они состоят из 50 самых популярных треков в стране или во всем мире.

Меня больше всего интересовали списки воспроизведения песен в Южной Африке, Южной Корее, США и Индии, и я выбрал их для своего анализа.

Вы можете посмотреть другие страны, исходя из ваших конкретных интересов. Все, что вам нужно для конкретного плейлиста, — это его соответствующий идентификатор, который доступен в разделе просмотра рабочего стола Spotify: ChartsЕженедельные песенные чарты в Spotify. И чтобы выбрать id, вам просто нужно скопировать id из ссылки этого плейлиста. Здесь, в приведенном ниже примере, идентификатором будет выделенная жирным шрифтом комбинация некоторых цифр и букв.

https://open.spotify.com/playlist/37i9dQZEVXbLp5XoPON0wI

import sys
import warnings
if not sys.warnoptions:
    warnings.simplefilter("ignore")
    
import spotipy
import json
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from math import pi
from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.preprocessing import MinMaxScaler
from spotipy.oauth2 import SpotifyClientCredentials
sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials(client_id="######",
                                                          client_secret="####"))
def compare_playlist(playlist_id):
    results = sp.playlist(playlist_id)
    ids=[]
    for item in results['tracks']['items']:
        track = item['track']['id']
        ids.append(track)
    #ids 
    song_name=[]
    for item in ids:
        song_name_ = sp.track(item)['name'] 
        song_name.append(song_name_)
# check the song feature
    features = sp.audio_features(ids)
    # change dictionary to dataframe
    features_df=pd.DataFrame.from_dict(features)
    # combine two list + features
    song_demo = pd.DataFrame({'id': ids,'song_name': song_name})
    final_df=song_demo.merge(features_df)
    return(final_df)
feat_df_Skorea = compare_playlist("37i9dQZEVXbJZGli0rRP3r")
feat_df_Safrica = compare_playlist("37i9dQZEVXbJV3H3OfCN1z")
feat_df_usa = compare_playlist("37i9dQZEVXbLp5XoPON0wI")
feat_df_india = compare_playlist("37i9dQZEVXbMWDif5SCBJq")
feat_df_global = compare_playlist("37i9dQZEVXbMDoHDwVN2tF")

Что говорит Дарт Радар?

Для обзора аудиофункций Spotify и того, как они отображаются в разных плейлистах, я использую радарную диаграмму.

from sklearn import preprocessing
feat_cols = ['danceability', 'energy', 'speechiness', 'acousticness', 'instrumentalness', 'liveness', 'valence']
mean_vals = pd.DataFrame(columns=feat_cols)
mean_vals = mean_vals.append(feat_df_Skorea.median(), ignore_index=True)
mean_vals = mean_vals.append(feat_df_Safrica.median(), ignore_index=True)
mean_vals = mean_vals.append(feat_df_usa.median(), ignore_index=True)
mean_vals = mean_vals.append(feat_df_india.median(), ignore_index=True)
import plotly.graph_objects as go
import plotly.offline as pyo
fig = go.Figure(
    data=[
        go.Scatterpolar(r=mean_vals.iloc[0], theta=feat_cols, fill='toself', name='South Korea'),
        go.Scatterpolar(r=mean_vals.iloc[1], theta=feat_cols, fill='toself', name='South Africa'),
        go.Scatterpolar(r=mean_vals.iloc[2], theta=feat_cols, fill='toself', name='USA'),
        go.Scatterpolar(r=mean_vals.iloc[3], theta=feat_cols, fill='toself', name='India'),
    ],
    layout=go.Layout(
        title=go.layout.Title(text='Feature comparison'),
        polar={'radialaxis': {'visible': True}},
        showlegend=True
    )
)
fig.write_image(file='RadarChart.png', format='png')
fig.show()

Как вы можете видеть, на приведенном ниже графике показано распределение различных атрибутов плейлиста. «0» каждой оси — это центр колеса, и атрибут становится все выше и выше по мере того, как мы удаляемся от центра.

Идеальную оценку танцевальности можно увидеть в плейлисте для Южной Африки. Они должны хорошо танцевать!

Танцевальность описывает, насколько трек подходит для танцев, основываясь на сочетании музыкальных элементов, включая темп, стабильность ритма, силу удара и общую регулярность. Значение 0,0 соответствует наименее танцевальному, а значение 1,0 — наиболее танцевальному.

Индия лидирует с точки зрения акустики. А самая высокая валентность и энергия наблюдается в Южной Корее.

Валентность — это показатель от 0,0 до 1,0, описывающий музыкальную позитивность, передаваемую треком. Треки с высокой валентностью звучат более позитивно (например, счастливые, веселые, эйфорические), в то время как треки с низкой валентностью звучат более негативно (например, грустные, подавленные, злые).

Энергия представляет собой меру от 0,0 до 1,0 и представляет перцептивную меру интенсивности и активности. Как правило, энергичные треки кажутся быстрыми, громкими и шумными. Например, у дэт-метала высокая энергия, а у прелюдии Баха низкий балл по шкале. Характеристики восприятия, влияющие на этот атрибут, включают динамический диапазон, воспринимаемую громкость, тембр, скорость начала и общую энтропию.

Как и ожидалось, живость и речьнизки, что подтверждает, что песни в этих плейлистах не записывались во время исполнения. live и включает в себя музыкальные / неречевые треки.

А как насчет других функций?

Я пропустил некоторые функции, так как хотел посмотреть на них отдельно от радиолокационной диаграммы. Кроме того, их масштаб был другим, и было бы неплохо их нормализовать (например, тональность).

feat_df_Skorea["Playlist_name"] = "South Korea"
feat_df_Safrica["Playlist_name"] = "South Africa"
feat_df_usa["Playlist_name"] = "USA"
feat_df_india["Playlist_name"] = "India"
res = pd.concat([feat_df_Skorea,feat_df_Safrica,feat_df_usa,feat_df_india])
#Creating a function for density plot for other left out features - 
def feature_densityPlt(feature):
    playlist_names  = ['South Korea', 'South Africa', 'USA','India']
    # Iterate through the 4 playlist
    for playlist_name in playlist_names:
        # Subset to the playlist
        subset = res[res['Playlist_name'] == playlist_name]
    
        # Draw the density plot
        sns.distplot(subset[feature], hist = False, kde = True,
                 kde_kws = {'linewidth': 3},
                 label = playlist_name)
    # Plot formatting
    plt.legend(prop={'size': 9}, title = 'playlist_names')
    plt.title('Density Plot for '+feature+' across different countries playlists')
    plt.xlabel(feature)
    plt.savefig('DensityPlot_'+feature+'.png')
  1. Ключ
feature_densityPlt('key')

Наиболее интересное распространение имеет США. Топ-50 песен в США имеют разнообразное распространение, и ни одна любимая тональность не может быть оценена. Для других стран мы наблюдаем бимодальное распределение.
Всего в 4 странах популярны два ключа — 1(C♯/D♭) и 10(A♯, B♭).

Примечание можно определить, сопоставив числа со стандартной нотацией класса высоты тона.

2. Темп

feature_densityPlt('tempo')

ЮАР выделялась выше. В 50 лучших песнях Южной Африки частота составляет около 110 ударов в минуту. Для других плейлистов мы можем наблюдать бимодальное распределение — один пик наблюдается около 110 ударов в минуту, а другой — около 160 ударов в минуту.

3. Громкость

Общая громкость дорожки в децибелах (дБ). Значения громкости усредняются по всей дорожке и полезны для сравнения относительной громкости дорожек. Громкость – это качество звука, которое является основным психологическим коррелятом физической силы (амплитуды). Обычно значения находятся в диапазоне от -60 до 0 дБ.

feature_densityPlt('loudness')

Южная Африка и Индия немного более разнообразны с точки зрения громкости по сравнению с Южной Кореей и США, которые в основном сосредоточены вокруг (-8,-2) дБ.

4. Валентность

feature_densityPlt('valence')

Очевидно, что Южная Корея имеет больше позитива в своих 50 лучших песнях по сравнению с другими тремя странами.

5. Акустика

feature_densityPlt('acousticness')

Приведенный выше график плотности подтверждает наш предыдущий вывод о том, что 50 лучших песен Индии более акустичны по своей природе и насколько они разнообразны по сравнению с ними. Южная Африка заметно менее акустична.

А как же Венн и Джерри?

import matplotlib
matplotlib.use('Agg')
import venn
set_Skorea = set(feat_df_Skorea["song_name"])
set_Safrica = set(feat_df_Safrica["song_name"])
set_usa = set(feat_df_usa["song_name"])
set_india = set(feat_df_india["song_name"])
labels = venn.get_labels([set_Skorea, set_Safrica, set_usa, set_india], fill = ['number'])
fig, ax = venn.venn4(labels, names=['South Korea', 'South Africa', 'USA', 'India'])
#fig.write_image(file='VennDiagram.png', format='png')
fig.savefig('VennDiagram.png')
fig.show()

Было 4 песни, которые были общими для всех плейлистов:

set_usa.intersection(set_Skorea, set_Safrica,set_india)
{'As It Was',
 'Glimpse of Us',
 'Left and Right (Feat. Jung Kook of BTS)',
 'STAY (with Justin Bieber)'}

Тепловая карта корреляции

A) Для еженедельного глобального плейлиста

feat_global_num = feat_df_global.select_dtypes(include=[np.float])
plt.figure(figsize=(16,8))
sns.heatmap(feat_global_num.corr(),cmap='mako')
plt.savefig('CorrHeatmap_globalPlaylist.png')
plt.show()

Здесь отчетливо видна отрицательная корреляция между двумя парами — танцевальностью и темпом; Энергия и акустика. Между тем, между энергией и громкостью наблюдается положительная корреляция, что также имеет смысл.

Б) Для сравнения плейлистов в разных странах

feat_Skorea_num = feat_df_Skorea.select_dtypes(include=[np.float])
feat_Safrica_num = feat_df_Safrica.select_dtypes(include=[np.float])
feat_usa_num = feat_df_usa.select_dtypes(include=[np.float])
feat_india_num = feat_df_india.select_dtypes(include=[np.float])
res_num = res.select_dtypes(include=[np.float])
f,(ax1,ax2,ax3, ax4, axcb) = plt.subplots(1,5, figsize=(25,10),
            gridspec_kw={'width_ratios':[1,1,1,1,0.08]})
ax1.get_shared_y_axes().join(ax2,ax3)
g1 = sns.heatmap(feat_Skorea_num.corr(),cmap='mako',cbar=False,ax=ax1)
g1.set_title('South Korea', fontsize=20)
g1.set_ylabel('')
g1.set_xlabel('')
g2 = sns.heatmap(feat_Safrica_num.corr(),cmap='mako',cbar=False,ax=ax2)
g2.set_title('South Africa', fontsize=20)
g2.set_ylabel('')
g2.set_xlabel('')
g2.set_yticks([])
g3 = sns.heatmap(feat_usa_num.corr(),cmap='mako',ax=ax3, cbar_ax=axcb)
g3.set_title('USA', fontsize=20)
g3.set_ylabel('')
g3.set_xlabel('')
g3.set_yticks([])
g4 = sns.heatmap(feat_india_num.corr(),cmap='mako',ax=ax4, cbar_ax=axcb)
g4.set_title('India', fontsize=20)
g4.set_ylabel('')
g4.set_xlabel('')
g4.set_yticks([])
# rotate the ticklabels correctly:
for ax in [g1,g2,g3,g4]:
    tl = ax.get_xticklabels()
    ax.set_xticklabels(tl, rotation=90)
    tly = ax.get_yticklabels()
    ax.set_yticklabels(tly, rotation=0)
plt.savefig('CorrHeatmap_acrossDiffPlaylists.png')
plt.show()

В целом тепловые карты корреляции Южной Кореи и Индии больше похожи друг на друга, тогда как Южная Африка и США также не сильно отличаются друг от друга с точки зрения характеристик звука. Это также было видно на графике радара выше.

Танцевальность положительно коррелирует с энергичностью и громкостью в Южной Корее и Индии (0,4–0,6). Речь также положительно коррелирует с энергией в Южной Корее и Индии, но не сильно в других странах. Другой интересной особенностью является валентность и то, как можно увидеть высокую положительную корреляцию между валентностью и танцевальностью в тех 2 странах, где на самом деле это не так, как в США или Южной Африке.

Плейлист Южной Африки немного отличается от других плейлистов. Танцевальность отрицательно коррелирует с акустикой и живостью (это не наблюдается в других странах или во всем мире); точно так же мы не видим большой отрицательной корреляции между акустикой и энергией.

Положительная корреляция между громкостью и энергией одинакова в разных странах (это согласуется с глобальным плейлистом).

Это все, что у меня есть для этого поста! Дайте мне знать, если у вас есть какие-либо другие предложения или интерпретации.

Вы также можете найти мой код на моей странице github здесь.

Для начинающих API Spotify вы можете проверить эту ссылку. Пожалуйста, пингуйте меня, если вы в конечном итоге анализируете плейлисты других стран / регионов!

Я также написал аналогичный пост для анализа собственных плейлистов, если интересно, нажмите здесь.

Интересный факт — вы можете аплодировать до 50 раз за пост или список на медиуме, чтобы показать поддержку автору :)