R de jeu #1 : API, dataviz, et statistiques

Wrote an API CALL Worked on the first try (mème)
Auteur : Colin Fay
Tags : Actualités
Date :

Bon, avouons-le, sur ce blog, ça ne rigole pas. Entre tutos sur le machine learning, le text-mining et des détails sur {forcats}, on ne prend plus trop le temps de s’amuser avec R. Et des fois, ça fait du bien de retrouver le bac à sable 😉

Alors, aujourd’hui, pas de théorie, que de la pratique, avec une session API, dataviz, et statistiques !

Hello Spotify

Les données Spotify, c’est sûr, il y a un package pour ça. Mais bon, où serait le fun si nous ne faisions pas les choses à la main ?

[pastacode lang=”R” manual=”%23%20Enfin…%20presque%20tout%20%C3%A0%20la%20main%0Alibrary(httr)” message=”” highlight=”” provider=”manual”/]

Web scraping

Première étape, qui ne se fait pas dans R, créer une application sur la plateforme développeur de Spotify. Ça, malheureusement, nous n’allions pas y échapper. Maintenant, il va falloir faire venir notre token dans notre session R.

[pastacode lang=”R” manual=”%23%20Donnons%20un%20joli%20petit%20nom%20%C3%A0%20notre%20application%0Aapp_id%20%3C-%20%22app_spotify%22%0A%0A%23%20Les%20tokens%20de%20l’app%0Aclient_id%20%3C-%20%22***%22%0Aclient_secret%20%3C-%20%22****%22%0A%0A%23%20Cr%C3%A9ons%20un%20oauth_endpoint%2C%20autrement%20dit%20un%20identifiant%20pour%20acc%C3%A9der%20%C3%A0%20l’API%0Aspoti_ep%20%3C-%20httr%3A%3Aoauth_endpoint(%0A%20%20authorize%20%3D%20%22https%3A%2F%2Faccounts.spotify.com%2Fauthorize%22%2C%0A%20%20access%20%3D%20%22https%3A%2F%2Faccounts.spotify.com%2Fapi%2Ftoken%22)%0Aspoti_app%20%3C-%20httr%3A%3Aoauth_app(app_id%2C%20client_id%2C%20client_secret)%0A%0Aaccess_token%20%3C-%20httr%3A%3Aoauth2.0_token(spoti_ep%2C%20spoti_app%2C%20scope%20%3D%20%22user-library-read%20user-read-recently-played%22)%0A—%0A%3CToken%3E%0A%3Coauth_endpoint%3E%0A%20authorize%3A%20https%3A%2F%2Faccounts.spotify.com%2Fauthorize%0A%20access%3A%20%20%20%20https%3A%2F%2Faccounts.spotify.com%2Fapi%2Ftoken%0A%3Coauth_app%3E%20app_spotify%0A%20%20key%3A%20%20%20%20***%0A%20%20secret%3A%20%3Chidden%3E%0A%3Ccredentials%3E%20access_token%2C%20token_type%2C%20expires_in%2C%20refresh_token%2C%20scope%0A—%20″ message=”” highlight=”” provider=”manual”/]

Eh voilà, {httr} a fait une grande partie du boulot à notre place. Il vient notamment d‘enregistrer dans notre dossier local un fichier .httr-oauth, qui contient le token pour effectuer des requêtes sur l’API. Allons chercher les données de ma bibliothèque.

[pastacode lang=”R” manual=”tracks%20%3C-%20GET(%22https%3A%2F%2Fapi.spotify.com%2Fv1%2Fme%2Ftracks%22%2C%20config(token%20%3D%20access_token)%2C%20query%20%3D%20list(limit%20%3D%2050))%0Acontent(tracks)%24total%0A%5B1%5D%202367″ message=”” highlight=”” provider=”manual”/]

Donc, 2367 tracks à aller chercher. Malheureusement, Spotify ne permet de requêter que par groupe de 50 maximum. Et avouons-le, on ne va pas y aller à la main, 50 par 50… Un petit map ?

[pastacode lang=”R” manual=”library(tidyverse)%0Alibrary(jsonlite)%0Aget_tracks%20%3C-%20function(offset)%7B%0A%20%20print(offset)%0A%20%20api_res%20%3C-%20GET(%22https%3A%2F%2Fapi.spotify.com%2Fv1%2Fme%2Ftracks%22%2C%20config(token%20%3D%20access_token)%2C%20query%20%3D%20list(limit%20%3D%2050%2C%20offset%20%3D%20offset))%0A%20%20played%20%3C-%20api_res%24content%20%25%3E%25%0A%20%20%20%20rawToChar()%20%25%3E%25%0A%20%20%20%20fromJSON(flatten%20%3D%20TRUE)%20%0A%20%20tibble(track%20%3D%20played%24items%24track.name%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20trackid%20%3D%20played%24items%24track.album.id%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20track_uri%20%3D%20gsub(%22spotify%3Atrack%3A%22%2C%20%22%22%2C%20played%24items%24track.uri)%20%25%7C%7C%25%20NA%2C%0A%20%20%20%20%20%20%20%20%20album_name%20%3D%20played%24items%24track.album.name%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20album_id%20%3D%20played%24items%24track.album.id%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20artist%20%3D%20map_chr(played%24items%24track.artists%2C%20~.x%24name%5B1%5D%20%25%7C%7C%25%20NA)%2C%20%0A%20%20%20%20%20%20%20%20%20duration%20%3D%20played%24items%24track.duration_ms%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20explicit%20%3D%20played%24items%24track.explicit%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20popularity%20%3D%20played%24items%24track.popularity%20%25%7C%7C%25%20NA)%0A%7D%0A%0Acolin_tracks%20%3C-%20map_df(seq(0%2C2367%2C%2050)%2C%20get_tracks)%0Adim(colin_tracks)%0A%5B1%5D%202367%20%20%20%209″ message=”” highlight=”” provider=”manual”/]

