R & Spotify – Part 1: Long Distance Calling

Data Science meets Post-Rock…

Schon vor ein paar Monaten habe ich eine sehr witzige Punk-Rock-Datenanalyse entdeckt, die Salvino A. Salvaggio auf seinem R-Blog veröffentlicht hat. Der Blogpost besteht aus einer Reihe interessanter (und gut visualisierter) Statistiken über die Ramones (wie z.B. die Anzahl unterschiedlicher Akkorde im Zeitverlauf) sowie einer durchaus anspruchsvollen quantitativen Analyse der Lyrics. Seither stolpere ich immer wieder über „Analysen“, die auf Daten von Spotify beruhen (wie zum Beispiel die Versuche, die depressivsten bzw. fröhlichsten Songs von Radiohead ausschließlich auf der Grundlage von Daten zu identifizieren). Möglich ist das vor allem deshalb, weil  Spotify einen Datenbank-Zugriff mittels Web-API ermöglicht (mehr Infos dazu gibt es hier). Und natürlich existieren mittlerweile mehrere Pakete für R, die eine bequeme Anbindung ermöglichen.

Als Daten- und Musikfreak musste ich mir das natürlich genauer anschauen. Als „Usecase“ dient dabei Long Distance Calling, eine Postrock-Band aus Münster (keine Ahnung, warum ich genau diese Band genommen habe – vermutlich weil sie gerade zufällig nebenher lief).

Um auf die Datenbank von Spotify zuzugreifen, nutze ich das Paket spotifyr von Charles Thompson. Das Paket ist (noch) nicht über CRAN erhältlich sondern auf github gehostet. Die Installation erfolgt daher über devtools.

devtools::install_github('charlie86/spotifyr')
library(spotifyr)

Zusätzlich wird ein Spotify-Developer-Account benötigt, der sich in wenigen Minuten hier erstellen lässt. Für den Zugriff via spofityr werden die SPOTIFY_CLIENT_ID und die SPOTIFY_CLIENT_SECRET ID benötigt, die man nach der Anmeldung erhält.

Sys.setenv(SPOTIFY_CLIENT_ID = "[HIER DIE ID EINGEBEN]")
Sys.setenv(SPOTIFY_CLIENT_SECRET = "[HIER DIE ID EINGEBEN]")
access_token <- get_spotify_access_token(client_id = Sys.getenv('SPOTIFY_CLIENT_ID'), client_secret = Sys.getenv('SPOTIFY_CLIENT_SECRET'))

Et voilà – das war’s auch schon. Jetzt erstellen wir einen Data Frame, der die Audio-Features aller Long Distance Calling Songs enthält. Das funktioniert folgendermaßen:

ldc_df <- get_artist_audio_features('Long Distance Calling')
str(ldc_df)

Wie die (R-typisch etwas kryptische) Ausgabe unten offenbart, enthält der Data Frame allerlei Daten – von Song- und Albennamen über Coverbilder bishin zu Spotify „Audio-Features“, wie z.B. der „Tanzbarkeit“ oder der „instrumentalness“ eines Songs (jeweils von 0 bis 1), das Tempo und die Grundttonart der jeweiligen Lieder. Nähere Details zu den Daten und vor allem zu den Audio-Features finden sich hier).

