Reformatear tablas

Las funciones para cambiar las tablas de formato son melt y dcast. Estas funciones están optimizadas para funcionar con grandes cantidades de datos guardados en memoria (10GB).

Larga a ancha

Actualmente tenemos una tabla larga. Vamos a convertirla en una tabla en la que las columnas sean los 73 paises y las canciones las filas. Los valores van a ser el numero de veces en las que cada canción ha aparecido en el listado de las 50 canciones más populares (data) en el último año. Adicionalmente vamos a mantener la columna de la fecha del listado (snapshot_date) pero la vamos a modificar de modo que nos quedemos con el mes y el año.

Larga a ancha:

dcast(data, formula, fun.aggregate = NULL, sep = "_",
    ..., margins = NULL, subset = NULL, fill = NULL,
    drop = TRUE, value.var = guess(data),
    verbose = getOption("datatable.verbose"))

# Vamos a utilizar la tabla de canciones del top50 en 73 paises

# Queremos crear una tabla de conteos de cada cancion por pais por mes en el que se hizo el listado top 50
freq_song_long <- data[country != "",.(.N), by = .(name,country,month_yr = format(snapshot_date,"%Y-%m"))]
freq_song_long
                                                     name country month_yr     N
                                                   <char>  <char>   <char> <int>
    1:  Yebo Lapho (Gogo) (feat. DJ Maphorisa & Djy Biza)      ZA  2024-09     8
    2: Sdakiwe Sbali (feat. Bless The Gentleman & DJ Kap)      ZA  2024-09     8
    3:      Mfazi Wephepha (feat. Big Zulu & Zee Nxumalo)      ZA  2024-09     8
    4:      Kwelanga 2.0 (feat. Tman Xpress & LeeMcKrazy)      ZA  2024-09     8
    5:                     eGoli (feat. Eltee & Novatron)      ZA  2024-09     8
   ---                                                                          
