Analisando dados de streaming do Spotify no Brasil

Dia 46 de quarentena: finalmente resolvi fazer um blog pra juntar tudo que tenho feito em R nas horas vagas. Para o primeiro post, vou utilizar um dos meus datasets favoritos, o Spotify Charts, que disponibiliza os rankings diários e semanais das 200 músicas com maior número de streamings no Spotify. O post será dividido em 2 partes: aquisição e análise dos dados.

Aquisição de dados

Primeiramente, vamos carregar os pacotes que iremos usar:

library(rvest)        
library(tidyverse)
library(scales)
library(janitor)
library(lubridate)
library(furrr)
library(glue)
library(tidytext)

theme_set(theme_light())

No topo direito da página, há uma opção para exportar os dados em formato .csv. No entanto, cada exportação gera apenas os dados do dia selecionado. Se copiarmos o link correspondente ao botão, veremos que segue o seguinte padrão spotifycharts.com/regional/br/daily/YYYY-MM-DD/download com YYYY-MM-DD correspondendo a data a ser exportada. Para exportar todas as datas que desejamos, então, basta substituir o espaço destinado a elas no link. Vamos fazer o download da tabela de 2 dias atrás para ver como o resultado é disponibilizado:

tabela_individual <- read_csv(glue("https://spotifycharts.com/regional/br/daily/{Sys.Date() - 2}/download"))

tabela_individual
## # A tibble: 201 x 5
##    X1     X2           X3       `Note that these figures are g~ X5              
##    <chr>  <chr>        <chr>    <chr>                           <chr>           
##  1 Posit~ Track Name   Artist   Streams                         URL             
##  2 1      A Gente Fez~ Gusttav~ 521613                          https://open.sp~
##  3 2      Don't Start~ Dua Lipa 443213                          https://open.sp~
##  4 3      Liberdade P~ Henriqu~ 413044                          https://open.sp~
##  5 4      BRABA        Luísa S~ 394097                          https://open.sp~
##  6 5      Tudo no Sig~ Vytinho~ 364649                          https://open.sp~
##  7 6      Graveto - A~ Marília~ 349974                          https://open.sp~
##  8 7      Litrão - Ao~ Matheus~ 342073                          https://open.sp~
##  9 8      Roses - Ima~ SAINt J~ 331409                          https://open.sp~
## 10 9      Rave de Fav~ MC Lan   324164                          https://open.sp~
## # ... with 191 more rows

Percebemos que o resultado sai com um texto acima do nome das colunas, logo precisaremos especificar que essa primeira linha deve ser ignorada na hora de ler a tabela. Além, disso, precisaremos criar uma coluna para especificar a data, e usar a função clean_names do pacote janitor para padronizar o nome das colunas.

Antes de baixar todas as tabelas, no entanto, precisamos saber quais dias estão disponíveis para download. Para isso, será preciso o uso de webscraping, ou seja, extrair dados diretamente de um website. Faremos isso com o auxilio do programa Selector Gadget, uma extensão do Chrome que permite identificar qual parte do CSS do site você deseja extrair, conforme mostra a imagem abaixo:

Usando os pacotes rvest e purrr, extraímos as datas disponíveis:

datas_disponiveis <- read_html("https://www.spotifycharts.com/regional/br/daily/") %>%
  html_nodes(".responsive-select~ .responsive-select+ .responsive-select .responsive-select-value , .responsive-select li") %>%
  map(html_text) %>%
  map_chr(rbind)

head(datas_disponiveis)
## [1] "Global"         "United States"  "United Kingdom" "Andorra"       
## [5] "Argentina"      "Austria"
tail(datas_disponiveis)
## [1] "01/06/2017" "01/05/2017" "01/04/2017" "01/03/2017" "01/02/2017"
## [6] "01/01/2017"

Podemos perceber que, além das datas disponíveis, também foram extraídos os países disponíveis. Portanto, precisamos filtrar para que fiquem apenas as datas e colocá-las no formato YYYY-MM-DD (vamos também filtrar apenas datas do ano de 2019 e 2020).

datas_disponivels_filtradas <- datas_disponiveis %>%
  enframe(name = NULL) %>%                              # transformando o vetor em tabela
  filter(str_detect(value, "\\d")) %>%                  # deixando apenas valores com presença de numeros
  mutate(value = mdy(value)) %>%
  filter(year(value) %in% c(2019, 2020)) %>%            # deixando apenas anos 2019 e 2020
  distinct(value) %>%
  pull(value)

head(datas_disponivels_filtradas)
## [1] "2020-05-06" "2020-05-05" "2020-05-04" "2020-05-03" "2020-05-02"
## [6] "2020-05-01"

