Data Science, même en musique.

Jan 23 2023
En testant l'API Spotify, j'ai trouvé de nombreuses fonctionnalités cachées derrière les chansons que nous écoutons tous les jours. Voici le projet, mais je préfère vous le montrer dans cet article.

En testant l'API Spotify, j'ai trouvé de nombreuses fonctionnalités cachées derrière les chansons que nous écoutons tous les jours.

Voici le projet, mais je préfère vous le montrer dans cet article.https://github.com/ivanurquiza/Spotify-Analysis

J'ai eu l'idée d'analyser les chansons les plus écoutées en ce moment.

Deux questions principales auxquelles répondre :
1. Quelle est la caractéristique de la musique tendance ?
2. En quoi est-ce différent de la musique à l'ancienne ?

# FILL IN THESE VALUES WITH YOUR OWN KEYS
client_id = ...

client_secret = ...

# Make sure to add this on "Edit Settings" in your Dashboard
redirect_uri = "http://localhost:9000"

import spotipy
from spotipy.oauth2 import SpotifyOAuth

# Connect with API Keys created earlier
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=client_id,
                                              client_secret=client_secret,
                                              redirect_uri=redirect_uri))

J'ai dû faire un choix. Pour ce cas, j'ai utilisé une playlist très célèbre en Argentine créée par Spotify, qui contient le Top 50 des chansons les plus écoutées en ce moment :

#Playlist ID
TOP50_playlist = sp.playlist('37i9dQZEVXbMMy2roB9myp')

for track_data in TOP50_playlist['tracks']['items']:
    
    #Getting just the ID (last part of the url)
    track_id = track_data['track']['uri'].split(':')[-1]
    track_name = track_data['track']['name']
    track_popularity = track_data['track']['popularity']
    list_tracksids.append((track_name,track_id,track_popularity))

df_features = pd.DataFrame()

for idx, dict_trackfeatures in enumerate(sp.audio_features(tracks=[url[1] for url in list_tracksids])):
    dict_trackfeatures['track_name'] = list_tracksids[idx][0]
    dict_trackfeatures['popularity'] = list_tracksids[idx][2]
    df_features = pd.concat([df_features,pd.Series(dict_trackfeatures)], axis=1)

                      #Selects only useful features
df_features=df_features.transpose()[['track_name','popularity','danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']]

#Display Top 5 songs
df_features.head()

Nous sommes prêts. Analysons les données !

Traçons quelques tableaux pour obtenir les premiers modèles sur la musique la plus populaire.

D'après le graphique de gauche, on peut voir que les musiques qui composent notre playlist TOP 50 se situent majoritairement dans la seconde moitié (plus de 0,5 sur 1), ce qui signifie apparemment que c'est très dansant. Comment savoir si ce soupçon est vrai ?

Comparons la danseabilité moyenne de ces chansons avec la musique classique. Bonjour Mozart !

import seaborn as sns
import matplotlib.pyplot as plt

# Let's plot some charts for getting the first patterns about the most popular music

sns.set_theme(context='notebook',style="ticks")
fig, axes = plt.subplots(1, 2, figsize=(10,5))

# Left - Danceability's histogram with kde
sns.distplot(ax=axes[0], x=df_features["danceability"], bins=6, kde=True, color="#5B3BA0")

axes[0].set(xlabel='Danceability', ylabel='Frequency')
axes[0].set_title('TOP 50 Danceability freq.')

# Right - Comparation between the playlist avarage and Mozart's most popular song

                                              # Requiem, K. 626: Lacrimosa
mozart_danceability = sp.audio_features(tracks=['3oHSL6pt9LpNrQZuQGu9wL'])[0]['danceability']

avg_top50_danceability = df_features['danceability'].mean()

sns.barplot(ax= axes[1],
            x = 'who',
            y = 'Danceability',
            data = {'who':['TOP 50','MOZART'],
                   'Danceability':[avg_top50_danceability, mozart_danceability]},
            palette=['#5B3BA0','#A378FF']
            )

axes[1].set(ylabel='Danceability')
axes[1].set_title('Mozart vs TOP 50')

plt.show()

      
                

Comme on peut l'imaginer, Mozart n'est pas dans le Top 50 des chansons les plus jouées. D'après notre brève analyse, Mozart n'a peut-être pas assez de danse pour faire partie de la liste de lecture.

  • La dansabilité de Mozart : 0,162
  • Moyenne de danse dans le TOP 50 : 0,739

