¿Cómo crear una tabla dinámica en Excel y en R?

Author

Cousteau Consultant Group

Published

January 17, 2024

Explora nuestros posts y nuestros cursos

Recuerda que tenemos diversos posts y dictamos cursos de programación, pesquerías, ecología, entre otros. Te invitamos a revisar la lista completa de nuestros posts en nuestra sección Posts y suscribirte a nuestras redes en Facebook y X para enterarte de nuestros cursos y de sus aperturas próximas.

En Excel

  • Para este artículo, utilizaremos como ejemplo el archivo mtcars.xlsx
Archivos de ejemplo

Los archivos utilizados en los artículos de Posts se encuentran alojados en nuestro repositorio de Github: https://github.com/CousteauG/posts-data.git.

  • El primer paso será seleccionar toda las celdas con las que deseamos trabajar, luego buscar el botón de Tabla Dinámica (Pivot Table) en la pestaña Insertar:

  • Se abrirá una ventana que nos pedirá confirmación de la selección de celdas y si deseamos mostrar los resultados en una nueva hoja. Dejaremos todo como nos lo sugiere y solo daremos click en Aceptar:

  • A continuación, se abrirá una nueva hoja con una barra lateral a la derecha que nos permitirá seleccionar las columnas con las que deseamos realiza nuestro análisis.

  • Para nuestro primer ejemplo, solicitaremos que nos calcule el promedio para las variables mpg y wt, utilizando los valores de am y gear como variables de agrupación. Para ello, tendremos que arrastrar dichas variables a los campos de Valores y Filas, respectivamente.

  • Posteriormente, tendremos que hacer click en cada una de las variables en la sección de Valores y seleccionar la opción Configuración del campo de valor (Value Field Settings)

  • Se abrirá una pequeña ventana mostrándonos todos los estadísticos disponibles. Seleccionaremos la opción de Promedio (Average) y daremos click en Aceptar. Repetiremos esto para la otra variable.

  • Y así, después de muchos clicks, tenemos nuestra primera tabla dinámica:

  • Luego, utilizando las opciones en la pestaña de Diseño, podemos ocultar los subtotales.

En R

Veremos ahora cómo replicar el ejemplo anterior en R a través de dos enfoques:

Utilizando funciones de R base

mtcars es un objeto que viene precargado en R, por lo que no será necesario cargarlo desde Excel. Sin embargo, puedes encontrar los detalles de cómo leer archivos de Excel en R en nuestro artículo ¿Cómo cargar (leer) una tabla de Excel en R?.

# Mostrar el número de filas y columnas (en ese orden) de mtcars
dim(mtcars)
[1] 32 11
# Mostrar las primeras 10 filas de mtcars
head(mtcars, 10)
                   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4         21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag     21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710        22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive    21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Valiant           18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Duster 360        14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Merc 240D         24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Merc 230          22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Merc 280          19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4

Utilizaremos la función aggregate, cuya sintaxis indica que el primer argumento deberá contener la tabla con los valores que deseamos reorganizar (en nuestro caso, un subset de mtcars indicando únicamente las columnas mpg y wt). Luego, en el argumento by indicaremos a modo de lista las variables que nos servirán como agrupadoras (en nuestro ejemplo am y gear). Finalmente, con el argumento FUNle indicaremos qué estadístico deseamos aplicar sobre los valores agrupados (en nuestro caso mean, que calcula el promedio de valores numéricos).

aggregate(x = mtcars[,c("mpg", "wt")], 
          by = list(mtcars$am, mtcars$gear), 
          FUN = mean)
  Group.1 Group.2      mpg     wt
1       0       3 16.10667 3.8926
2       0       4 21.05000 3.3050
3       1       4 26.27500 2.2725
4       1       5 21.38000 2.6326

¡Y eso es todo! Podemos verificar que hemos obtenido los mismos valores que con el análisis en Excel. Es posible modificar los nombres de columnas de las variables agrupadoras a través del nombre dado en la lista usada para el argumento by de la siguiente manera:

aggregate(x = mtcars[,c("mpg", "wt")], 
          by = list(am = mtcars$am, 
                    gear = mtcars$gear), 
          FUN = mean)
  am gear      mpg     wt
1  0    3 16.10667 3.8926
2  0    4 21.05000 3.3050
3  1    4 26.27500 2.2725
4  1    5 21.38000 2.6326

Así mismo, desde R podemos ejecutar una amplia variedad de funciones, algunas de ellas no están disponibles en la ventana que nos abre Excel. Por ejemplo, la mediana:

aggregate(x = mtcars[,c("mpg", "wt")], 
          by = list(am = mtcars$am, 
                    gear = mtcars$gear), 
          FUN = median)
  am gear   mpg    wt
1  0    3 15.50 3.730
2  0    4 21.00 3.315
3  1    4 25.05 2.260
4  1    5 19.70 2.770

O el rango:

aggregate(x = mtcars[,c("mpg", "wt")], 
          by = list(am = mtcars$am, 
                    gear = mtcars$gear), 
          FUN = range)
  am gear mpg.1 mpg.2  wt.1  wt.2