2367 individus, répartis sur 9 variables.

Dataviz

Aller, on regarde un peu ce qu’il s’y trame, dans ce dataset ? Des tracks plutôt populaires ?

[pastacode lang=”R” manual=”library(viridisLite)%0Alibrary(ggthemes)%0Apalette%20%3C-%20viridis(256%2C%20option%20%3D%20%22D%22)%0Aggplot(colin_tracks%2C%20aes(x%20%3D%20pop))%20%2B%20%0A%20%20geom_density(fill%20%3D%20palette%5B1%5D)%20%2B%20%0A%20%20labs(title%20%3D%20%22Popularit%C3%A9%20des%20tracks%20de%20la%20biblioth%C3%A8que%22%2C%20%0A%20%20%20%20%20%20%20subtitle%20%3D%20%22donn%C3%A9es%20via%20Spotify%22%2C%20%0A%20%20%20%20%20%20%20x%20%3D%20%22Popularit%C3%A9%22%2C%20%0A%20%20%20%20%20%20%20y%20%3D%20%22Densit%C3%A9%22%2C%20%0A%20%20%20%20%20%20%20caption%20%3D%20%22thinkr.fr%22)%20%2B%20%0A%20%20theme_few()” message=”” highlight=”” provider=”manual”/]

Pas très populaires, les morceaux de cette bibliothèque, à première vue…

Côté durée, un rapide coup d’oeil nous donne l’impression que c’est assez varié… juste une impression ?

[pastacode lang=”R” manual=”colin_tracks%20%25%3E%25%0A%20%20%23%20Transformons%20les%20dur%C3%A9es%20en%20secondes%0A%20%20mutate(duration%20%3D%20duration%20%2F%201000)%20%20%25%3E%25%0A%20%20ggplot(aes(x%20%3D%20duration))%20%2B%20%0A%20%20geom_density(fill%20%3D%20sample(palette%2C%201))%20%2B%20%0A%20%20labs(title%20%3D%20%22Dur%C3%A9e%20des%20tracks%20de%20la%20biblioth%C3%A8que%22%2C%20%0A%20%20%20%20%20%20%20subtitle%20%3D%20%22donn%C3%A9es%20via%20Spotify%22%2C%20%0A%20%20%20%20%20%20%20x%20%3D%20%22Dur%C3%A9e%20du%20morceau%22%2C%20%0A%20%20%20%20%20%20%20y%20%3D%20%22Densit%C3%A9%22%2C%20%0A%20%20%20%20%20%20%20caption%20%3D%20%22thinkr.fr%22)%20%2B%20%0A%20%20theme_few()” message=”” highlight=”” provider=”manual”/]

Une distribution avec un mode autour de 250 secondes (environ 4 minutes).

Bon, ils sont sortis quand tous ces albums ? Nous allons avoir besoin de faire une nouvelle requête :

[pastacode lang=”R” manual=”library(glue)%0A%0Aget_album%20%3C-%20function(id)%7B%0A%20%20%23%20%C3%89vitons%20de%20se%20faire%20kicker%20par%20l’API%20Spotify%0A%20%20Sys.sleep(0.1)%0A%20%20call%20%3C-%20GET(glue(%22https%3A%2F%2Fapi.spotify.com%2Fv1%2Falbums%2F%7Bid%7D%22)%2C%20config(token%20%3D%20access_token)%2C%20query%20%3D%20list(limit%20%3D%2050))%20%25%3E%25%20content()%0A%20%20tibble(artist%20%3D%20call%24artists%5B%5B1%5D%5D%24name%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20album%20%3D%20call%24name%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20album_cover%20%3D%20call%24images%5B%5B1%5D%5D%24url%20%25%7C%7C%25%20NA%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20release%20%3D%20gsub(%22(%5E….).*%22%2C%22%5C%5C1%22%2C%20call%24release_date)%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20tracks%20%3D%20length(call%24tracks%24items)%20%25%7C%7C%25%20NA%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20genre%20%3D%20ifelse(length(call%24genres)%20%3D%3D%200%2C%20NA%2C%20call%24genres)%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20popularity%20%3D%20call%24popularity%20%25%7C%7C%25%20NA)%0A%7D%0A%0Acolin_albums%20%3C-%20map_df(unique(colin_tracks%24album_id)%2C%20get_album)” message=”” highlight=”” provider=”manual”/]

Donc, niveau année de sortie, on en est où ?

