Tuneando tablas

¿De qué se trata todo esto?

¿Qué pretendo con este documento?

El objetivo de este documento es mostrar cómo se pueden armar tablas que resuman ciertos datos de interes con el paquete “dplyr”, y ponerlas bonitas con el paquete “DT”.

Para ejemplificar un poco lo que se quiere mostrar, se va autilizar el dataset “movies” que surge del paquete “ggplot2movies”. Dicho dataset muestra un listado de películas desde 1893, calificadas y clasificadas de acuerdo a su contenido.

Empecemos!

Levanto los datos, abro librerías y chusmeo qué contiene el dataset


Llamando a la función “datatable” del paquete “DT” ya logramos visualizar una tabla mucho más bonita que simplemente mostrando el resultado del head.
#install.packages("ggplot2movies")

data(movies,package="ggplot2movies")

movies <- as.data.frame(movies)

library(dplyr)
library(DT)

Solo el head:

head(movies)
##                      title year length budget rating votes   r1   r2  r3   r4
## 1                        $ 1971    121     NA    6.4   348  4.5  4.5 4.5  4.5
## 2        $1000 a Touchdown 1939     71     NA    6.0    20  0.0 14.5 4.5 24.5
## 3   $21 a Day Once a Month 1941      7     NA    8.2     5  0.0  0.0 0.0  0.0
## 4                  $40,000 1996     70     NA    8.2     6 14.5  0.0 0.0  0.0
## 5 $50,000 Climax Show, The 1975     71     NA    3.4    17 24.5  4.5 0.0 14.5
## 6                    $pent 2000     91     NA    4.3    45  4.5  4.5 4.5 14.5
##     r5   r6   r7   r8   r9  r10 mpaa Action Animation Comedy Drama Documentary
## 1 14.5 24.5 24.5 14.5  4.5  4.5           0         0      1     1           0
## 2 14.5 14.5 14.5  4.5  4.5 14.5           0         0      1     0           0
## 3  0.0 24.5  0.0 44.5 24.5 24.5           0         1      0     0           0
## 4  0.0  0.0  0.0  0.0 34.5 45.5           0         0      1     0           0
## 5 14.5  4.5  0.0  0.0  0.0 24.5           0         0      0     0           0
## 6 14.5 14.5  4.5  4.5 14.5 14.5           0         0      0     1           0
##   Romance Short
## 1       0     0
## 2       0     0
## 3       0     1
## 4       0     0
## 5       0     0
## 6       0     0


Con datatable:

head(movies) %>% datatable()


Con datatable, sacando el buscador y el conteo de páginas:

head(movies) %>% 
  datatable(rownames = FALSE,
            options = list(paging=FALSE,
                         searching=FALSE))

Tablas resumen

Tablas resumenes básicas

Distribución


Algo básico que solemos hacer cuando queremos resumir el contenido de un dataset es analizar la distribución de los datos.

Para simplificar la visualización vamos a analizar las películas de los últimos 10 años ingresados en el dataset (1996 a 2005), y veremos cómo se distribuye la cantidad de películas por año.
# Primero armo la tabla resumen

movies %>% 
  # Filtro y me quedo con los años que me interesan
  filter(year %in% c(1996:2005)) %>% 
  # Agrupo por anio
  group_by(year) %>%  
  # Armo la agregación
  summarise(Cant_Peliculas = n(), 
            Pct_Peliculas = n()) %>% 
  # Recalculo la columna de porcentaje
  mutate(Pct_Peliculas = Pct_Peliculas/sum(Cant_Peliculas))-> Resumen_1


# Ahora uso el paquete DT para ponerla bonita

Resumen_1 %>%
  
  # Saco el buscador y el contador de páginas
  datatable(rownames = FALSE,
          options = list(paging=FALSE,
                         searching=FALSE)) %>%
  
  # Le pongo separador de miles a la columna de cantidad
  formatRound(c("Cant_Peliculas"),0) %>%
  
  # Le pongo formato de porcentaje a la columna de porcentaje
  formatPercentage(c("Pct_Peliculas"),2) %>% 
  
  # Le agrego barras a la columna de porcentaje
  formatStyle("Pct_Peliculas", 
              
              # Acá aclaro el mínimo y máximo valor para el alto de las barras
              background = styleColorBar(c(0,
                                           max(Resumen_1$Pct_Peliculas)), 'lightblue'),
              
              # Acá indico el ancho de la barra y qué tanto cubre de la celda
              backgroundSize = '100% 100%', 
              backgroundRepeat = 'no-repeat')