75846:                  Nachts wach (Lila Wolken Bootleg)      AT  2023-10     2
75847:                                             HIBIKI      AR  2023-10     2
75848:                          Slime You Out (feat. SZA)      AE  2023-10     2
75849:                  SAY MY GRACE (feat. Travis Scott)      AE  2023-10     2
75850:                                         Rainy Days      AE  2023-10     2
freq_song_wide <- dcast(freq_song_long, month_yr+name~country, value.var = "N", fill = 0)
freq_song_wide[,1:9]
Key: <month_yr, name>
       month_yr                                          name    AE    AR    AT    AU    BE    BG    BO
         <char>                                        <char> <int> <int> <int> <int> <int> <int> <int>
    1:  2023-10                                                   0     0     0     0     0     0     0
    2:  2023-10 ""Slut!"" (Taylor's Version) (From The Vault)     3     0     3     3     3     3     0
    3:  2023-10                                   $AD BOYZ II     0     0     0     0     0     0     0
    4:  2023-10                  (It Goes Like) Nanana - Edit     0     0     0     5    14     0     0
    5:  2023-10                                   0800 HEAVEN     0     0     0     0     0     0     0
   ---                                                                                                 
37446:  2024-09                                        青と夏     0     0     0     0     0     0     0
37447:  2024-09                                高嶺の花子さん     0     0     0     0     0     0     0
37448:  2024-09                                          黑月     0     0     0     0     0     0     0
37449:  2024-09                                        黑玻璃     0     0     0     0     0     0     0
37450:  2024-09                            별별별 (See that?)     0     0     0     0     0     0     0

La función dcast también nos permite agregar valores de acuerdo a una función mientras cambiamos el formato de las tablas. Esto es útil cuando nuestra fórmula no puede identificar de manera única cada fila. Por ejemplo, si quiseramos comparar la popularidad promedio de cada canción entre el 2023 y el 2024 podemos hacer lo siguiente:

dcast(data[country != ""], country + name ~ format(snapshot_date,"%Y"), value.var = "popularity", fun.aggregate = function(x){round(mean(x, na.rm = T),digits = 1)})
Key: <country, name>
       country                                                                 name  2023  2024
        <char>                                                               <char> <num> <num>
    1:      AE                        ""Slut!"" (Taylor's Version) (From The Vault)  85.4   NaN
    2:      AE                                         (It Goes Like) Nanana - Edit   NaN  87.0
    3:      AE                                                            100 Bands   NaN  53.4
    4:      AE                                                                   22   NaN  35.0
    5:      AE                                                               3 Days   NaN   1.0
   ---                                                                                         
29523:      ZA uKhome Lotto (feat. Agzo, Optimist Music ZA, Seun1401 & El.Stephano)   NaN  55.3
29524:      ZA                        uLala Kanjani (feat. LeeMcKrazy & Skandisoul)  61.0   NaN
29525:      ZA                             we can't be friends (wait for your love)   NaN  91.5
29526:      ZA                                                    whatsapp (wassam)   NaN   0.0
29527:      ZA                                                            yes, and?   NaN  84.0

Ahora imagina que te gustaría pasar de ancha a larga utilizando dos columnas. Por ejemplo, para compara la popularidad y el ranking promedio por año. Podemos indicar múltiples columnas en value.var

pop_rank_per_year <- dcast(data[country != ""], country + name ~ format(snapshot_date,"%Y"), value.var = c("daily_rank", "popularity"), sep = ".", fun.aggregate = function(x){round(mean(x, na.rm = T),digits = 1)})

pop_rank_per_year
Key: <country, name>
       country                                                                 name daily_rank.2023 daily_rank.2024
        <char>                                                               <char>           <num>           <num>
    1:      AE                        ""Slut!"" (Taylor's Version) (From The Vault)            28.7             NaN
    2:      AE                                         (It Goes Like) Nanana - Edit             NaN            33.0
    3:      AE                                                            100 Bands             NaN             2.7
    4:      AE                                                                   22             NaN            26.0
    5:      AE                                                               3 Days             NaN             1.0
   ---                                                                                                             
29523:      ZA uKhome Lotto (feat. Agzo, Optimist Music ZA, Seun1401 & El.Stephano)             NaN            42.0
29524:      ZA                        uLala Kanjani (feat. LeeMcKrazy & Skandisoul)            33.1             NaN
29525:      ZA                             we can't be friends (wait for your love)             NaN            33.3
29526:      ZA                                                    whatsapp (wassam)             NaN            42.0
29527:      ZA                                                            yes, and?             NaN            30.5
       popularity.2023 popularity.2024
                 <num>           <num>
    1:            85.4             NaN
    2:             NaN            87.0
    3:             NaN            53.4
    4:             NaN            35.0
    5:             NaN             1.0
   ---                                
29523:             NaN            55.3
29524:            61.0             NaN
29525:             NaN            91.5
29526:             NaN             0.0
29527:             NaN            84.0

Ancha a larga

Ancha a larga:

melt(data, id.vars, measure.vars,
    variable.name = "variable", value.name = "value",
    ..., na.rm = FALSE, variable.factor = TRUE,
    value.factor = FALSE,
    verbose = getOption("datatable.verbose"))

freq_song_long2 <- melt(freq_song_wide, id.vars = c("month_yr","name"), variable.name = "country", value.name = "N")
freq_song_long2
         month_yr                                          name country     N
           <char>                                        <char>  <fctr> <int>
      1:  2023-10                                                    AE     0
      2:  2023-10 ""Slut!"" (Taylor's Version) (From The Vault)      AE     3
      3:  2023-10                                   $AD BOYZ II      AE     0
      4:  2023-10                  (It Goes Like) Nanana - Edit      AE     0
      5:  2023-10                                   0800 HEAVEN      AE     0
     ---                                                                     
2696396:  2024-09                                        青と夏      ZA     0
2696397:  2024-09                                高嶺の花子さん      ZA     0
2696398:  2024-09                                          黑月      ZA     0
2696399:  2024-09                                        黑玻璃      ZA     0
2696400:  2024-09                            별별별 (See that?)      ZA     0

De manera similar a dcast, podemos reformatear una tabla para conservar más de una columna en la tabla en formato largo. Por ejemplo, si tenemos la tabla generada anteriormente con el ranking promedio diario por año y la popularidad promedio por año, y quisiéramos una tabla que separara las medidas de popularidad en una columna y el ranking promedio en otra, podemos hacerlo de la siguiente manera:

## Forma 1
colA = paste0("daily_rank.", 2023:2024)
colB = paste0("popularity.", 2023:2024)
pop_rank_year_long <- pop_rank_per_year %>% 
  melt(., measure = list(colA, colB), value.name = c("daily_rank", "popularity"), variable.name = "year")

pop_rank_year_long[,year := ifelse(year == 1, 2023,2024)]
pop_rank_year_long
       country                                                                 name  year daily_rank popularity
        <char>                                                               <char> <num>      <num>      <num>
    1:      AE                        ""Slut!"" (Taylor's Version) (From The Vault)  2023       28.7       85.4
    2:      AE                                         (It Goes Like) Nanana - Edit  2023        NaN        NaN
    3:      AE                                                            100 Bands  2023        NaN        NaN
    4:      AE                                                                   22  2023        NaN        NaN
    5:      AE                                                               3 Days  2023        NaN        NaN
   ---                                                                                                         
59050:      ZA uKhome Lotto (feat. Agzo, Optimist Music ZA, Seun1401 & El.Stephano)  2024       42.0       55.3
59051:      ZA                        uLala Kanjani (feat. LeeMcKrazy & Skandisoul)  2024        NaN        NaN
59052:      ZA                             we can't be friends (wait for your love)  2024       33.3       91.5
59053:      ZA                                                    whatsapp (wassam)  2024       42.0        0.0
59054:      ZA                                                            yes, and?  2024       30.5       84.0
## Forma 2

pop_rank_per_year %>% 
  melt(., measure = patterns("^daily_rank.", "^popularity."), value.name = c("daily_rank", "popularity"), variable.name = "year")
       country                                                                 name   year daily_rank popularity
        <char>                                                               <char> <fctr>      <num>      <num>
    1:      AE                        ""Slut!"" (Taylor's Version) (From The Vault)      1       28.7       85.4
    2:      AE                                         (It Goes Like) Nanana - Edit      1        NaN        NaN
    3:      AE                                                            100 Bands      1        NaN        NaN
    4:      AE                                                                   22      1        NaN        NaN
    5:      AE                                                               3 Days      1        NaN        NaN
   ---                                                                                                          
59050:      ZA uKhome Lotto (feat. Agzo, Optimist Music ZA, Seun1401 & El.Stephano)      2       42.0       55.3
59051:      ZA                        uLala Kanjani (feat. LeeMcKrazy & Skandisoul)      2        NaN        NaN
59052:      ZA                             we can't be friends (wait for your love)      2       33.3       91.5
59053:      ZA                                                    whatsapp (wassam)      2       42.0        0.0
59054:      ZA                                                            yes, and?      2       30.5       84.0
# Forma 3

pop_rank_per_year %>% 
  melt(., measure.vars = measure(var=as.factor, year=as.integer, sep="."), value.name = "mean")
        country                                                                 name        var  year  mean
         <char>                                                               <char>     <fctr> <int> <num>
     1:      AE                        ""Slut!"" (Taylor's Version) (From The Vault) daily_rank  2023  28.7
     2:      AE                                         (It Goes Like) Nanana - Edit daily_rank  2023   NaN
     3:      AE                                                            100 Bands daily_rank  2023   NaN
     4:      AE                                                                   22 daily_rank  2023   NaN
     5:      AE                                                               3 Days daily_rank  2023   NaN
    ---                                                                                                    
118104:      ZA uKhome Lotto (feat. Agzo, Optimist Music ZA, Seun1401 & El.Stephano) popularity  2024  55.3
118105:      ZA                        uLala Kanjani (feat. LeeMcKrazy & Skandisoul) popularity  2024   NaN
118106:      ZA                             we can't be friends (wait for your love) popularity  2024  91.5
118107:      ZA                                                    whatsapp (wassam) popularity  2024   0.0
118108:      ZA                                                            yes, and? popularity  2024  84.0