[pastacode lang=”R” manual=”ggplot(colin_albums%2C%20aes(as.numeric(release)))%20%2B%0A%20%20geom_density(fill%20%3D%20sample(palette%2C%201))%20%2B%20%0A%20%20labs(title%20%3D%20%22Ann%C3%A9e%20de%20sortie%20des%20albums%20de%20la%20biblioth%C3%A8que%22%2C%20%0A%20%20%20%20%20%20%20subtitle%20%3D%20%22donn%C3%A9es%20via%20Spotify%22%2C%20%0A%20%20%20%20%20%20%20x%20%3D%20%22Ann%C3%A9e%20de%20sortie%20de%20l’album%22%2C%20%0A%20%20%20%20%20%20%20y%20%3D%20%22Densit%C3%A9%22%2C%20%0A%20%20%20%20%20%20%20caption%20%3D%20%22thinkr.fr%22)%20%2B%20%0A%20%20theme_few()” message=”” highlight=”” provider=”manual”/]

Globalement, les morceaux sont assez récents.

Track by track

Et si on se faisait une petite analyse des tracks ? Merci Spotify de nous fournir des données sur les caractéristiques audio de chaque morceau 🙂

[pastacode lang=”R” manual=”track_features%20%3C-%20function(id)%7B%0A%20%20print(id)%0A%20%20%23%20%C3%89vitons%20de%20se%20faire%20kicker%20par%20l’API%20Spotify%0A%20%20Sys.sleep(0.1)%0A%20%20api_res%20%3C-%20GET(glue(%22https%3A%2F%2Fapi.spotify.com%2Fv1%2Faudio-features%2F%7Bid%7D%22)%2C%20config(token%20%3D%20access_token))%0A%20%20res%20%3C-%20api_res%24content%20%25%3E%25%0A%20%20%20%20rawToChar()%20%25%3E%25%0A%20%20%20%20fromJSON(flatten%20%3D%20TRUE)%0A%20%20tibble(danceability%20%3D%20res%24danceability%20%25%7C%7C%25%20NA%2C%0A%20%20%20%20%20%20%20%20%20energy%20%3D%20res%24energy%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20key%20%3D%20res%24key%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20loudness%20%3D%20res%24loudness%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20mode%20%3D%20res%24mode%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20speechiness%20%3D%20res%24speechiness%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20acousticness%20%3D%20res%24acousticness%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20instrumentalness%20%3D%20res%24instrumentalness%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20liveness%20%3D%20res%24liveness%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20valence%20%3D%20res%24valence%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20tempo%20%3D%20res%24tempo%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20type%20%3D%20res%24type%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20id%20%3D%20res%24id%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20uri%20%3D%20res%24uri%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20track_href%20%3D%20res%24track_href%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20analysis_url%20%3D%20res%24analysis_url%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20duration_ms%20%3D%20res%24duration_ms%20%25%7C%7C%25%20NA%2C%20%0A%20%20%20%20%20%20%20%20%20time_signature%20%3D%20res%24time_signature%20%25%7C%7C%25%20NA%0A%20%20%20%20%20%20%20%20%20)%0A%7D%0Atracks_features%20%3C-%20map_df(colin_tracks%24track_uri%2C%20track_features)” message=”” highlight=”” provider=”manual”/]

Et nous voici donc avec deux tables contenant les tracks de la bibliothèque. On va commencer par s’en faire un bon gros tableau :

[pastacode lang=”R” manual=”full_tracks%20%3C-%20full_join(colin_tracks%2C%20tracks_features%2C%20by%20%3D%20c(%22track_uri%22%20%3D%20%22id%22))” message=”” highlight=”” provider=”manual”/]

Le tableau complet fait donc 2367 morceaux, sur 26 variables, qui contiennent notamment : le nom du morceau, l’album et l’artiste, un score de confiance sur l'”acousticness”, un score de dançabilité, la durée, un score d’énergie, un score prédit sur la présence ou non de chant, la tonalité, un score de présence ou non d’une audience (en gros, si c’est en concert ou non), la “loudness” du morceau, son mode (majeur == 1 ou mineur == 0), la présence de mot parlé, le tempo, le nombre de mesures, et la valence, qui est un calcul de la “positivité” du morceau : plus le score est proche de 1, plus le morceau est considéré comme positif. Débarrassons-nous des colonnes superflues :

[pastacode lang=”R” manual=”full_tracks%20%25%3C%3E%25%20select(-matches(%22id%7Curi%7Ctype%7Chre%7Curl%7Cduration_ms%22))%0A” message=”” highlight=”” provider=”manual”/]

Analyse factorielle

Partons sur une rapide analyse en composante principale, afin de déterminer quelles sont les variables qui décrivent le mieux le jeu de données.