Otras medidas


Nos puede interesar también conocer el mínimo, primer cuartil, mediana, promedio, tercer cuartil, y máximo puntaje por año.

En este caso quizás nos interese visualizar la tabla de otra manera. Una buena forma de apreciar rápidamente si hay una tendencia en los puntajes promedio es darle formato con colores, poniendo cierto color en los promedios más bajos y cierto color en los promedios más altos.

Vamos a poner rojo en los puntajes más bajos, y verde en los más alto. A ver qué sale ;)
# Primero armo la tabla resumen

movies %>% 
  # Filtro y me quedo con los años que me interesan
  filter(year %in% c(1996:2005)) %>% 
  # Agrupo por anio
  group_by(year) %>%  
  # Armo la agregación
  summarise(Min = min(rating), 
            Q1 = quantile(rating,0.25),
            Mediana = median(rating),
            Promedio = mean(rating),
            Q3 = quantile(rating,0.75),
            Max = max(rating))-> Resumen_2


# Primero tengo que definir algunos parámetros para colorear la columna de interes

# Defino los cortes que van a hacer que cambie de color
brks <- quantile(c(Resumen_2$Promedio,Resumen_2$Promedio), 
                 probs = seq(0, 1, .05), na.rm = TRUE)

# Defino los colores que voy a usar
colfunc <- colorRampPalette(c("#f8696b","#ffdb81","#63be7b"))
clrs <- colfunc(length(brks) + 1)

# Luego uso el paquete DT para poner bonita la tabla 

Resumen_2 %>%
  
  # Saco el buscador y el contador de páginas
  datatable(rownames = FALSE,
          options = list(paging=FALSE,
                         searching=FALSE)) %>%
  
  # Redondeo la columnas
  formatRound(c("Min",
                "Q1",
                "Mediana",
                "Promedio",
                "Q3",
                "Max"),2) %>%
  
  # Le agrego colores a la columna promedio
  formatStyle(c("Promedio"), 
              backgroundColor = styleInterval(brks, clrs))

Quizás simplemente nos interese marcar el máximo y mínimo puntaje promedio. Vamos a hacerlo!

# Primero tengo que definir algunos parámetros para colorear la columna de interes

# Calculo el máximo y mínimo promedio 

max_prom <- round(max(Resumen_2$Promedio),2)
min_prom <- round(min(Resumen_2$Promedio),2)

# Redondeo la columna de promedio para encontrar esos valores 

Resumen_2$Promedio <- round(Resumen_2$Promedio,2)

# Luego uso el paquete DT para poner bonita la tabla 

Resumen_2 %>%
  
  # Saco el buscador y el contador de páginas
  datatable(rownames = FALSE,
          options = list(paging=FALSE,
                         searching=FALSE)) %>%
  
  # Le agrego colores a la columna promedio
  formatStyle('Promedio',
              target = 'row',
              # Pinto las filas cuya celda cuenta con cierto valor
              backgroundColor = styleEqual(c(min_prom,max_prom), 
                                           c('#A3E4FE','#FFAEE8')),
              # Pongo en negrita las filas cuya celda cuenta con cierto valor
              fontWeight = styleEqual(c(min_prom,max_prom), c("bold","bold")),
              # Pinto el texto de las filas cuya celda cuenta con cierto valor
              color = styleEqual(c(min_prom,max_prom), c("#0088E0","#E000A0"))) %>%
  
  # Redondeo la columnas
  formatRound(c("Min",
                "Q1",
                "Mediana",
                "Q3",
                "Max"),2)

Y si quiero marcar los años que obtuvieron un puntaje mínimo arriba de 1, en vez de pintar las celdas con valor exacto voy a pintar las celdas que cumplen con una condición de intervalo.