1  0    3  10.4  21.5 2.465 5.424
2  0    4  17.8  24.4 3.150 3.440
3  1    4  21.0  33.9 1.615 2.875
4  1    5  15.0  30.4 1.513 3.570

Utilizando funciones del entorno tidyverse

El entorno de tidyverse (que involucra un conjunto de paquetes y herramientas orientadas al manejo optimizado de tablas de datos) se ha hecho muy popular en los últimos años, por lo que es importante mostrar qué nos ofrece respecto a Tablas dinámicas.

Dentro del paquete dplyr, utilizaremos las funciones group_by y summarise:

require(dplyr)

mtcars |> 
  
  # Definir las variables de agrupación separadas por comas
  group_by(am, gear) |> 
  
  # Ejecutar las operaciones para cada variable
  summarise(mpg = mean(mpg),
            wt = mean(wt), 
            .groups = "drop") # .groups cierra la orden de agrupación
# A tibble: 4 × 4
     am  gear   mpg    wt
  <dbl> <dbl> <dbl> <dbl>
1     0     3  16.1  3.89
2     0     4  21.0  3.30
3     1     4  26.3  2.27
4     1     5  21.4  2.63
¿Qué significan los comandos |> y %>%?

Dentro de nuestro artículo ¿Cómo eliminar filas con datos duplicados?, puedes revisar la nota referida a este punto titulada: ¿Qué significan los comandos |> y %>%?

Observamos que los resultados son los mismos que los obtenidos con Excel y con aggregate. Sin embargo, ¿cómo aplicar una misma función a lo largo de todo un conjunto de variables? Existen varios modos, uno de ellos es añadiendo la función across.

require(dplyr)

mtcars |> 
  
  # Definir las variables de agrupación separadas por comas
  group_by(am, gear) |> 
  
  # Ejecutar las operaciones para cada variable
  summarise(across(.cols = c(mpg, wt), 
                   .fns = mean), 
            .groups = "drop") 
# A tibble: 4 × 4
     am  gear   mpg    wt
  <dbl> <dbl> <dbl> <dbl>
1     0     3  16.1  3.89
2     0     4  21.0  3.30
3     1     4  26.3  2.27
4     1     5  21.4  2.63

¿Por qué se muestran menos valores decimales al utilizar summarise?

A primera impresión, podría parecer que el proceso ha quitado decimales a nuestro cálculo; sin embargo, esto es solo la manera en cómo un objeto de clase tbl_df/tbl se muestra en consola. Por ejemplo, digamos que creamos un data frame de la siguiente manera:

df_ejemplo <- data.frame(a = c(15.1234567, 2.7654321, -5.9876543),
                         b = c("A", "B", "C"))

df_ejemplo
          a b
1 15.123457 A
2  2.765432 B
3 -5.987654 C

Podemos observar que el método print aplicado a un objeto de clase data.frame muestra todos los valores decimales. No obstante, al convertirlo a un objeto de clase tbl_df/tbl, el print en consola solo mostrará un pequeño número de decimales, pero esto se hará SIN modificar nuestra tabla original. En otras palabras, el método print de un objeto tbl_df/tbl hará un redondeo de los valores con decimales UNICAMENTE al momento de mostrar la tabla en consola.

tbl_ejemplo <- as_tibble(df_ejemplo)

class(tbl_ejemplo)
[1] "tbl_df"     "tbl"        "data.frame"
tbl_ejemplo
# A tibble: 3 × 2
      a b    
  <dbl> <chr>
1 15.1  A    
2  2.77 B    
3 -5.99 C    

Podemos verificar de dos maneras que los valores se mantienen:

  • A través de la función all.equal que solamente devuelve TRUE cuando los dos objetos ingresados son exactamente iguales.
all.equal(target = df_ejemplo$a, current = tbl_ejemplo$a)
[1] TRUE
  • Realizando una diferencia entre las columnas de ambas tablas y observando que todos los valores son iguales a cero.
df_ejemplo$a - tbl_ejemplo$a
[1] 0 0 0

En este último ejemplo, vemos que a través del argumento .cols de across definimos las variables con los valores que ingresarán al cálculo, mientras que con .fns definimos la función (o funciones) que deseamos ejecutar. Y sí, podemos solicitar más de una función en un mismo comando:

require(dplyr)

mtcars |> 
  
  # Definir las variables de agrupación separadas por comas
  group_by(am, gear) |> 
  
  # Ejecutar las operaciones para cada variable
  summarise(across(.cols = c(mpg, wt), 
                   .fns = list(promedio = mean, mediana = median)), 
            .groups = "drop") 
# A tibble: 4 × 6
     am  gear mpg_promedio mpg_mediana wt_promedio wt_mediana
  <dbl> <dbl>        <dbl>       <dbl>       <dbl>      <dbl>
1     0     3         16.1        15.5        3.89       3.73
2     0     4         21.0        21          3.30       3.32
3     1     4         26.3        25.0        2.27       2.26
4     1     5         21.4        19.7        2.63       2.77