[pastacode lang=”R” manual=”library(FactoMineR)%0Ares_pca%20%3C-%20PCA(full_tracks%2C%20quali.sup%20%3D%201%3A3%2C%20quanti.sup%20%3D%20%205%3A6)%0Ares_pca%24eig%0A%20%20%20%20%20%20%20%20eigenvalue%20percentage%20of%20variance%20cumulative%20percentage%20of%20variance%0Acomp%201%20%20%202.8598390%20%20%20%20%20%20%20%20%20%20%20%20%2021.9987616%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2021.99876%0Acomp%202%20%20%201.8598677%20%20%20%20%20%20%20%20%20%20%20%20%2014.3066749%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2036.30544%0Acomp%203%20%20%201.2468081%20%20%20%20%20%20%20%20%20%20%20%20%20%209.5908313%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2045.89627%0Acomp%204%20%20%201.1089244%20%20%20%20%20%20%20%20%20%20%20%20%20%208.5301874%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2054.42646%0Acomp%205%20%20%201.0198197%20%20%20%20%20%20%20%20%20%20%20%20%20%207.8447671%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2062.27122%0Acomp%206%20%20%200.9280408%20%20%20%20%20%20%20%20%20%20%20%20%20%207.1387757%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2069.41000%0Acomp%207%20%20%200.8788716%20%20%20%20%20%20%20%20%20%20%20%20%20%206.7605510%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2076.17055%0Acomp%208%20%20%200.8434598%20%20%20%20%20%20%20%20%20%20%20%20%20%206.4881520%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2082.65870%0Acomp%209%20%20%200.7605218%20%20%20%20%20%20%20%20%20%20%20%20%20%205.8501676%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2088.50887%0Acomp%2010%20%200.7124319%20%20%20%20%20%20%20%20%20%20%20%20%20%205.4802456%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2093.98911%0Acomp%2011%20%200.3712415%20%20%20%20%20%20%20%20%20%20%20%20%20%202.8557038%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2096.84482%0Acomp%2012%20%200.2803237%20%20%20%20%20%20%20%20%20%20%20%20%20%202.1563360%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2099.00115%0Acomp%2013%20%200.1298500%20%20%20%20%20%20%20%20%20%20%20%20%20%200.9988463%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20100.00000″ message=”” highlight=”” provider=”manual”/]

Donc, 50% de l’information expliquée par les quatre premières dimensions. Si l’on en croit le cercle des corrélations du premier pan, valence et danceability sont corrélées, tout comme loudness et energy (ce qui fait sens, n’est-ce pas ?) et duration et instrumentalness : ça, il fallait s’y attendre, les tracks les plus longues sont souvent instrumentales. Pas grand-chose à dire sur key, tempo et liveness, qui sont mal projetés sur notre premier plan. Quant à acousticness, cette variable est corrélée négativement à loudness et energy. Mais ça aussi, il fallait s’y attendre 🙂

Quelles sont les contributions des variables à la construction des axes ?

[pastacode lang=”R” manual=”res_pca%24var%24contrib%0A%0Aduration%20%20%20%20%20%20%20%20%20%200.061557070%20%208.51433464%2017.704493327%20%203.1881352%2015.79235016%0Adanceability%20%20%20%20%20%204.832994227%2025.13234108%20%204.825060423%20%200.5035654%20%202.11311954%0Aenergy%20%20%20%20%20%20%20%20%20%20%2030.381631436%20%200.64333948%20%200.002877914%20%200.7775590%20%200.11330155%0Akey%20%20%20%20%20%20%20%20%20%20%20%20%20%20%200.073595128%20%200.05875634%2023.343938164%2015.7110560%20%208.71748423%0Aloudness%20%20%20%20%20%20%20%20%2025.677788989%20%202.51663911%20%200.008358477%20%200.1136058%20%200.06260330%0Amode%20%20%20%20%20%20%20%20%20%20%20%20%20%200.066270264%20%200.67636383%2028.394470066%2017.9258895%20%200.65408755%0Aspeechiness%20%20%20%20%20%20%206.050315299%20%200.95446561%20%200.027011474%2012.0799400%20%200.06130865%0Aacousticness%20%20%20%20%2025.412407378%20%201.26497762%20%201.408168526%20%202.1828277%20%200.87210617%0Ainstrumentalness%20%200.008530238%2020.48293565%20%202.794116204%20%208.6859354%20%201.08643982%0Aliveness%20%20%20%20%20%20%20%20%20%202.488517168%20%200.69130229%2013.890997842%2023.4841748%20%200.08728705%0Avalence%20%20%20%20%20%20%20%20%20%20%202.214334583%2033.55688478%20%200.283437162%20%202.6512231%20%200.67163776%0Atempo%20%20%20%20%20%20%20%20%20%20%20%20%202.653385662%20%200.15222361%20%204.845549398%2012.0540043%2031.57206854%0Atime_signature%20%20%20%200.078672559%20%205.35543597%20%202.471521022%20%200.6420838%2038.19620568″ message=”” highlight=”” provider=”manual”/]

Nous avons un jeu de données avec 2367 observations… En clair, difficile de lire le graphe des individus. Petit tour donc du côté des résultats de la PCA :

