R & Spotify – Part 2: Was hörst Du denn gerade so?
Musikgeschmack - statistisch belegt
Vor über einem Jahr habe ich entdeckt, wie man dank des großartigen Pakets spotifyr von Charles Thompson mit R auf so ziemlich alle Audio-Features der Spotify-Datenbank zugreifen kann - also z.B. auf das Tempo und die Grundtonart oder auf Features wie der “Tanzbarkeit” oder der “Energie” bestimmter Songs. Wie das funktioniert habe ich hier beschrieben. Spannend ist es aber natürlich auch, mal einen Blick auf die eigenen Hörgewohnheiten zu werfen - also was, wann und wie oft gehört wurde. Und auch das geht dank spotifyr ziemlich easy…
Wer spotifyr noch nicht installiert hat muss den kleinen Umweg über devtools gehen, da das Paket nicht über CRAN erhältlich ist sondern auf GitHub gehostet wird. Daneben werden noch die Pakete tidyverse, knitr und kableExtra geladen (dazu später etwas mehr):
# devtools::install_github('charlie86/spotifyr')
library(spotifyr)
library(tidyverse)
## Loading tidyverse: ggplot2
## Loading tidyverse: tibble
## Loading tidyverse: tidyr
## Loading tidyverse: readr
## Loading tidyverse: purrr
## Loading tidyverse: dplyr
## Conflicts with tidy packages ----------------------------------------------
## filter(): dplyr, stats
## lag(): dplyr, stats
library(knitr)
library(kableExtra)
Jetzt werden noch die Spotify-ID-Daten (SPOTIFY_CLIENT_ID und SPOTIFY_CLIENT_SECRET ID) benötigt, die man nach der Anmeldung eines Developer-Accounts erhält. (Es kann durchaus sein, dass sich an dieser Stelle einmal der Browser öffnet und euch dazu auffordert, euch bei Spotify einzuloggen).
Sys.setenv(SPOTIFY_CLIENT_ID = "HIER DIE ID EINGEBEN")
Sys.setenv(SPOTIFY_CLIENT_SECRET = "HIER DIE SECRET ID EINGEBEN")
access_token <- get_spotify_access_token(client_id = Sys.getenv('SPOTIFY_CLIENT_ID'), client_secret = Sys.getenv('SPOTIFY_CLIENT_SECRET'))
“Wie hieß der Song von gestern nochmal?”
Um sich nun beispielsweise die Songs anzeigen zu lassen, die man zuletzt via Spotify gehört hat, ist nicht viel mehr nötig, als die Funktion get_my_recently_played():
get_my_recently_played()
## # A tibble: 50 x 18
## track_name artist_name album_name played_at_utc context_type
## <chr> <chr> <chr> <dttm> <chr>
## 1 Devonian:… The Ocean Phanerozo… 2019-03-05 21:48:05 playlist_v2
## 2 Arrete Leech For Bette… 2019-03-05 21:36:59 playlist_v2
## 3 Linger The Inters… The Grand… 2019-03-05 21:29:37 album
## 4 New Maxim The Inters… The Grand… 2019-03-05 21:28:02 album
## 5 The Grand… The Inters… The Grand… 2019-03-05 21:24:28 album
## 6 Smoke Scr… The Inters… The Grand… 2019-03-05 21:20:51 album
## 7 Antitype The Inters… The Grand… 2019-03-05 21:16:49 album
## 8 Man on th… The Inters… The Grand… 2019-03-05 21:10:55 album
## 9 Mind over… The Inters… The Grand… 2019-03-05 21:06:38 album
## 10 Don't Thi… The Inters… The Grand… 2019-03-05 21:01:51 album
## # … with 40 more rows, and 13 more variables: context_uri <chr>,
## # context_spotify_url <chr>, album_type <chr>, track_number <int>,
## # track_popularity <int>, explicit <lgl>, album_release_date <chr>,
## # album_img <chr>, track_uri <chr>, artist_uri <chr>, album_uri <chr>,
## # track_preview_url <chr>, track_spotify_url <chr>
Und schon erhält man eine Liste der letzten Songs, die über Spotify abgespielt wurden (wie in der Ausgabe ersichtlich, werden allerdings einige Zeilen und Spalten abgeschnitten). Die Funktion lässt sich durch ein paar Zusatzargumente noch anpassen (mehr Details zu den jeweiligen Parametern finden sich bei Spotify). In diesem Fall will ich neben der Namen der Songs nur die Namen der dazugehörigen Künstler und das Abspiel-Datum nebst Uhrzeit sehen. Mit der Spezifikation limit = 10 grenze ich die Liste zudem auf die letzten zehn Songs ein:
get_my_recently_played(limit = 10) %>%
select(track_name, artist_name, played_at_utc)
## # A tibble: 10 x 3
## track_name artist_name played_at_utc
## <chr> <chr> <dttm>
## 1 Devonian: Nascent The Ocean 2019-03-05 21:48:05
## 2 Arrete Leech 2019-03-05 21:36:59
## 3 Linger The Intersphere 2019-03-05 21:29:37
## 4 New Maxim The Intersphere 2019-03-05 21:28:02
## 5 The Grand Delusion The Intersphere 2019-03-05 21:24:28
## 6 Smoke Screen The Intersphere 2019-03-05 21:20:51
## 7 Antitype The Intersphere 2019-03-05 21:16:49
## 8 Man on the Moon The Intersphere 2019-03-05 21:10:55
## 9 Mind over Matter The Intersphere 2019-03-05 21:06:38
## 10 Don't Think Twice The Intersphere 2019-03-05 21:01:51
Um mehr Songs zu sehen, lässt sich die Anzahl über die Spezifikationen etwas vergrößern, bei 50 Songs ist allerdings Schluss. Um die resultierende Tabelle etwas übersichtlicher zu gestalten (die Tabellen oben sehen - wie immer bei den Standardausgaben von R - eher mäßig aus), nutze ich die kable()-Funktion des knitr-Pakets mit der sich u.a. HTML-Tabellen erstellen lassen. Zusätzlich verwende ich Funktionen aus dem Paket kableExtra, mit deren Hilfe sich die Tabellen zusätzlich anpassen lassen. In diesem Fall möchte ich eine scrollbare HTML-Tabelle mit einer fest definierten Größe. Eine gute Einführung in die Erstellung von HTML-Tabellen mit kable und kableExtra findet sich übrigens hier.
get_my_recently_played(limit = 50) %>%
select(track_name, artist_name, played_at_utc) %>%
kable() %>%
kable_styling() %>%
scroll_box(width = "100%", height = "400px")
track_name | artist_name | played_at_utc |
---|---|---|
Devonian: Nascent | The Ocean | 2019-03-05 21:48:05 |
Arrete | Leech | 2019-03-05 21:36:59 |
Linger | The Intersphere | 2019-03-05 21:29:37 |
New Maxim | The Intersphere | 2019-03-05 21:28:02 |
The Grand Delusion | The Intersphere | 2019-03-05 21:24:28 |
Smoke Screen | The Intersphere | 2019-03-05 21:20:51 |
Antitype | The Intersphere | 2019-03-05 21:16:49 |
Man on the Moon | The Intersphere | 2019-03-05 21:10:55 |
Mind over Matter | The Intersphere | 2019-03-05 21:06:38 |
Don’t Think Twice | The Intersphere | 2019-03-05 21:01:51 |
Smile When the Raindrops Fall | Imperial Dance Orchestra | 2019-03-05 20:57:50 |
Moon Ray | Ella Fitzgerald and Her Famous Orchestra | 2019-03-05 14:42:09 |
Crosby, Columbo and Vallee | Dick Robertson | 2019-03-05 14:39:09 |
Copenhagen | Earl Hines | 2019-03-05 14:36:06 |
As Long as We Are in Love | Fred Rich & His Orchestra | 2019-03-05 14:33:35 |
Jumping At The Woodside | Count Basie | 2019-03-05 14:30:14 |
Jig Walk | Sam Lanin and The Ipana Troubadours | 2019-03-05 14:27:03 |
What a Difference a Day Made | Freddy Martin & His Orchestra | 2019-03-05 14:24:23 |
You Were Meant For Me | The Capitolians | 2019-03-05 14:21:18 |
Happy Days Are Here Again | Casa Loma Orchestra, Conducted by Glen Gray | 2019-03-05 14:18:35 |
Let’s Misbehave | Irving Aaronson and His Commanders | 2019-03-05 14:15:15 |
Katzen Brauchen Furchtbar Viel Musik | Cast - Aristocats | 2019-03-05 14:12:20 |
Execution Thirst | ASG | 2019-03-05 12:52:01 |
Survive Sunrise | ASG | 2019-03-05 11:55:12 |
The Heaven Moon | ASG | 2019-03-04 23:57:31 |
Hawks on the Run | ASG | 2019-03-04 23:57:00 |
Florida Sleep On | ASG | 2019-03-04 23:23:01 |
Lamb Song | ASG | 2019-03-04 23:19:35 |
Weekend Money | ASG | 2019-03-04 23:14:40 |
Heavy Scars | ASG | 2019-03-04 23:10:33 |
God Knows We | ASG | 2019-03-04 23:06:21 |
Kubrick Colors | ASG | 2019-03-04 23:02:19 |
The Heaven Moon | ASG | 2019-03-04 22:59:59 |
Hawks on the Run | ASG | 2019-03-04 22:56:10 |
Lightning Song | ASG | 2019-03-04 22:51:45 |
Up from My Dreams | ASG | 2019-03-04 22:47:02 |
Execution Thirst | ASG | 2019-03-04 22:42:54 |
Survive Sunrise | ASG | 2019-03-04 22:39:58 |
Survive Sunrise | ASG | 2019-03-04 22:36:17 |
Palo Alto | Kettcar | 2019-03-04 22:32:01 |
La Forza del Destino: Act II: Scene 1: Canzone - Al suon del tamburo | Giuseppe Verdi | 2019-03-04 21:38:40 |
La Forza del Destino: Act II: Scene 1: Scena - La cena è pronta | Giuseppe Verdi | 2019-03-04 21:26:55 |
La Forza del Destino: Act II: Scene 1: Coro, Ballabile - Holà, holà, holà! | Giuseppe Verdi | 2019-03-04 21:24:43 |
La Forza del Destino: Act I: Scena finale - È tardi | Giuseppe Verdi | 2019-03-04 21:23:16 |
La Forza del Destino: Act I: Dimani si partirà | Giuseppe Verdi | 2019-03-04 21:21:01 |
La Forza del Destino: Act I: Ah, per sempre, o mio bell’angiol | Giuseppe Verdi | 2019-03-04 21:16:48 |
La Forza del Destino: Act I: Me, pellegrina ed orfana | Giuseppe Verdi | 2019-03-04 21:13:38 |
La Forza del Destino: Act I: Recitativo e romanza - Temea restasse | Giuseppe Verdi | 2019-03-04 21:09:58 |
La Forza del Destino: Act I: Introduzione, Scena - Buona notte, mia figlia | Giuseppe Verdi | 2019-03-04 21:08:14 |
La Forza del Destino: Act I: Overture | Giuseppe Verdi | 2019-03-04 21:05:41 |
“Was ist eigentlich Dein Lieblings-Song?”
Auch diese Frage lässt sich mithilfe von spotifyr beantworten - allerdings nur dann, wenn die Frage vorher nochmals präzisiert wurde: “Meinst Du meinen Lieblings-Song der letzten Wochen, Monate oder Jahre?” Mit der Funktion get_my_top_tracks() lassen sich nämlich die meistgespielten Spotify-Songs innerhalb einer gewissen Zeitspanne (“short-term”, “medium-term” oder “long-term”) ausgeben. Die Angaben, die Spotify selbst zu diesen Zeitspannen macht, sind allerdings etwas vage (siehe hier). So bezieht sich “short-term” laut Spotify “in etwa” auf die letzten vier Wochen, “medium-term” auf die letzten sechs Monate und “long-term” auf “several years”, wobei ich bei der Betrachtung meiner “long-term”-Liste das Gefühl habe, dass die letzten ein bis zwei Jahre ziemlich überproportional gewichtet werden. Aber vielleicht täuscht mein Gefühl da auch.
Nachfolgend also meine “long-term”-Lieblings-Songs, wobei ich die Auswahl auf 25 Songs beschränkt habe und neben dem jeweiligen Titel auch noch die Namen der Künstler und der jeweiligen Alben mit in die Tabelle übernommen habe.
get_my_top_tracks(time_range = 'long_term', limit = 25) %>%
select(track_name, artist_name, album_name) %>%
kable() %>%
kable_styling() %>%
scroll_box(width = "100%", height = "400px")
track_name | artist_name | album_name |
---|---|---|
Florida Sleep On | ASG | Survive Sunrise |
Helios Erebus | God Is An Astronaut | Helios / Erebus |
No Man’s Land | The Pineapple Thief | Your Wilderness |
Katzen Brauchen Furchtbar Viel Musik | Cast - Aristocats | Disney Film-Hits (Magische Musik Momente) |
Chlorine & Wine | Baroness | Purple |
If I Have To Wake Up (Would You Stop The Rain?) | Baroness | Purple |
Arrete | Leech | For Better Or For Worse |
Solstice | If These Trees Could Talk | The Bones of a Dying World |
Gravity | Architects | All Our Gods Have Abandoned Us |
What You Have Become | Spidergawd | Spidergawd IV |
Gipfelkreuz | Heisskalt | Vom Stehen und Fallen |
Dirty Seconds | Leech | For Better Or For Worse |
Black Honey | Thrice | To Be Everywhere Is To Be Nowhere |
Threatening War | The Pineapple Thief | Dissolution |
Waiting Room | Fugazi | 13 Songs |
In Exile | The Pineapple Thief | Your Wilderness |
Paroli | Fjørt | Kontakt |
Try as I Might | The Pineapple Thief | Dissolution |
Empire of Silence | While She Sleeps | You Are We |
Tear You Up | The Pineapple Thief | Your Wilderness |
Heavy Scars | ASG | Survive Sunrise |
Just Tonight | Jimmy Eat World | Futures (International Version) |
Poison | Alice Cooper | The Best Of Alice Cooper |
Old Heart Falls | Katatonia | The Fall of Hearts |
The Time of Perfect Virtue | Junius | Days of the Fallen Sun |
Und - tadaaa - mein Lieblings-Songs müsste demnach “Florida Sleep On” von ASG sein. Nun ja, den Song habe ich zwar im letzten Sommer tatsächlich hoch und runter gehört, zu meinen absoluten “Lieblings-Songs” würde ich ihn allerdings nicht zählen. Insgesamt scheint die Liste, wie bereits erwähnt, ziemlich von den letzten beiden Jahren dominiert zu sein. Das zeigt sich zum einen daran, dass sich der Top-Song der Liste auf einem Album befindet, das erst 2018 veröffentlicht wurde und zum anderen an dem ziemlich guten Ranking von “Katzen brauchen furchtbar viel Musik” - dem Lieblingslied meiner zweieinhalb-jährigen Tochter. Egal - es sind durchaus ein paar ganz coole Songs auf der Liste.
Der Vollständigkeit halber hier auch noch die “medium-term” und “short-term” Liste. Letztere ist offenkundig sehr vom neuen Album von The Intersphere geprägt…:
get_my_top_tracks(time_range = 'medium_term', limit = 25) %>%
select(track_name, artist_name, album_name) %>%
kable() %>%
kable_styling() %>%
scroll_box(width = "100%", height = "400px")
track_name | artist_name | album_name |
---|---|---|
Arrete | Leech | For Better Or For Worse |
Dirty Seconds | Leech | For Better Or For Worse |
Antitype | The Intersphere | The Grand Delusion |
Try as I Might | The Pineapple Thief | Dissolution |
Death Is Not Defeat | Architects | Holy Hell |
Threatening War | The Pineapple Thief | Dissolution |
Permian: The Great Dying | The Ocean | Phanerozoic I: Palaeozoic |
Lethean | Katatonia | Dead End Kings |
Trading Shadows | Night Verses | From the Gallery of Sleep |
Hereafter | Architects | Holy Hell |
Cause We Didn’t Find Our Way | Tuber | Desert Overcrowded |
White Mist | The Pineapple Thief | Dissolution |
Die Straßen unseres Viertels | Kettcar | Ich vs. Wir |
Mortal After All | Architects | Holy Hell |
Devonian: Nascent | The Ocean | Phanerozoic I: Palaeozoic |
Alien Shivers | VOLA | Applause Of A Distant Crowd |
Tonitro | Brontide | Artery |
Age Of Man | Greta Van Fleet | Anthem Of The Peaceful Army |
Whaler | VOLA | Applause Of A Distant Crowd |
Man on the Moon | The Intersphere | The Grand Delusion |
Make a Man | Estrons | You Say I’m Too Much, I Say You’re Not Enough |
A Million Tears | Trees of Eternity | Hour of the Nightingale |
Katzen Brauchen Furchtbar Viel Musik | Cast - Aristocats | Disney Film-Hits (Magische Musik Momente) |
Herbstmonster | Leech | For Better Or For Worse |
Solstice | If These Trees Could Talk | The Bones of a Dying World |
get_my_top_tracks(time_range = 'short_term', limit = 25) %>%
select(track_name, artist_name, album_name) %>%
kable() %>%
kable_styling() %>%
scroll_box(width = "100%", height = "400px")
track_name | artist_name | album_name |
---|---|---|
Antitype | The Intersphere | The Grand Delusion |
Shine | Sylvan | Home |
Smoke Screen | The Intersphere | The Grand Delusion |
New Maxim | The Intersphere | The Grand Delusion |
The Grand Delusion | The Intersphere | The Grand Delusion |
Madman | Ashbury | Endless Skies |
Man on the Moon | The Intersphere | The Grand Delusion |
Linger | The Intersphere | The Grand Delusion |
Alien Shivers | VOLA | Applause Of A Distant Crowd |
You Feel Better When I Feel Bad | The Intersphere | The Grand Delusion |
Radio | Rishloo | Living as Ghosts With Buildings as Teeth |
The Sound of Her World | Sylvan | Home |
Dark Charade | Rishloo | Living as Ghosts With Buildings as Teeth |
God Shuffled His Feet | Crash Test Dummies | God Shuffled His Feet |
Mind over Matter | The Intersphere | The Grand Delusion |
Secret Place | The Intersphere | The Grand Delusion |
Overflow | The Intersphere | The Grand Delusion |
Don’t Think Twice | The Intersphere | The Grand Delusion |
Hawks on the Run | ASG | Survive Sunrise |
Survive Sunrise | ASG | Survive Sunrise |
Palo Alto | Kettcar | Palo Alto |
Hard Fight | Ashbury | Endless Skies |
Shipwreck | The Intersphere | The Grand Delusion |
Winslow | Rishloo | Living as Ghosts With Buildings as Teeth |
Point of No Return | Sylvan | Home |
“…und Deine Lieblings-Band?”
Womit wir bei der Lieblings-Band wären - auch die lässt sich eruieren, wobei auch hier dieselben drei Zeitspannen angegeben werden können. Die Logik ist im Grunde dieselbe, in dem Beispiel meiner “long-Term”-Lieblingsbands unten habe ich zusätzlich zu den Bandnamen noch die Genrebezeichnungen gepackt, die Spotify den Bands so anheftet. Und die sind schon sehr witzig. Dass Kettcar beispielsweise “antideutsch” sein soll ist eine zumindest interessante Zuschreibung und Genres wie “neo-progressive”, “atmospheric post-metal” oder “orgcore”(?) sind schon zum Schmunzeln… Naja. Mit dem Ergebnis (The Pineapple Thief als mein “Top-Artist”) kann ich zwar irgendwie leben, auch hier zeigt sich allerdings, dass Daten aus den letzten ein bis zwei Jahren vermutlich überproportional gewichtet werden. Sei’s drum - ein interessanter Einblick in meine Spotify-Daten eröffnet sich dadurch allemal.
get_my_top_artists(time_range = 'long_term', limit = 20) %>%
select(artist_name, artist_genres) %>%
rowwise %>%
mutate(artist_genres = paste(artist_genres, collapse = ', ')) %>%
ungroup %>%
kable() %>%
kable_styling() %>%
scroll_box(width = "100%", height = "400px")
artist_name | artist_genres |
---|---|
The Pineapple Thief | art rock, neo-progressive, progressive metal, progressive rock, symphonic rock |
Architects | mathcore, melodic metalcore, metalcore, screamo |
Kettcar | antideutsche, german indie, german pop, german punk, german rock, liedermacher |
Katatonia | doom metal, gothic metal, melodic death metal, metal, pagan black metal, progressive metal, swedish metal |
The Dear Hunter | dreamo, progressive post-hardcore |
Opeth | alternative metal, death metal, groove metal, melodic death metal, metal, progressive metal, rock, swedish metal |
Ghost | metal |
God Is An Astronaut | instrumental post-rock, post-rock |
Fjørt | deep german punk |
Thrice | emo, modern rock, pop punk, post-hardcore, screamo |
ASG | psychedelic doom, retro metal, sludge metal, stoner metal, stoner rock |
Long Distance Calling | german post-rock, instrumental post-rock, post-metal, post-rock |
Propagandhi | canadian indie, canadian punk, folk punk, melodic hardcore, orgcore, punk, ska punk, skate punk |
Hot Water Music | emo, emo punk, melodic hardcore, orgcore, pop punk, post-hardcore, punk, skate punk |
Leech | atmospheric post-rock, german post-rock, instrumental post-rock, post-rock |
The Ocean | alternative metal, atmospheric post-metal, avantgarde metal, djent, jazz metal, mathcore, post-doom metal, post-metal, post-rock, progressive metal, sludge metal |
O’Brother | dreamo, progressive post-hardcore |
A Perfect Circle | alternative metal, alternative rock, modern rock, nu metal, post-grunge, rap rock, rock |
TesseracT | djent, jazz metal, progressive metal |
Irie Révoltés | antideutsche, french reggae, german reggae, german rock |