Resumen_2 %>%
  
  # Saco el buscador y el contador de páginas
  datatable(rownames = FALSE,
          options = list(paging=FALSE,
                         searching=FALSE)) %>%
  
  # Le agrego colores a la columna promedio
  formatStyle('Min',
              
              # Pinto las celdas que toman valor hasta "1" de un color, y mayor a "1" de otro color
              backgroundColor = styleInterval(1,
                                              c('#FDD2CF','#D0FDCF')),
              color = styleInterval(1,
                                    c('#C80D00','#04D300'))) %>%
  
  # Redondeo la columnas
  formatRound(c("Min",
                "Q1",
                "Mediana",
                "Q3",
                "Max"),2)

Tablas cruzadas

Tablas cruzadas

Primera propuesta


Otro tipo de tablas que suelen interesar para visualizar datos son las tablas cruzadas, en donde las filas indican cierta característca, las columnas otra característica, y en el medio contamoms con alguna medida de agregación.

Para ejemplificar esto vamos a analizar el puntaje promedio por año y tipo de película. Se va a pintar en rojo más intenso los puntajes promedio más altos, y en blanco los puntajes promedio más bajos.
# Primero armo la tabla resumen

movies %>% 
  # Filtro y me quedo con los años que me interesan
  filter(year %in% c(1996:2005)) %>%
  # Armo la variable "Tipo_peli"
  mutate(Tipo_peli = case_when(Action==1~"Accion",
                               Animation==1~"Animadas",
                               Comedy==1~"Comedia",
                               Drama==1~"Drama",
                               Documentary==1~"Documental",
                               Romance==1~"Romance",
                               Short==1~"Corto",
                               TRUE~"Otro")) %>%
  # Agrupo por anio y tipo_peli
  group_by(year,Tipo_peli) %>%  
  # Armo la agregación
  summarise(Puntaje_Prom = mean(rating))-> Resumen_3


# Paso la tabla a tipo cruzada

library(tidyverse)

Resumen_3 %>% 
  spread(Tipo_peli, Puntaje_Prom)->Resumen_3_bis

# Defino los colores que quiero poner en la tabla 

brks <- quantile(Resumen_3_bis[,2:ncol(Resumen_3_bis)], probs = seq(0, 1, .05), na.rm = TRUE)
clrs <- round(seq(255, 40, length.out = length(brks) + 1), 0) %>%
  {paste0("rgb(255,", ., ",", ., ")")}

# Ahora uso el paquete DT para ponerla bonita

Resumen_3_bis %>%
  
  # Saco el buscador y el contador de páginas
  datatable(rownames = FALSE,
          options = list(paging=FALSE,
                         searching=FALSE)) %>%
  
  formatStyle(names(Resumen_3_bis)[2:ncol(Resumen_3_bis)], 
              backgroundColor = styleInterval(brks, clrs)) %>% 
  formatRound(names(Resumen_3_bis)[2:ncol(Resumen_3_bis)],2)

Y si le ponemos más onda?


También se puede agregar combinaciones de celdas para que la tabla sea más entendible.

# Defino la estructura que quiero poner

sketch = htmltools::withTags(table(
  class = 'display',
  
  # Acá pongo el título que combina todas las columnas arriba
  thead(
    tr(
      th(colspan = ncol(Resumen_3_bis), 
         'Puntajes promedio por año y tipo de película')
    ),
    
    # Acá defino el nombre de la variable de filas y el de columnas y la cantidad de celdas que quiero combinar
    tr(
      th(rowspan = 2, 'Año'),
      th(colspan = (ncol(Resumen_3_bis)-1), 'Tipo de película')
    ),
    tr(
      lapply(colnames(Resumen_3_bis)[2:ncol(Resumen_3_bis)], th)
    )
  )
))

# Uso el paquete DT para tunear la tabla

Resumen_3_bis %>%
  
  # Saco el buscador y el contador de páginas
  datatable(rownames = FALSE,
            # Arego esta sentencia para que se muestre el formato definido arriba
            container = sketch,
          options = list(paging=FALSE,
                         searching=FALSE)) %>%
  
  formatStyle(names(Resumen_3_bis)[2:ncol(Resumen_3_bis)], 
              backgroundColor = styleInterval(brks, clrs)) %>% 
  formatRound(names(Resumen_3_bis)[2:ncol(Resumen_3_bis)],2)