[pastacode lang=”R” manual=”dim1%20%3C-%20res_pca%24ind%24contrib%20%25%3E%25%0A%20%20as.data.frame()%20%25%3E%25%0A%20%20mutate(indiv%20%3D%20row.names(.))%20%25%3E%25%0A%20%20arrange(desc(Dim.1))%20%25%3E%25%0A%20%20top_n(5%2C%20Dim.1)%20%0Adim1%0A%20%20%20%20%20%20Dim.1%20%20%20%20%20%20Dim.2%20%20%20%20%20%20%20Dim.3%20%20%20%20%20%20%20%20Dim.4%20%20%20%20%20%20%20%20%20Dim.5%20indiv%0A1%200.5576816%200.30118126%200.034780033%200.0162052826%200.03300476161%20%201269%0A2%200.4899255%200.21291438%200.008330373%200.0315234685%200.00000120409%20%201274%0A3%200.4786848%200.37989445%200.010499758%200.0164488273%200.00996510231%20%20%20912%0A4%200.4775598%200.53584278%200.014363688%200.0006587940%200.10468518176%20%20%20897%0A5%200.4633826%200.08630106%200.058267384%200.0001801211%200.08943254035%20%201865%0A%0Adim2%20%3C-%20res_pca%24ind%24contrib%20%25%3E%25%0A%20%20as.data.frame()%20%25%3E%25%0A%20%20mutate(indiv%20%3D%20row.names(.))%20%25%3E%25%0A%20%20arrange(desc(Dim.2))%20%25%3E%25%0A%20%20top_n(5%2C%20Dim.2)%20%0Adim2%0A%20%20%20%20%20%20%20%20Dim.1%20%20%20%20%20Dim.2%20%20%20%20%20%20%20%20Dim.3%20%20%20%20%20%20%20Dim.4%20%20%20%20%20%20%20Dim.5%20indiv%0A1%200.200604880%200.6177477%200.4459632115%200.050470953%200.426768240%20%20%20924%0A2%200.477559778%200.5358428%200.0143636880%200.000658794%200.104685182%20%20%20897%0A3%200.001126611%200.5203046%200.2807840462%200.100882448%200.016343561%20%20%20%2074%0A4%200.157530632%200.5153425%200.1705381199%200.004767181%200.246680651%20%20%20918%0A5%200.387565069%200.3940052%200.0006005656%200.021397267%200.009522307%20%20%20911%0A%0Aindiv%20%3C-%20c(dim1%24indiv%2C%20dim2%24indiv)” message=”” highlight=”” provider=”manual”/]

Voici donc les morceaux qui contribuent le plus à la formation du plan :

[pastacode lang=”R” manual=”full_tracks%20%25%3E%25%0A%20%20mutate(individus%20%3D%20row.names(.))%20%25%3E%25%0A%20%20filter(individus%20%25in%25%20indiv)%20%25%3E%25%0A%20%20select(track%2C%20artist)%0A%23%20A%20tibble%3A%209%20x%202%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20track%20%20%20%20%20%20%20%20%20%20%20artist%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cchr%3E%20%20%20%20%20%20%20%20%20%20%20%20%3Cchr%3E%0A1%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Spirit%20of%20the%20North%20%20%20%20%20%20%20%20%20%20Eldamar%0A2%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Piano%20Concerto%20In%20G%20Major%2C%20M.%2083%3A%202.%20Adagio%20assai%20%20%20%20Maurice%20Ravel%0A3%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Sonata%20No.%202%2C%20Op.%2036%3A%20II.%20Non%20Allegro%20%20%20H%C3%A9l%C3%A8ne%20Grimaud%0A4%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Pictures%20at%20an%20Exhibition%3A%202.%20The%20Old%20Castle%2FIl%20vecchio%20castello%20Sir%20Simon%20Rattle%0A5%20Wagner%3A%20Tannh%C3%A4user%2C%20WWV%2070%3A%20Overture%20(Andante%20maestoso%20-%20Allegro%20-%20Tempo%20primo)%20%20%20Richard%20Wagner%0A6%20Le%20sacre%20du%20printemps%20(The%20Rite%20of%20Spring)%20(1943%20version)%3A%20Part%202%3A%20Le%20sacrifice%20%20Igor%20Stravinsky%0A7%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Finding%20It%20There%20%20%20%20%20%20%20%20%20Goldmund%0A8%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Ouendake%20%20%20%20%20%20%20%20%20Goldmund%0A9%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Carved%20Tree%20Inn%20%20%20Bjorn%20Eriksson” message=”” highlight=”” provider=”manual”/]

Statistiques

On a écrit juste au-dessus que certaines variables étaient corrélées les unes aux autres sur le plan factoriel. Testons-le de manière un peu “old school” :

[pastacode lang=”R” manual=”library(broom)%0Acalls%20%3C-%20list(cor.test(full_tracks%24danceability%2C%20full_tracks%24valence)%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20cor.test(full_tracks%24loudness%2C%20full_tracks%24energy)%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20cor.test(full_tracks%24duration%2C%20full_tracks%24instrumentalness))%0Amap_df(calls%2C%20~%20tidy(.x)%20%25%3E%25%20select(estimate%2C%20p.value%2C%20conf.low%2C%20conf.high%2C%20alternative))%0A%0A%20%20%20estimate%20%20%20%20%20%20%20p.value%20%20conf.low%20conf.high%20alternative%0A1%200.5660656%202.139758e-200%200.5380291%200.5928511%20%20%20two.sided%0A2%200.8175519%20%200.000000e%2B00%200.8037366%200.8304861%20%20%20two.sided%0A3%200.1934783%20%202.140058e-21%200.1543925%200.2319594%20%20%20two.sided” message=”” highlight=”” provider=”manual”/]

Bon, il semblerait que la corrélation se vérifie 🙂

Passons maintenant à quelques régressions. Par exemple, la variable “explicite” est-elle liée à d’autres variables du jeu de données ?

