Aubrey Graham, aka Drake, is arguably one of the greatest rappers of all time. He is currently ranked number one on Spotify's monthly listeners list and his latest album, "More Life", reached number one on the Billboard top 200 with ease. He is one of the few rappers that has been able to bridge the gap between underground hype and mainstream commercial success.
For this project, I wanted to examine Drake's lyrical and musical evolution throughout the years. Did his lyrics become more positive or more negative as he became more successful? How does sentiment compare to Drake's record sales? How common is profanity in his music as his career progresses? I think that his music overall will prove to be more positive now than when he dropped his first album in 2008.
In order to extract the lyrics from all of Drake's individual albums, I scraped his tracklists from the Genius API. I joined the lyrics with the Bing lexicon, a list of words which are deemed by humans as either positive or negative, and subtracted the negative words from the positive ones to get a general measure of lyrical sentiment. I normalized the number by dividing it by the total number of Bing lexicon words present in the song.
I plotted the results for each song separated by album below. Songs closer to -1 in sentiment are seen as more negative and songs closer to 1 are perceived as more positive.
I was surprised to find that most of Drake's lyrics have a negative sentiment attributed to them. Take Care and Nothing Was The Same are infamously melancholy albums, but I did not expect that none of his albums would have a majority of tracks with positive lyrical sentiment. Views is Drake's only album where half of the songs are neutral or positive.
It is important to note that the Bing lexicon can’t pick up on negation or irony. A song like "Portland" on More Life has a sentiment rate of -0.5 because of all of the profanity, but a human would most likely not think it has a negative connotation.
In the past decade, Spotify has grown into the premiere online destination for streaming music. One of Spotify's most effective tools is its ability to recommend songs to its users based on previous choices. The company does this by classifying songs into different categories. Categories include: danceability, energy, key, valence, acousticness, instrumentalness, liveness and tempo. When a song fits a certain amount of criteria based on user feedback, a new song will appear on a customer's "discover weekly" playlist.
For this study, I chose to examine the "valence" in each of Drake's songs as a representation of sentiment. I wanted to see how valence may have changed over time in Drake's music and how similar it is with lyrical sentiment. Spotify uses the word “valence” to measure whether a song is likely to make someone feel happy (higher valence) or sad (lower valence). The metric is measured on a scale from 0.0 to 1.0. According to Spotify's records, the average valence of popular music over the past fifty years hovers around 0.5.
It is also important to note that Spotify does not own the streaming rights to a few of the songs on Drake's discography, which is why there are fewer songs on certain albums.
Below are the graphs of the valence across all of Drake's individual studio albums.
It appears that lyrical sentiment and musical valence do not have a strong correlation on a song-to-song basis. Many of the songs that are considered to be negative according to the Bing lexicon are actually classified as positive in terms of valence. "Crew Love" and "Buried Alive" both have inversely related valences and lyrical sentiments. Also, many of the songs on If You're Reading This it's Too Late are much more positive in musical valence than lyrical sentiement.
I think that fans of Drake will agree that valence is a more accurate representation of the sentiment. The Nothing Was The Same graph made a lot of sense. I can barely get through some of the songs on that album without shedding a tear. Only one song from Nothing Was The Same, the hit "Started From the Bottom", broke a 0.5 valence rating.
To get a broad overview of the most common words in Drake's albums, I made some wordclouds. Wordclouds are a fun way to visualize word frequency in large bodies of text. The size of the words in each cloud represent its frequency in tracks featured on the album. The larger the word, the more times it is said.
I would recommend not scrolling down if you are younger than 18 years old or are easily offended by profanity.
At the beginning of Drake's career, he was known as somewhat of a heartthrob, which I think reflected in the first three clouds above. There is a much higher use of the words "Girl" and "Love" as well as action verbs in his earlier work than in later albums. His profanity use also significantly increased after his debut album.
Drake is well-known for popularizing terms and phrases such as "YOLO" (You Only Live Once), woes (friends) or the 6 (Toronto). The latter two terms can be found on the last three clouds. YOLO was used seven times on Take Care.
In summary, it appears that Drake's music has become more positive with his last two albums, but only after a stretch of consistent negative sentiment in Take Care and Nothing Was The Same. However, I would not say that my hypothesis was completely correct. More Life and Views are not overwhelmingly positive, but they are less negative than his previous albums according to the Bing lexicon and Spotify's valence metric.
In terms of comparing sentiment to record sales, it seems like Drake's more negative albums are more popular. Take Care is Drake's best-selling album according to Billboard. In my study, Take Care ranks high in negativity in lyrical and musical sentiment. Nothing Was The Same is second in his record sales, another relatively negative album that was one of the most negative in terms of valence as well as lyrical sentiment.
It would be interesting for further studies to investigate Spotify's other variables in Drake's music. I did not analyze “danceability,” “energy,” “key,” “loudness,” “speechiness,” “acousticness,” “instrumentalness,” “tempo,” or “time_signature,” which can all be found on Spotify's API.
Genius Code
devtools::install_github('josiahparry/geniusR')
library(geniusR)
library(tidyverse)
library(dplyr)
library(tidytext)
#genius
genius_get_artists <- function(artist_name, n_results = 10)
baseURL <- 'https://api.genius.com/search?q='
# Get song search results for the term 'good morning'
gm_search <- search_song(search_term = "good morning")
test <- genius_album(artist = "Kanye West")
?geniusR
genius_album(artist = "Drake", album = "So Far Gone") -> SoFarGone
genius_album(artist = "Drake", album = "Thank Me Later")
genius_album(artist = "Drake", album = "Views") -> ViewsLyrics
ViewsLyrics$text <- as.character(ViewsLyrics$text)
tidy_ViewsLyrics <- ViewsLyrics %>% unnest_tokens(word, text)
cleaned_ViewsLyrics <- tidy_ViewsLyrics %>% anti_join(stop_words)
ViewsLyrics_sentiment <- cleaned_ViewsLyrics %>% inner_join(bing) %>% count(title, sentiment) %>% spread(sentiment, n, fill = 0) %>% mutate(sentiment = (positive - negative)/(positive + negative))
ggplot(I, aes(title, sentiment)) + geom_bar(stat = "identity") + theme_economist() + coord_flip() + ggtitle("Views") + xlab("Song Title")
genius_album(artist = "Drake", album = "If You re Reading This It s Too Late") -> IfYourereading
IfYourereading$text <- as.character(IfYourereading$text)
tidy_IfYourReadingLyrics <- IfYourereading %>% unnest_tokens(word, text)
cleaned_IfYoureReadingLyrics <- tidy_IfYourReadingLyrics %>% anti_join(stop_words)
IfYoureReadingLyric_sentiment <- cleaned_IfYoureReadingLyrics %>% inner_join(bing) %>% count(title, sentiment) %>% spread(sentiment, n, fill = 0) %>% mutate(sentiment = (positive - negative)/(positive + negative))
ggplot(IfYoureReadingLyric_sentiment, aes(title, sentiment)) + geom_bar(stat = "identity") + theme_economist() + coord_flip() + ggtitle("If You're Reading This") + xlab("Song Title")
cleaned_IfYoureReadingLyrics2 %>% group_by(n) %>% head(20) -> IfYoureReadingMostCommon
cleaned_IfYoureReadingLyrics %>% count(word, sort = TRUE) -> cleaned_IfYoureReadingLyrics2
genius_album(artist = "Drake and Future", album = "What A Time To Be Alive") -> WhatATime
WhatATime$text <- as.character(WhatATime$text)
tidy_WhatATime <- WhatATime %>% unnest_tokens(word, text)
cleaned_WhatATime <- tidy_WhatATime %>% anti_join(stop_words)
WhatATime_sentiment <- cleaned_WhatATime %>% inner_join(bing) %>% count(title, sentiment) %>% spread(sentiment, n, fill = 0) # %>% # mutate(sentiment = (positive - negative)/(positive + negative))
ggplot(WhatATime_sentiment, aes(title, sentiment)) + geom_bar(stat = "identity") + theme_economist() + coord_flip() + ggtitle("What A Time To Be Alive") + xlab("Song Title")
genius_album(artist = "Drake", album = "More Life") -> MoreLife
MoreLife$text <- as.character(MoreLife$text)
tidy_MoreLife <- MoreLife %>% unnest_tokens(word, text)
cleaned_MoreLife <- tidy_MoreLife %>% anti_join(stop_words)
MoreLife_Lsentiment <- cleaned_MoreLife %>% inner_join(bing) %>% count(title, sentiment) %>% spread(sentiment, n, fill = 0) %>% mutate(sentiment = (positive - negative)/(positive + negative))
ggplot(MoreLife_Lsentiment, aes(title, sentiment)) + geom_bar(stat = "identity") + theme_economist() + coord_flip() + ggtitle("More Life") + xlab("Song Title")
SoFarGone$text <- as.character(SoFarGone$text)
tidy_drake <- SoFarGone %>% unnest_tokens(word, text)
cleaned_sofargone <- tidy_drake %>% anti_join(stop_words)
bing <- get_sentiments("bing")
SoFarGone_sentiment <- cleaned_sofargone %>% inner_join(bing) %>% count(title, sentiment) %>% spread(sentiment, n, fill = 0) %>% mutate(sentiment = (positive - negative)/(positive + negative))
ggplot(SoFarGone_sentiment, aes(title, sentiment)) + geom_bar(stat = "identity") + theme_economist() + coord_flip() + ggtitle("So Far Gone") + xlab("Song Title")
ThankMeLater$text <- as.character(ThankMeLater$text)
tidy_Thankme <- ThankMeLater %>% unnest_tokens(word, text)
cleaned_Thankme <- tidy_Thankme %>% anti_join(stop_words)
ThankMeLater_sentiment <- cleaned_Thankme %>% inner_join(bing) %>% count(title, sentiment) %>% spread(sentiment, n, fill = 0) %>% mutate(sentiment = (positive - negative)/(positive + negative))
ggplot(ThankMeLater_sentiment, aes(title, sentiment)) + geom_bar(stat = "identity") + theme_economist() + coord_flip() + ggtitle("Thank Me Later") + xlab("Song Title")
NothingWasTheSame$text <- as.character(NothingWasTheSame$text)
tidy_Nothingwasthesame <- NothingWasTheSame %>% unnest_tokens(word, text)
cleaned_Nothing <- tidy_Nothingwasthesame %>% anti_join(stop_words)
NothingWasTheSame_sentiment <- cleaned_Nothing %>% inner_join(bing) %>% count(title, sentiment) %>% spread(sentiment, n, fill = 0) %>% mutate(sentiment = (positive - negative)/(positive + negative))
ggplot(NothingWasTheSame_sentiment, aes(title, sentiment)) + geom_bar(stat = "identity") + theme_economist() + coord_flip() + ggtitle("Nothing Was The Same") + xlab("Song Title")
TakeCare$text <- as.character(TakeCare$text)
tidyTakeCare <- TakeCare %>% unnest_tokens(word, text)
cleaned_TakeCare <- tidyTakeCare %>% anti_join(stop_words)
TakeCare_sentiment <- cleaned_TakeCare %>% inner_join(bing) %>% count(title, sentiment) %>% spread(sentiment, n, fill = 0) %>% mutate(sentiment = (positive - negative)/(positive + negative))
ggplot(TakeCare_sentiment, aes(title, sentiment)) + geom_bar(stat = "identity") + theme_economist() + coord_flip() + ggtitle("Take Care") + xlab("Song Title")
TakeCareWordCount <- cleaned_TakeCare %>% count(word, sort = TRUE)
MoreLifeWordCount <- cleaned_MoreLife %>% count(word, sort = TRUE)
WhatATimeWordCount <- cleaned_WhatATime %>% count(word, sort = TRUE)
SoFarGoneWordCount <- cleaned_sofargone %>% count(word, sort = TRUE)
ThankMeLaterWordCount <- cleaned_Thankme %>% count(word, sort = TRUE)
NothingWasTheSameWordCount2 <- NothingWasTheSameWordCount %>% filter(!word %in% c("yeah", "em"))
NothingWasTheSameWordCount <- cleaned_Nothing %>% count(word, sort = TRUE)
TakeCareWordCount2 <- TakeCareWordCount
devtools::install_github("lchiffon/wordcloud2")
names(TakeCareWordCount2)[2] <- "freq"
wordcloud2(NothingWasTheSameWordCount2, size = 1, shape = "oval", fontFamily = "Courier", #color = "random_light", backgroundColor = "#3333", minRotation = -pi/6, maxRotation = -pi/6, rotateRatio = 1.5)
wordcloud(TakeCareWordCount$word, TakeCareWordCount$n, max.words = 120, colors = brewer.pal(8, "Dark2"), scale = c(2,2))
wordcloud2(SoFarGoneWordCount2,size = 1, shape = "oval", fontFamily = "Courier", # color = "red", backgroundColor = "#3333", minRotation = -pi/6, maxRotation = -pi/6, rotateRatio = 1.5)
Spotify code
devtools::install_github('charlie86/spotifyr') library(spotifyr)
install.packages("spotifyr")
access_token - get_spotify_access_token()
WhatATime_df - get_artist_audio_features("Drake")
IfYourereadingThisSpotify - spotify_df %>% filter(album_name =="If Youre Reading This Its Too Late")
ggplot(IfYourereadingThisSpotify, aes(track_name, valence)) + geom_bar(stat = "identity") + theme_wsj() + coord_flip() + ggtitle("If You're Reading This It's Too Late") + xlab("Song Title")
ThankMeLaterSpotify - spotify_df %/% filter(album_name =="Thank Me Later")
ggplot(ThankMeLaterSpotify, aes(track_name, valence)) + geom_bar(stat = "identity", fill="red") + theme_economist() + coord_flip() + ggtitle("Thank Me Later") + xlab("Song Title")
SoFarGoneSpotify <- spotify_df %>% filter(album_name=="So Far Gone")
ggplot(SoFarGoneSpotify, aes(track_name, valence)) + geom_bar(stat = "identity", fill="dark green") + theme_economist() + coord_flip() + ggtitle("So Far Gone") + xlab("Song Title")
TakeCareSpotify <- spotify_df %>% filter(album_name=="Take Care")
ggplot(TakeCareSpotify, aes(track_name, valence)) + geom_bar(stat = "identity", fill="Yellow") + theme_economist_white() + coord_flip() + ggtitle("Take Care") + xlab("Song Title")
NothingWasTheSameSpotify <- spotify_df %>% filter(album_name=="Nothing Was The Same")
ggplot(NothingWasTheSameSpotify, aes(track_name, valence)) + geom_bar(stat = "identity", fill="blue") + theme_economist() + coord_flip() + ggtitle("Nothing Was The Same") + xlab("Song Title")
ViewsSpotify <- spotify_df %>% filter(album_name=="Views")
ggplot(ViewsSpotify, aes(track_name, valence)) + geom_bar(stat = "identity", fill="light blue") + theme_economist() + coord_flip() + ggtitle("Views") + xlab("Song Title")
MoreLifeSpotify <- spotify_df %>% filter(album_name=="More Life")
ggplot(MoreLifeSpotify, aes(track_name, valence)) + geom_bar(stat = "identity", fill="black") + theme_economist_white() + coord_flip() + ggtitle("More Life") + xlab("Song Title")