Classes ‘tbl_df’, ‘tbl’ and 'data.frame':	43 obs. of  23 variables:
 $ album_uri         : chr  "5MaHKABaR7lcdub0boDbiP" "5MaHKABaR7lcdub0boDbiP" "5MaHKABaR7lcdub0boDbiP" "5MaHKABaR7lcdub0boDbiP" ...
 $ album_name        : chr  "Satellite Bay (Re-issue + Bonus)" "Satellite Bay (Re-issue + Bonus)" "Satellite Bay (Re-issue + Bonus)" "Satellite Bay (Re-issue + Bonus)" ...
 $ album_img         : chr  "https://i.scdn.co/image/ad924fe983e06025c1ba1b4986a0fbb29bd43472" "https://i.scdn.co/image/ad924fe983e06025c1ba1b4986a0fbb29bd43472" "https://i.scdn.co/image/ad924fe983e06025c1ba1b4986a0fbb29bd43472" "https://i.scdn.co/image/ad924fe983e06025c1ba1b4986a0fbb29bd43472" ...
 $ album_release_date: chr  "2006" "2006" "2006" "2006" ...
 $ album_release_year: Date, format: "2006-01-01" "2006-01-01" "2006-01-01" ...
 $ album_popularity  : int  26 26 26 26 26 26 26 26 26 26 ...
 $ track_name        : chr  "Jungfernflug" "Fire in the Mountain" "Aurora" "Horizon" ...
 $ track_uri         : chr  "4KYEZ3soadVj93J9csiBoA" "4y9QL3fvmHgdmMJtJDReSs" "7yG951ap7DBMzwmXebNe17" "2Ni5lKzmc1naqkZzkSVs6R" ...
 $ danceability      : num  0.349 0.53 0.63 0.491 0.547 0.321 0.433 0.528 0.472 0.445 ...
 $ energy            : num  0.652 0.79 0.43 0.705 0.558 0.695 0.955 0.722 0.753 0.484 ...
 $ key               : chr  "A" "A" "A" "G" ...
 $ loudness          : num  -8.22 -7.16 -8.38 -8.27 -9.04 ...
 $ mode              : chr  "minor" "minor" "minor" "major" ...
 $ speechiness       : num  0.0354 0.0353 0.0314 0.0349 0.0391 0.0401 0.059 0.0296 0.0352 0.037 ...
 $ acousticness      : num  5.64e-04 5.13e-05 1.51e-03 4.34e-05 2.26e-03 5.73e-05 1.18e-04 8.77e-04 5.73e-03 8.46e-04 ...
 $ instrumentalness  : num  0.889 0.843 0.905 0.852 0.752 0.841 0.838 0.833 0.569 0.841 ...
 $ liveness          : num  0.123 0.341 0.158 0.107 0.127 0.41 0.378 0.314 0.102 0.105 ...
 $ valence           : num  0.0679 0.249 0.0681 0.351 0.0721 0.0877 0.212 0.541 0.578 0.226 ...
 $ tempo             : num  133.3 135 129.9 87.5 120.1 ...
 $ duration_ms       : num  636053 448000 522493 353693 622760 ...
 $ time_signature    : num  4 4 4 4 4 4 4 4 4 3 ...
 $ key_mode          : chr  "A minor" "A minor" "A minor" "G major" ...
 $ track_popularity  : int  17 18 22 16 14 15 14 10 12 11 ...

Als erstes interessiert mich, welche Songs von Long Distance Calling bei den Nutzern von Spotify am beliebtesten sind. Dazu nutze ich die Variable track_popularity, die Werte zwischen 0 und 100 annehmen kann (wobei 100 die maximale Popularität signalisiert). Berechnet wird die track popularity über einen Algorithmus, der auf der Abspielhäufigkeit eines Songs beruht, dabei aber aktuelle Streams deutlich höher gewichtet als frühere. Zur Visualisierung der track popularity nutze ich ggplot2.

ggplot(ldc_df, aes(track_popularity,
                       reorder(track_name, track_popularity),
                       fill=album_name)) +
  labs(x = "Popularität", y = "Songs", fill = "Alben") +
  geom_point(size = 2, shape = 21)

LDC_1

Der mit Abstand beliebteste Songs ist – tadaaa – Black Paper Planes. Soweit nicht überraschend. Einige meiner Lieblinge (z.B. Invisible Giants und Arecibo) finden sich dagegen vergleichsweise weit hinten. Zum Teil dürfte das darauf zurückzuführen sein, dass es sich hierbei um relativ alte Songs handelt und die Streams der jüngeren Vergangenheit überproportional hoch gewichtet werden (zum Teil mag es aber auch an meinem Geschmack liegen…).

Als nächstes interessiert mich, ob sich die musikalische Entwicklung der Band auch in den Daten widerspiegelt. Dazu sollte man wissen, dass sich auf den früheren Alben der Band nahezu ausschließlich ziemlich lange Instrumentalstücke finden; die Songs auf den letzten beiden Alben sind dagegen nicht nur kürzer sondern auch etwas „popiger“ – und sehr viel häufiger auch mit Gesang. Einen Überblick über die einzelnen Alben habe ich mir unter Zuhilfenahme einiger dplyr-Funktionen verschafft, die Visualisierung erfolgt wieder mittels ggplot.