[pastacode lang=”R” manual=”data_glm%20%3C-%20full_tracks%20%25%3E%25%0A%20%20select(duration%3Atime_signature)%20%25%3E%25%0A%20%20mutate(explicit%20%3D%20as.numeric(explicit))%0Amodel%20%3C-%20glm(explicit%20~%20.%2C%20data%20%3D%20data_glm)%0A%0A%23%20Parce%20qu’on%20aime%20bien%20les%20jolies%20sorties%0Atidy_and_slice%20%3C-%20function(x%2C%20digits%20%3D%202)%7B%0A%20%20tidy(x)%20%25%3E%25%20%0A%20%20%20%20slice(2%3An())%20%25%3E%25%20%0A%20%20%20%20mutate(RR%20%3D%20exp(estimate))%20%25%3E%25%0A%20%20%20%20mutate_at(.vars%20%3D%20vars(estimate%2C%20std.error%2C%20statistic%2C%20RR)%2C%20.funs%20%3D%20round%2C%20digits%20%3D%203)%20%25%3E%25%0A%20%20%20%20select(term%2C%20statistic%2C%20p.value%2C%20RR)%0A%7D%0A%0Atidy_and_slice(model)%20%25%3E%25%0A%20%20filter(p.value%20%3C%200.05)%0A%0A%23%20A%20tibble%3A%206%20x%204%0A%20%20%20%20%20%20%20%20%20%20term%20statistic%20%20%20%20%20%20p.value%20%20%20%20RR%0A%20%20%20%20%20%20%20%20%20%3Cchr%3E%20%20%20%20%20%3Cdbl%3E%20%20%20%20%20%20%20%20%3Cdbl%3E%20%3Cdbl%3E%0A1%20%20%20popularity%20%20%20%20%205.275%201.449550e-07%201.002%0A2%20danceability%20%20%20%20%203.836%201.283798e-04%201.159%0A3%20%20%20%20%20loudness%20%20%20%20%203.332%208.743460e-04%201.007%0A4%20%20speechiness%20%20%20%20%208.513%202.966253e-17%201.946%0A5%20%20%20%20%20liveness%20%20%20%20%202.731%206.369635e-03%201.086%0A6%20%20%20%20%20%20valence%20%20%20%20-3.324%209.019833e-04%200.912″ message=”” highlight=”” provider=”manual”/]

Effectivement. On voit par exemple que pour chaque augmentation d’une unité de la variable popularity, le risque d’être classé en explicit est multiplié par 1.002. Les chansons très populaires seraient-elles plus explicites ?

[pastacode lang=”R” manual=”ggplot(full_tracks%2C%20aes(popularity%2C%20fill%20%3D%20explicit))%20%2B%20%0A%20%20geom_density()%20%2B%20%0A%20%20scale_fill_manual(values%20%3D%20sample(palette%2C%202))%20%2B%20%0A%20%20facet_grid(explicit%20~%20.)%20%2B%20%0A%20%20labs(title%20%3D%20%22Popularit%C3%A9%20et%20chanson%20’explicit’%22%2C%20%0A%20%20%20%20%20%20%20subtitle%20%3D%20%22donn%C3%A9es%20via%20Spotify%22%2C%20%0A%20%20%20%20%20%20%20x%20%3D%20%22Popularit%C3%A9%22%2C%20%0A%20%20%20%20%20%20%20y%20%3D%20%22Densit%C3%A9%22%2C%20%0A%20%20%20%20%20%20%20caption%20%3D%20%22thinkr.fr%22)%20%2B%20%0A%20%20theme_few()” message=”” highlight=”” provider=”manual”/]

Bien, cela ne saute pas aux yeux, mais on décèle quelque chose. Nous avons également vu que pour chaque augmentation d’une unité de loudness, les chances d’appartenir à la classe explicit sont multipliées par 1.007.

[pastacode lang=”R” manual=”ggplot(full_tracks%2C%20aes(loudness%2C%20fill%20%3D%20explicit))%20%2B%20%0A%20%20geom_density()%20%2B%20%0A%20%20scale_fill_manual(values%20%3D%20sample(palette%2C%202))%20%2B%20%0A%20%20facet_grid(explicit%20~%20.)%20%2B%20%0A%20%20labs(title%20%3D%20%22Loudness%20et%20chanson%20’explicit’%22%2C%20%0A%20%20%20%20%20%20%20subtitle%20%3D%20%22donn%C3%A9es%20via%20Spotify%22%2C%20%0A%20%20%20%20%20%20%20x%20%3D%20%22Loudness%22%2C%20%0A%20%20%20%20%20%20%20y%20%3D%20%22Densit%C3%A9%22%2C%20%0A%20%20%20%20%20%20%20caption%20%3D%20%22thinkr.fr%22)%20%2B%20%0A%20%20theme_few()” message=”” highlight=”” provider=”manual”/]

Il semblerait que les morceaux explicits soient plus concentrés vers les valeurs hautes de loudness !

Aller, une petite régression linéaire pour le fun ?

[pastacode lang=”R” manual=”modelm%20%3C-%20lm(energy%20~%20loudness%2C%20data%20%3D%20full_tracks)%0Asummary(modelm)%24r.squared%20%0A%5B1%5D%200.6683911″ message=”” highlight=”” provider=”manual”/]