Agora que temos nossas datas, podemos fazer download de todas as tabelas de uma vez só, criando uma função que será repetida para cada data. Usaremos o pacote furrr, que aplica as funções do pacote purrr em paralelo, ganhando velocidade. A próxima parte pode levar alguns minutos para concluir. Se você preferir, pode baixar os dados diretamente daqui.

funcao_tabelas <- function(x){
  read_csv(glue("https://spotifycharts.com/regional/br/daily/{x}/download"),
           skip = 1) %>%
    clean_names("upper_camel") %>%      # padronizando nomes das colunas
    mutate(Date = x)
}

plan(multiprocess)
tabela_spotify <- future_map_dfr(datas_charts_filtered, funcao_tabelas, .progress = TRUE)
## # A tibble: 98,200 x 6
##    Position TrackName        Artist     Streams Url                   Date      
##       <dbl> <chr>            <chr>        <dbl> <chr>                 <date>    
##  1        1 A Gente Fez Amo~ Gusttavo ~  521613 https://open.spotify~ 2020-05-05
##  2        2 Don't Start Now  Dua Lipa    443213 https://open.spotify~ 2020-05-05
##  3        3 Liberdade Provi~ Henrique ~  413044 https://open.spotify~ 2020-05-05
##  4        4 BRABA            Luísa Son~  394097 https://open.spotify~ 2020-05-05
##  5        5 Tudo no Sigilo   Vytinho NG  364649 https://open.spotify~ 2020-05-05
##  6        6 Graveto - Ao Vi~ Marília M~  349974 https://open.spotify~ 2020-05-05
##  7        7 Litrão - Ao Vivo Matheus &~  342073 https://open.spotify~ 2020-05-05
##  8        8 Roses - Imanbek~ SAINt JHN   331409 https://open.spotify~ 2020-05-05
##  9        9 Rave de Favela ~ MC Lan      324164 https://open.spotify~ 2020-05-05
## 10       10 Ranking          Jorge & M~  303451 https://open.spotify~ 2020-05-05
## # ... with 98,190 more rows

Uma ultima alteração: algumas músicas tem um complemento após o nome, como “- Ao Vivo” ou “(feat.)”. Vamos remover esses complementos para que diferentes versões de uma música sejam consideradas como uma só.

tabela_spotify <- tabela_spotify %>%
  mutate(TrackName = str_remove(TrackName, " \\-.*| \\(.*"))

Agora que temos nosso dataset, podemos partir para a segunda etapa do post.

Análise de dados

Vamos começar com duas perguntas básicas: quais os artistas e as músicas mais populares no Brasi durante o período?

tabela_spotify %>%
  group_by(Ano = year(Date), Artist) %>%
  summarise(Total = sum(Streams)) %>%
  arrange(-Total) %>%
  top_n(25, Total) %>%
  ungroup() %>%
  mutate(Artist = tidytext::reorder_within(Artist, Total, within = Ano)) %>%
  ggplot(aes(x = Artist, y = Total)) +
  geom_col(fill = "red") +
  coord_flip() +
  facet_wrap(~ Ano, scales = "free") +
  scale_y_continuous(labels = unit_format(suffix = "M", scale = 1e-6)) +
  scale_x_reordered() +
  labs(x = "",
       y = "",
       title = "Marilia Mendonça é a artista mais popular do Brasil",
       subtitle = "Baseado no número de streams do Spotify em 2019 e 2020")

Clique abaixo para ouvir algumas das músicas da artista mais popular do Brasil:

tabela_spotify %>%
  group_by(Ano = year(Date), TrackName) %>%
  summarise(Total = sum(Streams)) %>%
  arrange(-Total) %>%
  top_n(25, Total) %>%
  ungroup() %>%
  mutate(TrackName = tidytext::reorder_within(TrackName, Total, within = Ano)) %>%
  ggplot(aes(x = TrackName, y = Total)) +
  geom_col(fill = "blue") +
  coord_flip() +
  facet_wrap(~ Ano, scales = "free") +
  scale_y_continuous(labels = unit_format(suffix = "M", scale = 1e-6)) +
  scale_x_reordered() +
  labs(x = "",
       y = "",
       title = "Liberdade Provisória é a música mais tocada no Brasil em 2020",
       subtitle = "Baseado no número de streams do Spotify")

Clique abaixo para ouvir a música mais popular do Brasil em 2020 ate o momento:

Agora que sabemos quais as musicas e os artistas mais populares, vamos tentar detalhar um pouco mais essas informações, de maneiras diferentes. Para os artistas, faremos uma animação com o número acumulado de streams por semana no ano de 2020, ate chegar na semana atual que representa o gráfico anterior:

library(gganimate)

por_semana <- tabela_spotify %>%
  filter(year(Date) == 2020) %>%
  group_by(Artist) %>%
  mutate(TotalArtista = sum(Streams)) %>%
  ungroup() %>%
  mutate(Artist = fct_lump(Artist, 20, w = TotalArtista)) %>%
  filter(Artist != "Other") %>%
  group_by(Semana = floor_date(Date, "week"), Artist) %>%
  summarise(Total = sum(Streams)) %>%
  ungroup() %>%
  group_by(Artist) %>%
  mutate(Acumulado = cumsum(Total)) %>%
  group_by(Semana) %>%
  mutate(Rank = rank(-Acumulado)) %>%
  ungroup() %>%
  mutate(Artist = as.factor(Artist)) %>%
  select(-Total)

baseplot1 <- por_semana %>%
  ggplot(aes(x = Semana, group = Artist, fill = Artist, color = Artist)) +
  geom_bar(aes(y = Acumulado), stat = "identity", position = "dodge") +
  theme(legend.position = "bottom")

baseplot2 <- baseplot1 +
  coord_flip(clip = "off", expand = FALSE)

baseplot3 <- por_semana %>%
  ggplot(aes(x = Rank,
             group = Artist, 
             fill = Artist, 
             color = Artist)) +
  geom_text(aes(y = 0, label = paste(Artist, " ")), vjust = 0.2, hjust = 1) +
  coord_flip(clip = "off", expand = FALSE) +
  geom_bar(aes(y = Acumulado), stat = "identity", position = "identity") +
  theme(legend.position = "none",
        axis.ticks.y = element_blank(), 
        axis.text.y  = element_blank(), 
        axis.title.y = element_blank(),
        plot.margin = margin(1, 1, 1, 5, "cm")) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_reverse()

animp <- baseplot3 +
  geom_text(aes(y = Acumulado, 
                label = as.character(Acumulado)), 
            color = "black", vjust = 0.2, hjust = .5) +
  labs(title = "Semana {closest_state}", 
       y = "Total acumulado de streams") +
  transition_states(Semana, transition_length = 5,
                    state_length = c(rep(.25, 18), 50), wrap = FALSE) +
  ease_aes('linear') +
  enter_fade() +
  exit_fade()

animate(animp, fps = 10, duration = 20, width = 800, height = 450)

Ja para as músicas, pode-se perceber no gráfico anterior que a música mais popular de 2019 não aparece entre as mais populares de 2020 até o momento. Isso me levou a pensar sobre a duração do auge de popularidade de uma música. Assim, analisaremos as músicas mais populares ao longo de todo o período analisado, para descobrirmos quais foram as músicas de momento em diferentes épocas.

library(gghighlight)


tabela_spotify %>%
  filter(Position == 1) %>%
  mutate(TrackName = fct_lump(TrackName, n = 10, other_level = "Outras")) %>%        
  ggplot(aes(x = Date, y = Streams)) +
  geom_col(aes(fill = TrackName)) +
  scale_y_continuous(labels = unit_format(suffix = "M", scale = 1e-6)) +
  scale_x_date(breaks = function(x) seq.Date(min(x), max(x), by = "2 month"),
               date_labels = "%b/%y") +
  labs(x = "",
       y = "",
       fill = "Musica",
       title = "As musicas de momento no Brasil desde 2019",
       subtitle = "Baseado nas músicas mais ouvidas por dia durante o período") +
  theme(legend.position = "none",
        axis.text.x = element_text(angle = 90, hjust = 0.5)) +
  gghighlight() + 
  facet_wrap(~ TrackName)

Fica claro quais músicas dominaram cada época de 2019 até o dia atual. No início do ano passado, por exemplo, a música do momento foi “Jenifer”. Já no meio do ano passado, o hit foi “Todo Mundo Vai Sofrer”. “Liberdade Provisória”, do Henrique & Juliano, teve o pico de popularidade mais longo, entre Dezembro e meio de Março, com uma breve interrupção no carnaval quando foi ultrapassado por “Tudo Ok”, do Thiaguinho MT. Já atualmente, a música mais popular é “A Gente Fez Amor”, conforme percebemos anteriormente.

Para evitar que o post fique muito longo, vamos finalizar por aqui. No entanto, há ainda muitas outras coisas interessantes a serem desvendadas com o nosso dataset, que pode servir também como um divertido instrumento de aprendizado de R. Caso você tenha alguma dúvida ou sugestão, fique a vontade para entrar em contato. Obrigado pela leitura!

 Share!

 
comments powered by Disqus