library(dplyr)
library(tidyr)
library(lubridate)

ldc_agg <- ldc_df %>%
  group_by(album_name) %>%
  summarise(year = mean(year(album_release_year)),
            tracks = n(),
            mean_duration = mean(duration_ms/60000),
            tempo = mean(tempo),
            danceability = mean(danceability),
            energy = mean(energy),
            valence = mean(valence),
            instrumentalness = mean(instrumentalness),
            album_popularity = mean(album_popularity),
            track_popularity = mean(track_popularity)) %>%
  arrange(year)

ldc_agg

# A tibble: 5 x 11
                        album_name  year tracks mean_duration    tempo danceability    energy   valence instrumentalness album_popularity track_popularity
                             <chr> <dbl>  <int>         <dbl>    <dbl>        <dbl>     <dbl>     <dbl>            <dbl>            <dbl>            <dbl>
1 Satellite Bay (Re-issue + Bonus)  2006     11      8.181938 120.8619    0.4850000 0.6610909 0.2295000        0.8220909               26         14.09091
2                  Avoid the Light  2010      6      9.150000 133.0807    0.3588333 0.7518333 0.2000000        0.7513333               42         30.16667
3            Long Distance Calling  2011      7      8.021279 143.9229    0.3458571 0.6844286 0.1052286        0.7521700               29         20.42857
4                 The Flood Inside  2013      8      6.926863 113.8842    0.4201250 0.7180000 0.2055000        0.5291500               31         20.00000
5     TRIPS (Bonus Tracks Version)  2016     11      5.462339 120.0635    0.4915455 0.7013636 0.2686545        0.4394511               39         24.27273

Die Tatsache, dass die Songs auf den letzten Alben deutlich kürzer geworden sind, wird in der Grafik unten sehr deutlich. Mit durchschnittlich 5,46 Minuten pro Song wird LDC ja langsam fast schon radiotauglich…

ggplot(ldc_agg) +
  geom_line(aes(year, mean_duration), size = 1, color = "darkgrey") +
  geom_point(aes(year, mean_duration, fill = reorder(album_name, year)), size = 4, shape = 21) +
  labs(x = "Popularität", y = "Songs", fill = "Alben") +
    theme(text = element_text(size = 14))

LDC_2

Zuletzt noch ein Blick auf einige „Audio Features“ wie „dance“, „energy“, „valence“ und „instrumentalness“:

ldc_audio <- ldc_agg %>%
  select (album_name, year, danceability, energy, valence, instrumentalness) %>%
  gather(variable, value, -c(album_name, year)) 

ggplot(ldc_audio) +
  geom_line(aes(year, value, color = variable), size = 1.25) +
  theme(text = element_text(size = 14)) +
  geom_point(aes(year, value, shape = reorder(album_name, year)), size = 2) +
  labs(x = "Veröffentlichungsjahr",
       y = "Durchschnittswert",
       color = "Audio Feature",
       shape = "Album")

LDC_3

An der Entwicklung der Variable „instrumentalness“ wird die Abkehr von der reinen Instrumentalband zur „auch-Instrumentalband“ deutlich erkennbar. Zudem deuten die Daten darauf hin, dass die letzten beiden Alben etwas „fröhlicher“ („valence“) und „tanzbarer“ geworden sind. Auch das deckt sich mit meinem Eindruck, dass LDC zunehmend „popiger“ geworden sind (bedauerlicherweise).

Mein erstes Fazit: Die Anbindung von R zur Spotify-Datenbank funktioniert bestens und die Daten sind durchaus interessant. Ich werde mich damit garantiert noch etwas intensiver auseinandersetzen – deswegen auch das „Part 1“ in der Überschrift.

Ein kleines Update im Mai 2018: Nachdem mit „Boundless“ (endlich) wieder ein reines Instrumentalalbum von Long Distance Calling erschienen ist, musste ich natürlich auch den Blogbeitrag nochmal aktualisieren. Und siehe da: Die Entwicklung zeigt sich klar in den Daten. Die „instrumentalness“ steigt deutlich an und das Album ist weniger „fröhlich“ und „tanzbar“. Ach, und länger sind die Songs auch wieder. So soll es sein :-):

LDC5LDC4

 

Werbeanzeigen