#Adding Mozart's song variables to our dataframe
mozart = pd.DataFrame({'track_name':['Mozart'], 'popularity':[0.0]})
for k,v in sp.audio_features(tracks=['3oHSL6pt9LpNrQZuQGu9wL'])[0].items():
    if k in df_features.keys():
        mozart[k]=v

df_features = pd.concat([df_features,mozart], axis=0)
df_features['playlist'] = ['TOP 50' if x != 'Mozart' else 'Mozart' for x in df_features['track_name']] 
                           
df_features.tail(1)

      
                
#Scatter plot plt.figure(dpi=80) sns.scatterplot( data=df_features, x='acousticness',y='loudness', hue="playlist", sizes=(20, 200), legend="full", palette=['#5B3BA0','#D00000'] ) plt.show()

Ce tableau aide en partie à comprendre pourquoi Mozart n'est pas à la mode. Les chansons du Top 50 ont des valeurs similaires des variables « volume » et « acoustique » et sont fortement concentrées dans la partie supérieure gauche du graphique. La tendance est claire : une sonie élevée et des niveaux d'acoustique faibles. Par contre, Mozart va à contre-courant !

Mêmes étapes, une autre playlist

Et si, à la place de Mozart et des chansons tendances, on prenait une playlist avec les meilleures chansons des années 80 ?

Faisons la même chose, mais légèrement différente.

AllOut80s = sp.playlist('37i9dQZF1DX4UtSsGT1Sbe')
list_tracksids = list()

for track_data in AllOut80s['tracks']['items']:
    
    #Gets just the ID (last part of the url)
    track_id = track_data['track']['uri'].split(':')[-1]
    track_name = track_data['track']['name']
    track_popularity = track_data['track']['popularity']
    list_tracksids.append((track_name,track_id,track_popularity))

AllOut80s_features = pd.DataFrame()

for idx, dict_trackfeatures in enumerate(sp.audio_features(tracks=[url[1] for url in list_tracksids])):
    dict_trackfeatures['track_name'] = list_tracksids[idx][0]
    dict_trackfeatures['popularity'] = list_tracksids[idx][2]
    AllOut80s_features = pd.concat([AllOut80s_features,pd.Series(dict_trackfeatures)], axis=1)



                           #Selects only useful features
AllOut80s_features=AllOut80s_features.transpose()[['track_name','popularity','danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']]
AllOut80s_features['playlist'] = 'AllOut80s'

#Handles data types
AllOut80s_features[['danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']]=AllOut80s_features[['danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']].astype(float)

Voir les résultats :

# Setting up concatenated df
df_allsongs = pd.concat([df_features, AllOut80s_features[:50]]).reset_index()

df_allsongs= df_allsongs.drop(df_allsongs.index[df_allsongs['playlist'] == 'Mozart'])

plt.figure(dpi=80)


sns.lmplot(
    data=df_allsongs, x='acousticness',y='loudness', hue="playlist",
    legend="full", palette=['#5B3BA0','#D00000']
)

plt.show()

      
                

En regardant les distributions et les droites de régression pour chaque playlist, on remarque que les tendances sont assez différentes. Bien que la relation entre les variables (pente des courbes) reste assez similaire, les chansons semblent être positionnées dans un schéma, la liste de lecture du Top 50 ayant un niveau de "loudness" plus élevé.

Rien qu'en vérifiant ces deux caractéristiques, nous pouvons voir que la musique des années 80 ressemble plus aux tendances actuelles que Mozart.

Poussons le projet un peu plus loin !

Peut-on prédire, compte tenu de toutes les variables possibles, à quelle playlist appartient une chanson ? Je ne suis pas sûr, mais la réponse est probablement KNeighbors .

J'ai recherché sur Google la chanson la plus représentative des années 80 pour l'utiliser comme entrée de notre prédiction de modélisation :

Features used for modeling
featlist=['danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']

prince = {}
for k,v in sp.audio_features(tracks=['54X78diSLoUDI3joC2bjMz'])[0].items():
    if k in featlist:
        prince[k]=v

prince = pd.DataFrame(prince.items()).transpose()
prince.columns = prince.iloc[0]
prince=prince[1:]
prince[featlist] = prince[featlist].astype(float)
prince

      
                
from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier(n_neighbors=3) X = df_allsongs[featlist] y = df_allsongs['playlist'] knn.fit(X,y) # Prediction prediction = knn.predict(prince) print('The song could be included in the playlist: ', prediction[0])

Merci d'avoir lu!

Contact : www.linkedin.com/in/ivanroblesurquiza

Gazouillement :https://twitter.com/urqivo