Pas trop mal. Ça donne quoi sur un graphe ?

[pastacode lang=”R” manual=”ggplot(train%2C%20aes(energy%2C%20loudness))%20%2B%20%0A%20%20geom_point(color%20%3D%20sample(palette%2C%201))%20%2B%20%0A%20%20geom_smooth(method%20%3D%20%22lm%22)%20%2B%0A%20%20labs(title%20%3D%20%22Energy%20et%20loudness%22%2C%20%0A%20%20%20%20%20%20%20subtitle%20%3D%20%22donn%C3%A9es%20via%20Spotify%22%2C%20%0A%20%20%20%20%20%20%20x%20%3D%20%22Energy%22%2C%20%0A%20%20%20%20%20%20%20y%20%3D%20%22loudness%22%2C%20%0A%20%20%20%20%20%20%20caption%20%3D%20%22thinkr.fr%22)%20%2B%20%0A%20%20theme_few()” message=”” highlight=”” provider=”manual”/]

Oui, bon, il y a quelque chose, effectivement !

Text-mining

Et pour terminer, amusons nous avec un peu de text-mining sur le nom des morceaux. Première étape : quels sont les termes les plus fréquents ?

[pastacode lang=”R” manual=”library(tidytext)%0Alibrary(proustr)%0A%23%20On%20va%20cr%C3%A9er%20un%20seul%20tableau%20qui%20enl%C3%A8ve%20les%20stop_word%20anglais%2C%20fran%C3%A7ais%2C%20et%20les%20chiffres%0A%0Astopwordsfull%20%3C-%20rbind(stop_words%5B%2C1%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20data.frame(word%20%3D%20as.character(1%3A2017))%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20proustr%3A%3Aproust_stopwords())%0A%0A%0Amono%20%3C-%20full_tracks%20%25%3E%25%0A%20%20unnest_tokens(word%2C%20track)%20%25%3E%25%0A%20%20%23%20On%20stemme%20%0A%20%20pr_stem_words(word%2C%20language%20%3D%20%22english%22)%20%25%3E%25%0A%20%20%23%20On%20compte%0A%20%20count(word)%20%25%3E%25%0A%20%20%23%20Bye%20bye%20stopwords%0A%20%20anti_join(stopwordsfull)%20%25%3E%25%0A%20%20%23%20On%20ne%20garde%20que%20les%2015%20premiers%0A%20%20top_n(15%2C%20n)%20%25%3E%25%0A%20%20arrange(desc(n))%0A%0Amono%0A%23%20A%20tibble%3A%2015%20x%202%0A%20%20%20%20%20%20word%20%20%20%20%20n%0A%20%20%20%20%20%3Cchr%3E%20%3Cint%3E%0A%201%20%20remast%20%20%20188%0A%202%20version%20%20%20148%0A%203%20%20%20%20live%20%20%20%2077%0A%204%20%20%20%20love%20%20%20%2034%0A%205%20%20%20remix%20%20%20%2034%0A%206%20%20%20%20feat%20%20%20%2028%0A%207%20%20%20singl%20%20%20%2027%0A%208%20%20%20%20hate%20%20%20%2024%0A%209%20%20%20black%20%20%20%2023%0A10%20%20%20digit%20%20%20%2023%0A11%20%20%20%20danc%20%20%20%2022%0A12%20%20%20%20%20mix%20%20%20%2022%0A13%20%20%20world%20%20%20%2022%0A14%20%20%20%20blue%20%20%20%2020%0A15%20%20%20%20dead%20%20%20%2020″ message=”” highlight=”” provider=”manual”/]

Partons voir du côté des bigrams :

[pastacode lang=”R” manual=”bi%20%3C-%20full_tracks%20%25%3E%25%0A%20%20select(track)%20%25%3E%25%0A%20%20unnest_tokens(word%2C%20track%2C%20token%20%3D%20%22ngrams%22%2C%20n%20%3D%202)%20%25%3E%25%0A%20%20separate(word%2C%20c(%22word1%22%2C%20%22word2%22)%2C%20sep%20%3D%20%22%20%22)%20%25%3E%25%0A%20%20filter(!word1%20%25in%25%20stopwordsfull%24word)%20%25%3E%25%0A%20%20filter(!word2%20%25in%25%20stopwordsfull%24word)%20%25%3E%25%0A%20%20%23%20On%20stemme%20%0A%20%20pr_stem_words(word1%2C%20language%20%3D%20%22english%22)%20%25%3E%25%0A%20%20pr_stem_words(word2%2C%20language%20%3D%20%22english%22)%20%25%3E%25%0A%20%20unite(word%2C%20word1%2C%20word2%2C%20sep%20%3D%20%22%20%22)%20%25%3E%25%20%0A%20%20%23%20On%20compte%0A%20%20count(word)%20%25%3E%25%0A%20%20%23%20On%20ne%20garde%20que%20les%2010%20premiers%0A%20%20top_n(10%2C%20n)%20%25%3E%25%0A%20%20arrange(desc(n))%0A%0Abi%0A%23%20A%20tibble%3A%2010%20x%202%0A%20%20%20%20%20%20%20%20%20%20%20%20%20word%20%20%20%20%20n%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cchr%3E%20%3Cint%3E%0A%201%20remast%20version%20%20%20%2090%0A%202%20%20singl%20version%20%20%20%2021%0A%203%20%20%20digit%20remast%20%20%20%2016%0A%204%20%20%20live%20version%20%20%20%2016%0A%205%20%20%20%20live%20wacken%20%20%20%2014%0A%206%20%20%20london%20union%20%20%20%2012%0A%207%20%20%20%20%20union%20live%20%20%20%2012%0A%208%20%20%20%20bonus%20track%20%20%20%2010%0A%209%20%20%20%20%20radio%20edit%20%20%20%20%207%0A10%20%20%20%20%20live%20bonus%20%20%20%20%206″ message=”” highlight=”” provider=”manual”/]

