El paquete {dplyr} provee una enorme cantidad de funciones útiles para manipular y analizar datos de manera intuitiva y expresiva.
El espíritu detrás de {dplyr} es que la enorme mayoría de los análisis, por más complicados que sean, involucran combinar y encadenar una serie relativamente acotada de acciones (o verbos). En este curso vamos a centrarnos las cinco más comunes:
select()
: selecciona columnas de una tabla.filter()
: selecciona (o filtra) filas de una tabla a partir de una o más condiciones lógicas.group_by()
: agrupa una tabla en base al valor de una o más columnas.mutate()
: agrega nuevas columnas a una tabla.summarise()
: calcula estadísticas para cada grupo de una tabla.dplyr y tablas dinámicas:
A grosso modo, las operaciones de {dplyr} permiten hacer en R lo que se hace en tablas dinámicas (pivot tables) en Excel. filter()
vendría a ser como la sección de “Filtros”, group_by()
, la sección de “Filas”, select()
, la sección de “Columnas” y summarise()
, la parte de “Valores”.
Primer desafío:
Te dieron una tabla con datos de temperatura mínima y máxima para distintas estaciones meteorológicas de todo el país durante los 365 días de un año. Las columnas son: id_estacion
, temperatura_maxima
, temperatura_minima
y provincia
. En base a esos datos, te piden que computen la temperatura media anual de cada estación únicamente de las estaciones de La Pampa.
¿En qué orden ejecutarías estos pasos para obtener el resultado deseado?
summarise()
para calcular la estadística mean(temperatura_media)
para cada id_estacion
group_by()
para agrupar por la columna id_estacion
mutate()
para agregar una columna llamada temperatura_media
que sea (temperatura_minima + temperatura_maxima)/2
.filter()
para seleccionar solo las filas donde la columnas provincia
es igual a “La Pampa”Para usar {dplyr} primero hay que instalarlo (esto hay que hacerlo una sola vez) con el comando:
y luego cargarlo en memoria con
## Warning: replacing previous import 'vctrs::data_frame' by 'tibble::data_frame'
## when loading 'dplyr'
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
Volvé a cargar los datos de países (para un recordatorio, podés ir a Lectura de datos ordenados):
## Parsed with column specification:
## cols(
## pais = col_character(),
## continente = col_character(),
## anio = col_double(),
## esperanza_de_vida = col_double(),
## poblacion = col_double(),
## pib_per_capita = col_double()
## )
select()
Para quedarse únicamente con las columnas de año, país y PBI per cápita, usá select()
## # A tibble: 1,704 x 3
## anio pais pib_per_capita
## <dbl> <chr> <dbl>
## 1 1952 Afganistán 779.
## 2 1957 Afganistán 821.
## 3 1962 Afganistán 853.
## 4 1967 Afganistán 836.
## 5 1972 Afganistán 740.
## 6 1977 Afganistán 786.
## 7 1982 Afganistán 978.
## 8 1987 Afganistán 852.
## 9 1992 Afganistán 649.
## 10 1997 Afganistán 635.
## # … with 1,694 more rows
¿Dónde quedó este resultado? Si te fijás en la variable paises
, ésta está intacta:
## # A tibble: 1,704 x 6
## pais continente anio esperanza_de_vida poblacion pib_per_capita
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Afganistán Asia 1952 28.8 8425333 779.
## 2 Afganistán Asia 1957 30.3 9240934 821.
## 3 Afganistán Asia 1962 32.0 10267083 853.
## 4 Afganistán Asia 1967 34.0 11537966 836.
## 5 Afganistán Asia 1972 36.1 13079460 740.
## 6 Afganistán Asia 1977 38.4 14880372 786.
## 7 Afganistán Asia 1982 39.9 12881816 978.
## 8 Afganistán Asia 1987 40.8 13867957 852.
## 9 Afganistán Asia 1992 41.7 16317921 649.
## 10 Afganistán Asia 1997 41.8 22227415 635.
## # … with 1,694 more rows
select()
y el resto de las funciones de {dplyr} siempre generan una nueva tabla y nunca modifican la tabla original. Para guardar la tabla con las tres columnas anio
, pais
y pbi_per_capita
tenés que asignar el resultado a una nueva variable.
## # A tibble: 1,704 x 3
## anio pais pib_per_capita
## <dbl> <chr> <dbl>
## 1 1952 Afganistán 779.
## 2 1957 Afganistán 821.
## 3 1962 Afganistán 853.
## 4 1967 Afganistán 836.
## 5 1972 Afganistán 740.
## 6 1977 Afganistán 786.
## 7 1982 Afganistán 978.
## 8 1987 Afganistán 852.
## 9 1992 Afganistán 649.
## 10 1997 Afganistán 635.
## # … with 1,694 more rows
filter()
Ahora podés usar filter()
para quedarte con sólo unas filas. Por ejemplo, para ver los datos de Argentina:
## # A tibble: 12 x 3
## anio pais pib_per_capita
## <dbl> <chr> <dbl>
## 1 1952 Argentina 5911.
## 2 1957 Argentina 6857.
## 3 1962 Argentina 7133.
## 4 1967 Argentina 8053.
## 5 1972 Argentina 9443.
## 6 1977 Argentina 10079.
## 7 1982 Argentina 8998.
## 8 1987 Argentina 9140.
## 9 1992 Argentina 9308.
## 10 1997 Argentina 10967.
## 11 2002 Argentina 8798.
## 12 2007 Argentina 12779.
La mayoría de los análisis consisten en varios pasos (en el primer desafío usaste 4 pasos para calcular las temperaturas medias de una serie de estaciones). La única tabla que te interesa es la última, por lo que ir asignando variables nuevas en cada paso intermedio es tedioso y poco práctico. Para eso se usa el operador ‘pipe’ (%>%
).
El operador ‘pipe’ (%>%
) agarra el resultado de una función y se lo pasa a la siguiente. Esto permite escribir el código como una cadena de funciones que van operando sobre el resultado de la anterior.
Las dos operaciones anteriores (seleccionar tres columnas y luego filtrar las filas correspondientes a Argentina) se pueden escribir uno después del otro y sin asignar los resultados intermedios a nuevas variables de esta forma:
## # A tibble: 12 x 3
## anio pais pib_per_capita
## <dbl> <chr> <dbl>
## 1 1952 Argentina 5911.
## 2 1957 Argentina 6857.
## 3 1962 Argentina 7133.
## 4 1967 Argentina 8053.
## 5 1972 Argentina 9443.
## 6 1977 Argentina 10079.
## 7 1982 Argentina 8998.
## 8 1987 Argentina 9140.
## 9 1992 Argentina 9308.
## 10 1997 Argentina 10967.
## 11 2002 Argentina 8798.
## 12 2007 Argentina 12779.
La forma de “leer” esto es “Tomá la variable paises
, después aplicale select(anio, pais, pib_per_capita)
, después aplicale filter(pais == "Argentina")
”.
Cómo vimos, el primero argumento de todas las funciones de dplyr espera un data.frame y justamente el operador %>%
toma el data.frame paises
y se lo pasa al primer argumento de select()
. Luego el data.frame resultante de seleccionar las columnas anio, país y pib_per_capita pasa como el primer argumento de la función filter()
gracias al %>%
.
Tip:
En RStudio podés escribir %>%
usando el atajo de teclado Ctr + Shift + M. ¡Probalo!
group_by() %>% summarise()
Si querés calcular la expectativa de vida media para cada continente, tenés que usar el combo group_by() %>% summarise()
. Es decir, primero agrupar la tabla según la columna continente y luego calcular un promedio para cada grupo.
Para agrupar la tabla países según el continente usamos el siguiente código:
## # A tibble: 1,704 x 6
## # Groups: continente [5]
## pais continente anio esperanza_de_vida poblacion pib_per_capita
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Afganistán Asia 1952 28.8 8425333 779.
## 2 Afganistán Asia 1957 30.3 9240934 821.
## 3 Afganistán Asia 1962 32.0 10267083 853.
## 4 Afganistán Asia 1967 34.0 11537966 836.
## 5 Afganistán Asia 1972 36.1 13079460 740.
## 6 Afganistán Asia 1977 38.4 14880372 786.
## 7 Afganistán Asia 1982 39.9 12881816 978.
## 8 Afganistán Asia 1987 40.8 13867957 852.
## 9 Afganistán Asia 1992 41.7 16317921 649.
## 10 Afganistán Asia 1997 41.8 22227415 635.
## # … with 1,694 more rows
A primera vista parecería que la función no hizo nada, pero fijate que el resultado ahora dice que tiene grupos (“Groups:”), y nos dice qué columna es la que agrupa los datos (“continente”) y cuántos grupos hay (“5”). Las operaciones subsiguientes que le hagamos a esta tabla van a hacerse para cada grupo.
Para ver esto en acción, usá summarise()
para computar el promedio de la esperanza de vida:
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 5 x 2
## continente esperanza_de_vida_media
## <chr> <dbl>
## 1 África 48.9
## 2 Américas 64.7
## 3 Asia 60.1
## 4 Europa 71.9
## 5 Oceanía 74.3
¡Tadá! summarise()
devuelve una tabla con una columna para el continente y otra nueva, llamada “esperanza_de_vida_media” que contiene el promedio de esperanza_de_vida
para cada grupo. Esta operación es equivalente a esta tabla dinámica en Excel:
group_by()
permite agrupar en base a múltiples columnas y summarise()
permite generar múltiples columnas de resumen. El siguiente código calcula la esperanza de vida media y su desvío estándar para cada continente y cada año.
paises %>%
group_by(continente, anio) %>%
summarise(esperanza_de_vida_media = mean(esperanza_de_vida),
esperanza_de_vida_sd = sd(esperanza_de_vida))
## `summarise()` regrouping output by 'continente' (override with `.groups` argument)
## # A tibble: 60 x 4
## # Groups: continente [5]
## continente anio esperanza_de_vida_media esperanza_de_vida_sd
## <chr> <dbl> <dbl> <dbl>
## 1 África 1952 39.1 5.15
## 2 África 1957 41.3 5.62
## 3 África 1962 43.3 5.88
## 4 África 1967 45.3 6.08
## 5 África 1972 47.5 6.42
## 6 África 1977 49.6 6.81
## 7 África 1982 51.6 7.38
## 8 África 1987 53.3 7.86
## 9 África 1992 53.6 9.46
## 10 África 1997 53.6 9.10
## # … with 50 more rows
El resultado va a siempre ser una tabla con la misma cantidad de filas que grupos y una cantidad de columnas igual a la cantidad de columnas usadas para agrupar y los estadísticos computados.
Desafío:
¿Cuál te imaginás que va a ser el resultado del siguiente código? ¿Cuántas filas y columnas va a tener? (Tratá de pensarlo antes de correrlo.)
El combo group_by() %>% summarise()
se puede resumir en esta figura. Las filas de una tabla se dividen en grupos, y luego cada grupo se “resume” en una fila en función del estadístico usado.
Al igual que hicimos “cuentas” usando algunas variables numéricas para obtener información nueva, también podemos utilizar variables categóricas. No tiene sentido calcular mean(continente)
ya que contienen caracteres, pero tal vez nos interese contar la cantidad de observaciones por continente:
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 5 x 2
## continente cantidad
## <chr> <int>
## 1 África 624
## 2 Américas 300
## 3 Asia 396
## 4 Europa 360
## 5 Oceanía 24
mutate()
Todo esto está bien para hacer cálculos con columnas previamente existentes, pero muchas veces tenés que crear nuevas columnas.
La tabla paises
tiene información de PBI per cápita y de población, por lo que es posible computar el PBI de cada país multiplicando los valores de estas columnas. mutate()
permite agregar una nueva columna llamada “pbi” con esa información:
## # A tibble: 1,704 x 7
## pais continente anio esperanza_de_vi… poblacion pib_per_capita pbi
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Afganis… Asia 1952 28.8 8425333 779. 6.57e 9
## 2 Afganis… Asia 1957 30.3 9240934 821. 7.59e 9
## 3 Afganis… Asia 1962 32.0 10267083 853. 8.76e 9
## 4 Afganis… Asia 1967 34.0 11537966 836. 9.65e 9
## 5 Afganis… Asia 1972 36.1 13079460 740. 9.68e 9
## 6 Afganis… Asia 1977 38.4 14880372 786. 1.17e10
## 7 Afganis… Asia 1982 39.9 12881816 978. 1.26e10
## 8 Afganis… Asia 1987 40.8 13867957 852. 1.18e10
## 9 Afganis… Asia 1992 41.7 16317921 649. 1.06e10
## 10 Afganis… Asia 1997 41.8 22227415 635. 1.41e10
## # … with 1,694 more rows
Recordá que las funciones de {dplyr} nunca modifican la tabla original. mutate()
devolvió una nueva tabla que es igual a la tabla paises
pero con la columna “pbi” agregada. La tabla paises
sigue intacta.
ungroup()
En general, la mayoría de las funciones de {dplyr} “entienden” cuando una tabla está agrupada y realizan las operaciones para cada grupo.
Desafío:
¿Cuál de estos dos códigos agrega una columna llamada “pbi_continente” con el pbi promedio del continente correspondiente a cada país? ¿Qué hace el otro?
En otras palabras, los resultados de mutate()
, filter()
, summarise()
y otras funciones cambian según si la tabla está agrupada o no. Como a veces uno se puede olvidar que quedaron grupos, es conveniente usar la función ungroup()
una vez que dejás de trabajar con grupos:
paises %>%
group_by(continente) %>%
mutate(pbi_continente = mean(pib_per_capita*poblacion)) %>%
ungroup()
## # A tibble: 1,704 x 7
## pais continente anio esperanza_de_vi… poblacion pib_per_capita
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Afga… Asia 1952 28.8 8425333 779.
## 2 Afga… Asia 1957 30.3 9240934 821.
## 3 Afga… Asia 1962 32.0 10267083 853.
## 4 Afga… Asia 1967 34.0 11537966 836.
## 5 Afga… Asia 1972 36.1 13079460 740.
## 6 Afga… Asia 1977 38.4 14880372 786.
## 7 Afga… Asia 1982 39.9 12881816 978.
## 8 Afga… Asia 1987 40.8 13867957 852.
## 9 Afga… Asia 1992 41.7 16317921 649.
## 10 Afga… Asia 1997 41.8 22227415 635.
## # … with 1,694 more rows, and 1 more variable: pbi_continente <dbl>