Calcular resúmenes de datos con dplyr::summarize()

14/12/2025

dplyr básico

En el tutorial de introducción a {dplyr} aprendimos a ordenar, seleccionar, y filtrar datos tabulares. Con estas operaciones básicas deberíamos poder desenvolvernos con tablas de datos.

Luego aprendimos a crear y modificar variables con la función mutate() de {dplyr}.

Ahora veremos cómo calcular resúmenes de datos. Con esto nos referimos a tomar todas las observaciones o filas de una tabla, y aplicar algún cálculo para reducir todas las filas a un solo dato. Esto sirve, por ejemplo, para calcular la suma o el promedio de una columna, y para calcular estadísticos descriptivos.

library(dplyr)

options(scipen = 999) # desactivar notación científica

Introducción

Para este tutorial vamos a trabajar con datos de población de países de América del Sur, obtenidas desde una tabla de Wikipedia usando [web scraping](/tags/web-scraping/]. Puedes ver el código del web scraping aquí.

Para cargar los datos en tu entorno de R, ejecuta el siguiente código:

datos <- tribble(
                ~pais, ~superficie, ~poblacion,  ~idh,
             "Brasil",     8515767,   2.08e+08, 0.765,
          "Argentina",     2780400,   44500000, 0.845,
               "Perú",     1286216,   32200000, 0.777,
           "Colombia",     1141748,      5e+07, 0.767,
            "Bolivia",     1098581,   11200000, 0.718,
          "Venezuela",      916445,   31800000, 0.711,
              "Chile",      756102,   17800000, 0.851,
           "Paraguay",      406752,    7100000, 0.728,
            "Ecuador",      256370,   16900000, 0.759,
             "Guyana",      214970,      8e+05, 0.682,
            "Uruguay",      176215,    3500000, 0.817,
            "Surinam",      163820,      5e+05, 0.738,
   "Guayana Francesa",       83846,      3e+05, 0.901,
  "Trinidad y Tobago",        5128,    1300000, 0.796
  )

Como hemos visto en el tutorial introductorio de R, para calcular una suma usamos la función sum():

total <- sum(datos$poblacion)

format(total, big.mark = ".", scientific = FALSE)
[1] "425.900.000"

Mientras que para calcular un promedio usamos la función mean():

promedio <- mean(datos$idh)

round(promedio, 2)
[1] 0.78

Cualquier función como las anteriores, que reciba varios datos y entregue uno solo, será una función que podemos usar dentro de summarize() para obtener resúmenes de datos.

Resumir datos con summarize()

La función summarize() calcula resúmenes de las tablas de datos, a partir de una o varias funciones que van a resumir los datos a una sola fila.

Esquema de un resumen de datos: se pasa de varias filas a una sola

Para calcular el resumen de los valores de una variable, dentro de summarize() ubicamos la función necesaria, aplicada a la columna que nos interesa resumir.

Calculemos la suma (sum()) de la columna poblacion:

datos |> 
  summarize(
    suma = sum(poblacion)
  )
# A tibble: 1 × 1
       suma
      <dbl>
1 425900000

Redujimos las 14 filas de nuestra tabla de datos y obtuvimos una sola fila, que resume todos los valores de la poblacion a partir de una suma.

Dentro de summarize() podemos calcular varios resúmenes al mismo tiempo.

Agreguemos una segunda línea para calcular el promedio del índice de desarrollo humano (idh):

datos |> 
  summarize(
    suma = sum(poblacion),
    promedio = mean(idh)
  )
# A tibble: 1 × 2
       suma promedio
      <dbl>    <dbl>
1 425900000    0.775

Estadísticos descriptivos

De este modo podemos calcular datos que resumen las observaciones, por ejemplo, calcular estadísticas descriptivos relevantes a los datos que estamos trabajando:

datos |> 
  # calcular estadísticos descriptivos
  summarize(
    poblacion_total = sum(poblacion),
    poblacion_promedio = mean(poblacion),
    poblacion_minima = min(poblacion),
    poblacion_maxima = max(poblacion)
  ) |> 
  # agregar puntos de miles
  mutate(
    across(
      where(is.numeric), ~format(.x, big.mark = ".")
    )
  )
# A tibble: 1 × 4
  poblacion_total poblacion_promedio poblacion_minima poblacion_maxima
  <chr>           <chr>              <chr>            <chr>           
1 425.900.000     30.421.429         300.000          208.000.000     

Resúmenes por grupos

Tal que como vimos con mutate(), podemos anteponer la función de agrupación group_by() para que los resúmenes de datos se calculen por grupos. Esto significa que, en vez de obtener una sola fila de resumen, obtendremos una fila por cada grupo de la variable que elijamos para agrupar los datos.

Primero creemos una variable que nos permita agrupar los datos:

datos_2 <- datos |>
  # crear grupos por índice de desarrollo humano
  mutate(grupo = case_when(poblacion >= 20000000 ~ "Alta",
                           poblacion >= 5000000 ~ "Media",
                           poblacion <  5000000 ~ "Baja")) |> 
  # ordenar factor
  mutate(grupo = factor(grupo, 
                        levels = c("Baja", "Media", "Alta")))

datos_2 |> 
  count(grupo)
# A tibble: 3 × 2
  grupo     n
  <fct> <int>
1 Baja      5
2 Media     4
3 Alta      5

Ahora, usando group_by(), podemos calcular los resúmenes por cada grupo de población:

datos_2 |> 
  group_by(grupo) |> 
  summarize(
    poblacion_total = sum(poblacion),
    poblacion_promedio = mean(poblacion),
    idh_promedio = mean(idh),
    idh_maximo = max(idh)
  )
# A tibble: 3 × 5
  grupo poblacion_total poblacion_promedio idh_promedio idh_maximo
  <fct>           <dbl>              <dbl>        <dbl>      <dbl>
1 Baja          6400000            1280000        0.787      0.901
2 Media        53000000           13250000        0.764      0.851
3 Alta        366500000           73300000        0.773      0.845

El uso de group_by() es muy conveniente, porque podemos tener un mismo código para calcular resúmenes estadísticos, y con tan solo cambiar la variable de agrupación obtendremos resultados actualizados.

Resúmenes de varias variables con across()

En lugar de tener que estar especificando las columnas que queremos resumir, podemos calcular un resumen para varias columnas al mismo tiempo. Igual que con mutate(), esto lo logramos usando across() dentro de summarize(), que permite aplicar las operaciones a varias columnas a la vez.

Por ejemplo, para calcular un resumen de todas las columnas numéricas, indicamos dentro de across() que queremos aplicar la operación donde (where()) las variables sean numéricas (is.numeric):

datos_2 |> 
  summarize(             # resumir los datos
    across(              # donde las columnas
      where(is.numeric), # sean numéricas
      ~mean(.x)          # calculando el promedio
    )
  )
# A tibble: 1 × 3
  superficie poblacion   idh
       <dbl>     <dbl> <dbl>
1   1271597. 30421429. 0.775

Para controlar el nombre que tendrán las columnas resultantes se puede usar el argumento .names:

datos_2 |> 
  summarise(
    across(where(is.numeric), 
           ~mean(.x), 
           .names = "resumen_{.col}_promedio" # cambiar el nombre de columnas
    )
  )
# A tibble: 1 × 3
  resumen_superficie_promedio resumen_poblacion_promedio resumen_idh_promedio
                        <dbl>                      <dbl>                <dbl>
1                    1271597.                  30421429.                0.775

O bien, se pueden poner las funciones de resumen dentro de una lista, donde puedes entregarle el nombre que tendrá el resultado:

datos_2 |> 
  summarise(
    across(where(is.numeric), 
           list(
             "promedio" = ~mean(.x)
           )
    )
  )
# A tibble: 1 × 3
  superficie_promedio poblacion_promedio idh_promedio
                <dbl>              <dbl>        <dbl>
1            1271597.          30421429.        0.775

Múltiples resúmenes a la vez

También es posible calcular resúmenes usando más de una función, por ejemplo para calcular los promedios y las sumas al mismo tiempo, entregando las funciones dentro de una lista:

datos_2 |> 
  summarise(
    across(where(is.numeric), 
           list(
             "promedio" = ~mean(.x), 
             "suma" = ~sum(.x)
           )
    )
  ) |> 
  glimpse()
Rows: 1
Columns: 6
$ superficie_promedio <dbl> 1271597
$ superficie_suma     <dbl> 17802360
$ poblacion_promedio  <dbl> 30421429
$ poblacion_suma      <dbl> 425900000
$ idh_promedio        <dbl> 0.7753571
$ idh_suma            <dbl> 10.855

O bien, podemos aprovechar across() para reducir el código que escribimos en combinación con resúmenes individuales:

datos_2 |> 
  summarize(
    "idh_prom" = mean(idh),
    across(c(superficie, poblacion), 
           list("suma" = ~sum(.x))
    )
  )
# A tibble: 1 × 3
  idh_prom superficie_suma poblacion_suma
     <dbl>           <dbl>          <dbl>
1    0.775        17802360      425900000

Obviamente podemos combinar lo anterior con la agrupación para obtener un completo resumen de datos de la tabla:

datos_2 |> 
  group_by(grupo) |>
  summarise(
    across(where(is.numeric), 
           list(
             "promedio" = ~mean(.x), 
             "suma" = ~sum(.x)
           )
    )
  )
# A tibble: 3 × 7
  grupo superficie_promedio superficie_suma poblacion_promedio poblacion_suma
  <fct>               <dbl>           <dbl>              <dbl>          <dbl>
1 Baja              128796.          643979            1280000        6400000
2 Media             629451.         2517805           13250000       53000000
3 Alta             2928115.        14640576           73300000      366500000
# ℹ 2 more variables: idh_promedio <dbl>, idh_suma <dbl>