Der Audio-Streaming Dienst Spotify ist mit 381 Millionen aktiven Nutzern in 2021 der weltweit größte Anbieter seiner Art. Immer mehr NutzerInnen verwenden Spotify zum Anhören ihrer Lieblingssongs und Lieblingspodcasts. Einer der Gründe für Spotifys Erfolg neben ihrem umfangreichen Angebot, ist ihr Umgang mit gesammelten Daten. Spotify nutzt verschiedene Instrumente, um aus den Daten einen Mehrwert zu erzeugen. Dazu gehören Künstlichen Intelligenzen, die das Verhalten der User erlernen und auch das Zusammenfassen klassicher Datensätze, wie die Spotify Charts.
Diese Datenanalyse beschäftigt sich mit den internen Spotify Top 200 Wochencharts von 2020 und 2021. Die Charts beinhalten keine Podcasts und beziehen sich auf die weltweiten Streams. Ein Stream wird gezählt, wenn der Titel 30 Sekunden oder länger angehört wird. Der Datensatz Spotify Top 200 Charts (2020-2021) ist auf der Data-Science-Platform Kaggle öffentlich zugänglich.
In dem Zeitraum vom 27.12.2019 bis zum 30.07.2021 waren 1556 verschiedene Songs in den Top 200 Charts, dementsprechend beinhaltet der Datensatz auch 1556 Zeilen. Weiterhin gibt es 23 Spalten, die umfangreiche Informationen zu jedem Song bereitstellen. Es folgt eine Erläuterung der unterschiedlichen Spalten.
Jeder Song hat eine persönliche Nummer. Der Datensatz ist nach den Indizes sortiert.
Diese Spalte behinhaltet die höchste Chartposition der Songs innerhalb des Zeitraums. Im Folgenden wird diese Spalte als Highest CP bezeichnet.
Hier wird angezeigt wie viele Wochen sich der Song in den Charts gehalten hat. Im Folgenden wird diese Spalte als Number of TC bezeichnet.
Passend zur höchsten Chartposition wird hier die entsprechende Woche angegeben. Im Folgenden wird diese Spalte als Week of HC bezeichnet.
Diese Spalte zeigt den Namen des Songs an.
Die Anzahl der Streams bestimmt die Chartplatzierungen. Es ist zu beachten, dass die Streamanzahl sich auf die absoluten Streams (auch vor dem Zeitraum) bezieht.
Hier werden der Artist oder die Artists angezeigt. Später werden Einträge mit mehreren Artists aufgesplitet, um den Datensatz zugänglicher zu machen.
Die Spalte beinhaltet die Followeranzahl des Artists. Bei mehereren Artists bezieht sich dieser Wert auf den Erstgenannten.
Jeder Song besitzt eine ID aus Buchstaben und Zahlen. Da es bereits die Spalte Index gibt, ist diese Spalte für diese Datenanayse unwichtig und kann im weiteren herusgenommen werden.
Die Spalte beinhaltet die Genre, die zum jeweiligen Song passen. Nicht jedes Feld dieser Spalte beinhaltet ein Genre.
Das Release Date gibt den Tag an, an dem der Song offiziell veröffentlicht wurde.
Die Felder dieser Spalte sind jeweils mit einer Zeichenkette gefüllt, die alle Wochen mit Chartplatzierung darstellt.
Die Spalte besitzt Werte zwischen 0 und 100, wobei 100 für maximale Beliebtheit
Danceability beschreibt, wie geeignet ein Track zum Tanzen ist, basierend auf einer Kombination von musikalischen Elementen wie Tempo, Rhythmusstabilität, Taktstärke und allgemeine Regelmäßigkeit. Ein Wert von 0,0 ist am wenigsten tanzbar und 1,0 ist am tanzbarsten.
Energy ist ein Maß von 0,0 bis 1,0 und repräsentiert ein wahrnehmungsbezogenes Maß für Intensität und Aktivität. Normalerweise fühlen sich energiegeladene Tracks schnell, laut und geräuschvoll an.
Die Gesamtlautstärke eines Tracks in Dezibel (dB). Lautheitswerte werden über den gesamten Track gemittelt. Der typische Wertebereich liegt zwischen -60 und 0 db.
Speechiness erkennt das Vorhandensein von gesprochenen Wörtern in einem Track. Je mehr Gesprochenes auf dem Lied vorhanden ist, desto näher liegt der Attributwert bei 1,0.
Ein Maß von 0,0 bis 1,0 dafür, ob der Track akustisch ist.
Erkennt die Anwesenheit eines Publikums in der Aufnahme. Höhere Liveness stellt eine erhöhte Wahrscheinlichkeit dar, dass der Track live gespielt wurde.
Das geschätzte Gesamttempo eines Tracks in Beats per Minute (BPM). In der musikalischen Terminologie ist Tempo die Geschwindigkeit oder das Tempo eines bestimmten Stücks und leitet sich direkt von der durchschnittlichen Beatdauer ab.
Die Tracklänge in ms. Später wird der Wert aus Lesbarkeitsgründen in min umgewandelt.
Ein Maß von 0,0 bis 1,0, das die musikalische Positivität eines Tracks beschreibt. Tracks mit hoher Valenz klingen positiver (z. B. fröhlich, freundlich, euphorisch), während Tracks mit niedriger Valenz negativer klingen (z. B. traurig, deprimiert, wütend).
Der Hauptakkord des Tracks.
Die Songs im Rohdatensatz besitzen die wichtigsten Informationen, die für eine umfangreiche Analyse notwendig sind. Lediglich könnte noch beschrieben werden, ob das jeweilige Lied eine Single oder Teil eines Albums ist und wie das Album heißt.
Die Spalten Highest CP, Number of TC und Week of HC beschreiben das Auftreten der Songs recht ordentlich und spiegeln die Beliebheit der Lieder in dem Zeitraum gut dar.
Weiterhin gibt es für jedes Lied nicht eindeutig messbare Werte und Informationen. Dazu gehören zum Beispiel die Danceability, Energy und Speechiness. Mit diesen Werten lassen sich interessante Zusammenhänge zu der Beliebtheit darstellen, allerdings sind diese auch mit Vorsicht zu bewerten, da es von außen nicht einsichtig ist, wie sich diese Werte zusammensetzen.
Zur weiteren Bearbeitung werden die Daten angepasst und Fehler bereinigt.
Zuerst wird das Package tidyverse angehangen und mit Hilfe von tidyr die Rohdaten eingelesen.
library(tidyverse)
library(kableExtra)
spotify <- read_csv("C:/Users/Laurenz/Desktop/Datenanalyse/Projekt/Spotify/data/archive (3).zip")
Anschließend werden die Spaltennamen angepasst.
spotify <- spotify %>%
rename(Highest_CP =`Highest Charting Position`,
Number_of_TC = `Number of Times Charted`,
Week_of_HC = `Week of Highest Charting`,
Song_Name = `Song Name`,
Artist_Followers = `Artist Followers`,
Song_ID = `Song ID`,
Release_Date = `Release Date`,
Weeks_Charted = `Weeks Charted`,
Duration_in_ms = `Duration (ms)`)
In den Rohdaten ist die Songlänge in ms angegeben. Eine Angabe in min ist zum Verständis sinnvoller.
spotify <- spotify %>%
mutate(Duration_in_ms = Duration_in_ms/60000) %>%
rename(Duration_in_min = Duration_in_ms)
Beim Arbeiten mit den Daten fällt auf, dass es Fehler in der Spalte Number of Times Charted gibt. Der betrachtete Zeitraum erstreckt sich über 83 Wochen, allerdings gibt es zwei Einträge mit Werten größer als 83 Wochen.
| Index | Song_Name | Number_of_TC |
|---|---|---|
| 93 | Circles | 84 |
| 369 | Falling | 142 |
Um die Informationen aus dieser Spalte verwenden zu können muss erst überprüft werden, woher der Fehler stammt und ob noch mehrere Fehler vorhanden sind. Möglicherweise könnten sich Fehler aus der Spalte Weeks Charted fortgepflanzt haben. Tatsächlich sind in der Zeichenkette für den Song “Falling” Wochen doppelt angegeben. Hier ein Ausschnitt der Zeichenkette.
example_Weeks_Charted <- "2020-01-24--2020-01-31\n2020-01-24--2020-01-31"
Die Werte für Number of Times Charted lassen sich zum Beispiel aus der Anzahl der Doppelstriche “- -” berechnen. Ein Doppelstrich spiegelt eine Woche dar. Demnach muss die Summe aller Doppelstriche des Songs “Falling” (Index 369) den fehlerhaften Wert 142 ergeben.
length(unlist(gregexpr("--", spotify$Weeks_Charted[369])))
[1] 142
Tatsächlich. Gilt diese Annahme für alle Einträge? Dafür erstellen wir eine neue Spalte mit dem Namen Number of Doublelines, füllen diese mit der Anzahl an Doppelstrichen und vergleichen diese mit Number of Times Charted.
spotify <- spotify %>%
mutate(Number_of_Doublelines = NA, .after = Number_of_TC)
i <- 1
while(spotify$Index[i] < 1556){
spotify$Number_of_Doublelines[i] = length(unlist(gregexpr("--", spotify$Weeks_Charted[i])))
i = i + 1
}
spotify %>%
filter(Number_of_TC != Number_of_Doublelines) %>% view()
| Number_of_TC | Number_of_Doublelines |
|---|---|
Die Tabelle ist komplett leer. Nun können die richtigen Werte für Number of Times Charted bestimmt werden. Dafür werden die doppelten Wochen aus Weeks Charted herausgelöscht. Mit Hilfe von Regulären Ausdrücken kann dies erreicht werden. Ein Pattern wird erstellt, das einen doppelten Eintrag darstellt. Den Rohdaten von Weeks Charted werden ein Leerzeichen angehangen, damit alle potentiellen Fehler gefunden werden können. Anschließend werden mit str_replace_all alle doppelten Einträge entfernt und die neuen Zeichenkettten in Weeks Charted New gespeichert.
pattern <- "(202(0|1)-\\d{2}-\\d{2}--202(0|1)-\\d{2}-\\d{2}\n)\\1"
spotify <- spotify %>%
mutate(Weeks_Charted = paste(Weeks_Charted, " ", sep = "")) %>%
mutate(Weeks_Charted_New = str_replace_all(Weeks_Charted, pattern, "\\1"), .after = Weeks_Charted)
Number of Doublelines wird mit den verbesserten Werten aus Weeks Charted New überschrieben.
i = 1
while(spotify$Index[i] < 1556){
spotify$Number_of_Doublelines[i] = length(unlist(gregexpr("--", spotify$Weeks_Charted_New[i])))
i = i + 1
}
Vergleicht wir nun die alten und neuen Einträge. Wie viele Einträge sind fehlerhaft?
spotify %>%
select(Index, Song_Name, Number_of_TC, Number_of_Doublelines) %>%
filter(Number_of_TC != Number_of_Doublelines) %>% view()
| Index | Song_Name | Number_of_TC | Number_of_Doublelines |
|---|---|---|---|
| 93 | Circles | 84 | 83 |
| 120 | Perfect | 83 | 82 |
| 369 | Falling | 142 | 74 |
| 647 | Santa Baby | 5 | 4 |
| 649 | Christmas (Baby Please Come Home) | 6 | 5 |
| 905 | Jangueo | 29 | 27 |
Es sind 6 Einträge fehlerhaft. Abschließend werdem Number of Times Charted und Weeks Charted überschrieben sowie Number of Doublelines und Weeks und Charted New entfernt.
spotify <- spotify %>%
mutate(Number_of_TC = Number_of_Doublelines,
Weeks_Charted = Weeks_Charted_New) %>%
select(-c(Number_of_Doublelines, Weeks_Charted_New))
Wie zuvor beschrieben, beinhalten einige Zellen in Artist mehrere Artists. Ziel ist es jeder Zeile nur einen Artist zuzuordnen. Zeilen mit mehreren Artists werden aufgesplitet und eine neue Spalte gibt dann an, ob es sich bei dem Artist um einen Featuregast handelt. Die While-Schleife schaut ob ein Komma in Artist vorkommt (Anzeichen für Featuregäste) und erstellt für jeden Featuregast eine neue Zeile. Ein Problem dabei ist, dass auch Artists ein Komma im Namen haben können. Der einzige große Artist, der mir eingefallen ist, ist “Tyler, The Creator”. Für ihn wird ein Vektor angelegt, welcher die if-Bedingung für seine Einträge unterdrückt. Die Funktion grepl() erkennt, ob ein Komma vorhanden ist und gregexpr() erkennt an welcher Stelle sich das erste Komma befindet. Mit substr() lassen sich Strings in zwei Teile aufspliten.
spotify <- spotify %>%
mutate(Feature = NA, .after = Artist)
tyler_the_creator <- spotify %>%
filter(str_detect(Artist, "Tyler, The Creator"))
tyler_the_creator <- tyler_the_creator$Index
i = 1
while((spotify$Index[i] < 1556) & !(spotify$Index[i] %in% tyler_the_creator)){
if(grepl(",", spotify$Artist[i])){
pos_first_comma <- unlist(gregexpr(",", spotify$Artist[i]))
pos_first_comma <- pos_first_comma[1]
featured_artist <- substr(spotify$Artist[i], pos_first_comma + 2, nchar(spotify$Artist[i]))
spotify$Artist[i] <- substr(spotify$Artist[i], 1, pos_first_comma - 1)
spotify <- spotify %>% add_row(Index = spotify$Index[i],
Highest_CP = spotify$Highest_CP[i],
Number_of_TC = spotify$Number_of_TC[i],
Week_of_HC = spotify$Week_of_HC[i],
Song_Name = spotify$Song_Name[i],
Streams = spotify$Streams[i],
Artist = featured_artist,
Song_ID = spotify$Song_ID[i],
Genre = spotify$Genre[i],
Release_Date = spotify$Release_Date[i],
Weeks_Charted = spotify$Weeks_Charted[i],
Popularity = spotify$Popularity[i],
Danceability = spotify$Danceability[i],
Energy = spotify$Energy[i],
Loudness = spotify$Loudness[i],
Speechiness = spotify$Speechiness[i],
Acousticness = spotify$Acousticness[i],
Liveness = spotify$Liveness[i],
Tempo = spotify$Tempo[i],
Duration_in_min = spotify$Duration_in_min[i],
Valence = spotify$Valence[i],
Chord = spotify$Chord[i],
.after = i)
spotify$Feature[i + 1] = TRUE
}
i = i + 1
}
Aus 1556 Zeilen wurden nun 2064. Demnach gibt es 508 Zeilen mit Featuregästen. Als Letztes wird die nicht benötigte Spalte Song ID gelöscht
spotify <- spotify %>%
select(-Song_ID)
Die Spalte Release Date gibt das Erscheinungsdatum im Format “yyyy-mm-dd” an. Verändern wir dieses Format in “yyyy” und plotten die Anzahl der Songs über den Zeitraum des ersten Songs bis 2021.
# Die Bibliothek ggforce ist eine Erweiterung für ggplot2. Diese ermöglicht ein heranzoomen von Plots
library(ggforce)
# Umwandlung der Daten in einen Dataframe mit den Jahren von 1942 bis 2021 mit der jeweiligen Anzahl der releasten Tracks
abb1 <- spotify %>%
filter(is.na(Feature)) %>%
filter(!is.na(Release_Date)) %>%
mutate(Release_Date = as.integer(substr(Release_Date, 1, 4))) %>%
select(Release_Date) %>%
group_by(Release_Date) %>%
summarise(Anzahl = n()) %>%
add_row(Release_Date = (c(1942:2021)), Anzahl = 0) %>%
group_by(Release_Date) %>%
summarise(Anzahl = sum(Anzahl))
# In dem Vektor labels_Release wird jedes vierte Jahr gespeichert. Zwischen den Jahren werden leere Strings abgespeichert
labels_Release <- c(1942:2021)
labels_Release[seq(2, length(labels_Release), 2)] <- ""
labels_Release[seq(3, length(labels_Release), 4)] <- ""
#facet_zoom ist eine Funktion von ggforce, die einen Ausschnitt eines Plots neben den originalen Plot plottet
ggplot(abb1) +
geom_col(aes(x = factor(Release_Date), y = Anzahl), fill = "firebrick2", color = "white") +
scale_x_discrete(labels = labels_Release) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, colour = "black"),
axis.text.y = element_text(vjust = 0.5, hjust=1, colour = "black"),
panel.grid.major.y = element_line(colour = "grey",linetype = 1),
panel.grid.major.x = element_blank(),
panel.background = element_blank()) +
labs(title = "Es sind nicht nur neue Songs in den Charts",
subtitle = "Verteilung der Releases von 1942 bis 2021",
x = "Erscheinungsjahr") +
facet_zoom(ylim = c(0, 20), zoom.size = 1)
Auf der rechten Seite sieht man den kompletten Plot und auf der linken einen Auschnitt mit bis zu 20 Songs. Wie zu erwarten war, stammen ein Großteil der Lieder aus den Jahren 2019, 2020 und 2021. Doch auch ältere Lieder sind in den Charts vertreten. Das älteste ist “White Christmas” von 1942. Generell sind die älteren Lieder entweder Weihnachtslieder oder Lieder, die durch soziale Netzwerke oder durch Kinofilme einen Hype erfahren haben. Der Song “Dreams” von Fleetwood Mac von 1977 hatte dank eines viralen Videos ein Revival gefeiert und konnte sich 44 Wochen in den Charts halten.
Den Erfolg eines Artists lässt sich unterschiedlich messen. Hier werden zwei verschiedene Wege vorgestellt. Einerseits an der Anzahl der summierten Streams, andererseits an der Anzahl der verschiedenen Songs in den Charts.
#Die Bibliothek reshape2 wird für die Funktion melt() benötigt
library(reshape2)
#Die Bibliothek gridExtra ermöglicht das Darstellen von mehreren Plots in einer Grafik
library(gridExtra)
# Umwandlung der Daten in einen Dataframe mit den meisten Streams pro Artist
abb2 <- spotify %>%
group_by(Artist) %>%
summarise(Anzahl_Streams = sum(Streams)/1000000) %>%
arrange(desc(Anzahl_Streams)) %>%
head(23)
pabb2 <- ggplot(abb2) +
geom_col(aes(x = reorder(Artist, -Anzahl_Streams), y = Anzahl_Streams), fill = "firebrick2") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, colour = "black"),
axis.text.y = element_text(vjust = 0.5, hjust=1, colour = "black"),
panel.grid.major.y = element_line(colour = "grey",linetype = 1),
panel.grid.major.x = element_blank(),
panel.background = element_blank())+
labs(title = "Bad Bunnys und Taylor Swifts Chartsongs haben jeweils beinahe 400 Millionen Streams",
subtitle = "Erfolgreichste Artists: Summierte Streamzahlen der Chartsongs",
x = "Artists",
y = "Streams in Millionen")
# Umwandlung der Daten in einen Dataframe mit den meisten Songs pro Artist
abb3 <- spotify %>%
group_by(Artist) %>%
summarise(istFeature = sum(!is.na(Feature)),
keinFeature = sum(is.na(Feature))) %>%
filter(istFeature + keinFeature > 15)
# Die Funktion melt() wandelt mehrere Spalten in eine einzige um
mabb3 <- melt(abb3, id.vars = "Artist")
pabb3 <- ggplot(mabb3, aes(x = reorder(Artist, -value), y = value, fill = variable)) +
geom_bar(position = "stack", stat = "identity")+
scale_y_continuous(breaks = seq(0, 60, 10)) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, colour = "black"),
axis.text.y = element_text(vjust = 0.5, hjust=1, colour = "black"),
panel.grid.major.y = element_line(colour = "grey",linetype = 1),
panel.grid.major.x = element_blank(),
panel.background = element_blank())+
labs(title = "Bad Bunny hat in fast 2 Jahren an 57 Chart-Songs mitgewirkt",
subtitle = "Erfolgreiche Artists: Anzahl der Chartsongs",
x = "Artists",
y = "Anzahl Songs",
fill = "Art der Mitwirkung") +
scale_fill_manual(labels = c("Featuregast", "Hauptartist"), values = c("springgreen2", "hotpink2"))
grid.arrange(pabb2, pabb3, nrow = 2)
Die beiden Methoden zur Beurteilung des Erfolgs von Artists liefern ein ähnliches Ergebnis. Der Reggaeton-Künstler Bad Bunny und die Country-Sängerin Taylor Swift sind eindeutig die erfolgreichsten Artists des beobachteten Zeitraums. Generell lässt sich erkennen, dass die erfolgreichsten Artists aus den USA oder lateinamerikanischen Ländern wohnen. Ausnahmen sind BTS aus Südkorea, Dua Lipa aus Großbritannien und The Kid LAROI aus Australien. Die erfolgreichsten Genre (abgeleitet von den erfolgreichsten Artists) sind US-Rap und lateinamerikanischer Rap (Reggaeton).
Auch wenn es keine explizite Spalte für die Nationalität der Artists gibt, lassen sich die Songs der deutschen Artists herausfiltern. Die Genrenamen enthalten die Nationalität der Artists, solange diese nicht aus den USA stammen. Schauen wir uns die deutschen Lieder genauer an. Welche Genre schaffen es in die Top 200 Charts? Wirft man einen Blick auf die Daten sieht man, dass sich die Lieder in drei übergeordnete Genre einteilen lassen: Rap, Electronic Dance Music (EDM) und Pop.
# Alle deutsche Lieder.
german <- spotify %>%
filter(is.na(Feature)) %>%
filter(str_detect(Genre, "german"))
# Deutsche Rapsongs.
german_rap <- german %>%
filter(str_detect(Genre, "rap|hip hop")) %>%
mutate(Genre = "Rap")
# Deutsche EDM-Songs.
german_edm <- german %>%
filter(str_detect(Genre, "edm|dance")) %>%
mutate(Genre = "EDM")
#Deutsche Popsongs.
german_pop <- german %>%
filter(str_detect(Genre, "pop")) %>%
filter(!str_detect(Genre, "rap|hip hop|edm|dance")) %>%
mutate(Genre = "Pop")
tab1 <- german_rap %>%
add_row(german_edm) %>%
add_row(german_pop) %>%
group_by(Genre) %>%
summarise(Anzahl = n()) %>%
arrange(desc(Anzahl)) %>% view()
| Genre | Anzahl |
|---|---|
| Rap | 53 |
| EDM | 6 |
| Pop | 1 |
Auffällig ist, dass es hauptsächlich Rapsongs in die Charts schaffen. Vereinzelt kommen auch EDM-Songs vor. Deutsche EDM-Künstler sind in der ganzen Welt bekannt (z.B. Robin Schulz und Topic). Die vertretenen EDM-Lieder und der eine Popsong haben alle einen englischen Text, wohingegen die Rapsongs hauptsächlich auf Deutsch gerappt werden.
Der Datensatz beinhaltet mehrere Spalten, die die musikalischen Eigenschaften und die Stimmung der Songs beschreiben. Sechs dieser Spalten haben Werte zwischen 0 und 100 %. Anhand dieser Daten lassen sich musikalische Unterschiede verschiedener Genre darstellen. Die größten Genre der Charts sind Pop, Rap, Latin und Rock. Da Pop nicht eindeutig einzuordnen ist und sich mit anderen Genre überschneidet, betrachten wir nur die anderen drei Genre. Die Berechnung der musikalischen Eigenschaften (Erklärung siehe 2.1) ist nicht einsichtig und deshalb ist das Ergebnis mit Vorsicht zu genießen.
library(reshape2)
# Alle Rapsongs
rap <- spotify %>%
filter(str_detect(Genre, "rap|hip hop"), is.na(Feature)) %>%
select(Index, Song_Name, Danceability, Energy, Speechiness, Acousticness, Liveness, Valence) %>%
mutate(Genre = "Rap")
# Alle Rocksongs
rock <- spotify %>%
filter(str_detect(Genre, "rock"), is.na(Feature)) %>%
select(Index, Song_Name, Danceability, Energy, Speechiness, Acousticness, Liveness, Valence) %>%
mutate(Genre = "Rock")
# Alle lateinamerikanischen Songs
latin <- spotify %>%
filter(str_detect(Genre, "latin"), is.na(Feature)) %>%
select(Index, Song_Name, Danceability, Energy, Speechiness, Acousticness, Liveness, Valence) %>%
mutate(Genre = "Latin")
# Zusammenfassung der drei Genre
abb4 <- rap %>%
add_row(rock) %>%
add_row(latin) %>%
select(-c("Index", "Song_Name"))
# Verschmelzung der verschiedenen musikalischen Eigenschaften in eine Spalte
mabb4 <- melt(abb4, id.vars = "Genre")
pabb4 <- ggplot(mabb4, aes(x = variable, y = value, fill = Genre)) +
stat_boxplot(geom = "errorbar") +
geom_boxplot()+
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, colour = "black"),
axis.text.y = element_text(vjust = 0.5, hjust=1, colour = "black"),
panel.grid.major.y = element_blank(),
panel.grid.major.x = element_blank(),
panel.background = element_blank()) +
labs(title = "Die musikalischen Eigenschaften von Rap-Songs streuen sehr stark",
subtitle = "Gewichtung von musikalischen Eigenschaften für die Genre Latin, Rap und Rock",
x = "",
y = "")
pabb4
Es ist zu erkennen, dass die Genre bei den verschiedenen Kriterien relativ nah aneinander liegen. Die Tendenzen der unterschiedlichen Genre spiegeln allerdings tatsächlich die typischen Eigenschaften der Genre wieder. Zum Beispiel ist die Danceability vom Genre Latin höher als die vom Genre Rock und die Speechiness von Rap am höchsten. Besonders auffällig sind die Ausreißer bei Rapsongs, diese sind damit zu erklären, dass das Genre sehr divers ist. Betrachtet man die extremen Ausreißer von Rapsongs bei Acousticness genauer, fällt auf, dass es sich dabei meist um Intros, Outros, Interludes und Skits handelt. Diese vier Songformen sind oft Teil eines Rapalbums und unterscheiden sich stark von gewöhnlichen Rapsongs. Sie sind oft nicht länger als eine Minute lang und erzählen die Geschichte des Albums. Sie sind keine gewöhnlichen Lieder.
Während der Bearbeitung der Daten habe ich immer Musik gehört und wie es in der Vorweihnachtszeit oft der Fall ist, laufen viele Weihnachtslieder im Radio. Deshalb ist es interessant zu wissen, wann wie viele Weihnachtslieder in den Charts sind.
# Der Dataframe christmas enthält Lieder mit typischen Weihnachtswörtern im Titel
# 5 Lieder beinhalten Weihnachtswörter im Titel, sind aber keine Weichnachtslieder
# Diese werden herausgefiltert
christmas <- spotify %>%
filter(str_detect(Song_Name, "Christmas|Bell|Snow|Sleigh|Santa|Reindeer|Mistletoe")) %>%
filter(is.na(Feature)) %>%
filter(!str_detect(Index, "\\b366\\b|1090|1098|1272|1363")) %>%
select(Index, Song_Name, Weeks_Charted) %>%
mutate(Weeks_Charted = substr(Weeks_Charted,1,nchar(Weeks_Charted)-1))
# Ähnlich wie in der Datenbereitung (3.1) werden die Einträge in Weeks_Charted aufgesplitet
# Aus einem Eintrag aus n Wochen werden n Spalten
i = 1
for (i in c(1:185)) {
if(grepl("\n", christmas$Weeks_Charted[i])){
pos_first_space <- unlist(gregexpr("\n", christmas$Weeks_Charted[i]))
pos_first_space <- pos_first_space[1]
featured_week <- substr(christmas$Weeks_Charted[i], pos_first_space + 1, nchar(christmas$Weeks_Charted[i]))
christmas$Weeks_Charted[i] <- substr(christmas$Weeks_Charted[i], 1, pos_first_space - 1)
christmas <- christmas %>% add_row(Index = christmas$Index[i],
Song_Name = christmas$Song_Name[i],
Weeks_Charted = featured_week,
.after = i)
}
}
# spotify[30] ist der Song Blinding Lights, der alle Wochen in den Charts war.
# Aus dem Eintrag aus Weeks_charted wird ein Vektor erzeugt, der alle Wochen beinhaltet.
x_axis_christmas <- substr(spotify$Weeks_Charted[30], 1, nchar(spotify$Weeks_Charted[30])-1)
x_axis_christmas <- strsplit(x_axis_christmas, "\n")[[1]]
# Die erste Summarise-Funktion weist den jeweiligen Wochen die Anzahl an Weihnachtsliedern zu.
# Es gibt noch Lücken, weil es mehrere Wochen gibt, in dem kein Weihnachtslieder in den Charts waren.
# Durch add_row werden erneut alle Wochen hinzugefügt und mit der Anzahl 0 versehen
# Nach der zweiten Summarise-Funktion sind auch die Wochen mit Anzahl 0 enthalten.
abb5 <- christmas %>%
group_by(Weeks_Charted) %>%
summarise(Anzahl = n()) %>%
add_row(Weeks_Charted = x_axis_christmas, Anzahl = 0) %>%
group_by(Weeks_Charted) %>%
summarise(Anzahl = sum(Anzahl))
# Der Vektor cw soll nach den zwei For-Schleifen in den Wochen mit Anzahl > 0 die jeweilige Kalenderwoche anzeigen
cw <- 1:83
cw[1] = "2019, CW52"
for (i in 1:52) {
if (abb5$Anzahl[i + 1] != 0)
cw[i + 1] = paste("2020, CW", i)
else
cw[i + 1] = ""
}
for (i in 1:30) {
if (abb5$Anzahl[i + 53] != 0)
cw[i + 53] = paste("2021, CW", i)
else
cw[i + 53] = ""
}
# Zur visuellen Hilfe wird der Vektor cw für die x-Labels verwendet.
pabb5 <- ggplot(abb5) +
geom_col(aes(x = Weeks_Charted , y = Anzahl), fill = "firebrick2") +
scale_x_discrete(labels = cw) +
scale_y_continuous() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, colour = "black"),
axis.text.y = element_text(vjust = 0.5, hjust=1, colour = "black"),
panel.grid.major.y = element_line(colour = "grey",linetype = 1),
panel.grid.major.x = element_blank(),
panel.background = element_blank()) +
labs(title = "Vom 18. Dez 2020 bis zum 25. Dez 2020 waren 49 unterschiedliche Weihnachtslieder in den Charts",
subtitle = "Verteilung von Weihnachtsliedern in den Charts Ueber den Zeitraum",
x = "Zeit in Wochen")
pabb5
Im Jahr 2020 läuft bereits vom 30.10 bis zum 06.11 mit “All I Want For Christmas Is You” das erste Weihnachtslied in den Charts. Der Song von Mariah Carey ist außerdem der einzige Weihnachtssong, der es auf Platz 1 der Charts schaffte. Wie zu erwarten ist, steigt die Anzahl von Woche zu Woche an und gipfelt in der Weihnachtswoche. Interessanterweise konnten sich in der letzten Kalenderwoche des Jahres immer noch 25 Weihnachtslieder in den Charts halten. Im vergleich zur lezten Kalenderwoche von 2019 (nur 1 Song) ein enormer Anstieg. Ein möglicher Grund dafür ist, dass die letzte Kalenderwoche von 2019 mit dem 27.12 beginnt und die von 2020 mit dem 25.12. Noch verwunderlicher ist, dass in den ersten 11 Wochen von 2021 jeweils ein Lied in den Charts ist. Dabei handelt es sich um das Lied Snowman von Sia. Dieses Lied konnte sich so lange in den Charts halten, weil es auf der Platform TikTok eine Challenge zu diesem Lied gab.
Insgesamt lässt sich sagen, dass die Arbeit mit dem Datensatz und mit R seine Höhen und Tiefen hatte. Allgemein hat mir die Arbeit aber Spaß gemacht und ich habe viel über R gelernt und wie man bei einer Datenanalyse vorgeht.
Das Anspruchvolle an der Datenanylse war, dass man sich ein bestimmtes Ziel gesetzt (z.B. das Erstellen einer Grafik) und man wegen vermeintlichen Kleinigkeiten viel länger gebraucht hat als erwartet. Wie in der Datenbereinigung beschrieben, habe ich die Spalte Number of Times Charted von Fehlern bereinigt. Im Endeffekt gab es nur 6 Fehler, trotzdem habe ich dafür sehr viel Zeit benötigt. Weiterhin habe ich die Spalte in der folgenden Analyse gar nicht genutzt, da ich eine Idee verworfen hatte, die sich als nicht sehr aussagekräftig herausgestellt hatte.
Das gute an R ist, dass die Community im Internet recht gross ist. Deshalb konnte ich zu jedem Problem eine Lösung finden. Besonders mit ggplot2 hatte ich meine Probleme, wie zum Beispiel das die Label falsch angezeigt wurden. Auf stackoverflow.com gab es immer einen Nutzer der ein ähnliches Problem hatte und andere Nutzer die helfen konnten.
Abschliessend lässt sich sagen, dass ich nach diesem Projekt strukturierter an eine Datenanalyse gehen würde. Das Projekt war ein gutes Training für weitere Datenanlysen.