Et un peu de topic modeling pour voir ?

[pastacode lang=”R” manual=”dtm%20%3C-%20full_tracks%20%25%3E%25%0A%20%20unnest_tokens(word%2C%20track)%20%25%3E%25%0A%20%20%23%20On%20compte%0A%20%20count(word%2C%20artist)%20%25%3E%25%0A%20%20%23%20Bye%20bye%20stopwords%0A%20%20anti_join(stopwordsfull)%20%25%3E%25%0A%20%20cast_dtm(artist%2C%20term%20%3D%20word%2C%20value%20%3D%20n)%0A%0Alibrary(topicmodels)%0Alda_model%20%3C-%20LDA(x%20%3D%20dtm%2C%20k%20%3D%206%2C%20control%20%3D%20list(seed%20%3D%202811))%0A%0A%23%20Quels%20sont%20les%20individus%20les%20plus%20repr%C3%A9sentatifs%20de%20chaque%20topic%20%3F%0A%0Atidy(lda_model%2C%20matrix%20%3D%20%22gamma%22)%20%25%3E%25%20%0A%20%20group_by(topic)%20%25%3E%25%20%0A%20%20arrange(desc(gamma))%20%25%3E%25%20%0A%20%20top_n(1)%20%25%3E%25%20%0A%20%20arrange(topic)%0A%0A%23%20A%20tibble%3A%206%20x%203%0A%23%20Groups%3A%20%20%20topic%20%5B6%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20document%20topic%20%20%20%20%20gamma%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cchr%3E%20%3Cint%3E%20%20%20%20%20%3Cdbl%3E%0A1%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Hubert%20F%C3%A9lix%20Thi%C3%A9faine%20%20%20%20%201%200.9966540%0A2%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Kreator%20%20%20%20%202%200.9983608%0A3%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20David%20Bowie%20%20%20%20%203%200.9992388%0A4%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Terror%20%20%20%20%204%200.9949339%0A5%20The%20Broken%20Circle%20Breakdown%20Bluegrass%20Band%20%20%20%20%205%200.9933348%0A6%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Orelsan%20%20%20%20%206%200.9938862%0A” message=”” highlight=”” provider=”manual”/]

Un partitionnement qui, à première vue, semble faire sens 😉 Et si on visualise les topics ?

[pastacode lang=”R” manual=”tidy(lda_model%2C%20matrix%20%3D%20%22beta%22)%20%25%3E%25%0A%20%20group_by(topic)%20%25%3E%25%0A%20%20top_n(10%2C%20beta)%20%25%3E%25%0A%20%20ungroup()%20%25%3E%25%0A%20%20arrange(topic%2C%20-beta)%20%25%3E%25%0A%20%20ggplot(aes(reorder(term%2C%20beta)%2C%20beta%2C%20fill%20%3D%20factor(topic)))%20%2B%0A%20%20geom_col(show.legend%20%3D%20FALSE)%20%2B%0A%20%20facet_wrap(~%20topic%2C%20scales%20%3D%20%22free%22)%20%2B%0A%20%20scale_fill_manual(values%20%3D%20sample(palette))%20%2B%20%0A%20%20coord_flip()%20%2B%20%0A%20%20labs(x%20%3D%20%22Topic%22%2C%20%0A%20%20%20%20%20%20%20y%20%3D%20%22beta%20score%22%2C%20%0A%20%20%20%20%20%20%20subtitle%20%3D%20%22donn%C3%A9es%20via%20Spotify%22%2C%20%0A%20%20%20%20%20%20%20caption%20%3D%20%22thinkr.fr%22)%20%2B%20%0A%20%20theme_few()” message=”” highlight=”” provider=”manual”/]

On voit que les topics couvrent des sujets parfois… différents. Le premier topic mixe “love” et “black” avec des termes plutôt liés au classique (allegro, sonata, piano). Le topic 3 paraît plus unifié, avec des termes autour de “version”, “remastered”, “single”, caractéristique de la définition des conditions d’enregistrement des morceaux.

Bon, c’était bien fun tout ça ! Vivement la prochaine !


Commentaires

Une réponse à “R de jeu #1 : API, dataviz, et statistiques”

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *


À lire également

Nos formations Certifiantes à R sont finançables à 100% via le CPF

Nos formations disponibles via moncompteformation.gouv.fr permettent de délivrer des Certificats reconnues par l’état, enregistrées au répertoire spécifique de France Compétences. 3 niveaux de certifications existent :

Contactez-nous pour en savoir plus.

Calendrier

23/05/2023

09/05/2023

09/05/2023