Dplyr y las copas mundiales de fútbol femenino

Jesica Formoso

¿Qué es Dplyr?

dplyr es una gramática para la manipulación y transformación de datos ordenados. Es uno de los paquetes que forma parte del tidyverse.

Hablamos de datos ordenados cuando:

Dplyr roporciona una serie de funciones que buscan facilitar este proceso.

Permite:

  1. Seleccionar las variables que nos interesan.
  2. Seleccionar observaciones.
  3. Crear nuevas variables.
  4. Resumir datos y extraer información.
  5. Ordenar los datos.

Vamos a verlo en acción!

Copas mundiales de futbol femenino

La base de datos que vamos a utilizar se encuentra en el repositorio de github del proyecto datos de miércoles, una iniciativa organizada por la comunidad de R, que busca que sus participantes adquieran habilidades de procesamiento de datos. Para ello, cada semana publican un conjunto de datos para explorar.

Podés descargar la base que utilizamos en este tutorial simplemente corriendo la siguiente línea de código:

resultados_cmff <- read_csv("https://raw.githubusercontent.com/cienciadedatos/datos-de-miercoles/master/datos/2019/2019-07-17/resultados_cmff.csv")

El operador pipe %>%

Este operador (%>%) nos permite encadenar una secuencia de operaciones realizadas sobre la misma base de datos. Simplifica el código y hace que sea más facilmente legible.

Veamos un ejemplo:

Para imprimir en la consola las primeras líneas de un data frame utilizamos la función head().

  • Código tradicional:
head(resultados_cmff, 2) # sin pipe
## # A tibble: 2 x 8
##    anio equipo   codigo_pais ronda resultado goles id_partido_anio numero_equipo
##   <dbl> <chr>    <chr>       <chr> <chr>     <dbl>           <dbl>         <dbl>
## 1  1991 Repúbli~ CHN         Fase~ Victoria      4               1             1
## 2  1991 Noruega  NOR         Fase~ Derrota       0               1             2
  • Código con pipes
resultados_cmff %>% 
  head(2) 
## # A tibble: 2 x 8
##    anio equipo   codigo_pais ronda resultado goles id_partido_anio numero_equipo
##   <dbl> <chr>    <chr>       <chr> <chr>     <dbl>           <dbl>         <dbl>
## 1  1991 Repúbli~ CHN         Fase~ Victoria      4               1             1
## 2  1991 Noruega  NOR         Fase~ Derrota       0               1             2

Cuando utilizamos una única función, la diferencia no es tan notoria. La ventaja de utilizar este operador es más fácil de ver cuando queremos realizar varias operaciones sobre los mismos datos.

Por ejemplo, si quisiera seleccionar las variables resultados_cmff, equipo y anio, ordenar el data frame resultando según la variable anio y luego imprimir en la consola las primera tres filas:

  • Utilizando código tradicional:
equipo_anio <- select(resultados_cmff, equipo, anio) # selecciono las variables
ordenado <- arrange(equipo_anio, anio) # ordeno las variables por año
head(ordenado, 3) # pido las primeras tres filas
## # A tibble: 3 x 2
##   equipo                   anio
##   <chr>                   <dbl>
## 1 República Popular China  1991
## 2 Noruega                  1991
## 3 Dinamarca                1991
  • Utilizando pipes:
resultados_cmff %>% 
  select(equipo, anio) %>% # selecciono las variables
  arrange(anio) %>%  # ordeno las variables por año
  head(3) # pido las primeras tres filas
## # A tibble: 3 x 2
##   equipo                   anio
##   <chr>                   <dbl>
## 1 República Popular China  1991
## 2 Noruega                  1991
## 3 Dinamarca                1991
# es una pipeline!

Usando las pipes no necesitamos crear objetos intermedios y el código es más legible.

Funciones que forman parte de dplyr

  • select() selecciona variables.
  • filter() selecciona observaciones.
  • mutate() crea nuevas variables.
  • summarise() extrae información no presente en la base.
  • arrange() ordena los datos.

select()

Con la función select() podemos seleccionar las variables anio, equipo y goles

resultados_cmff %>% 
  select(equipo, goles, anio) 
## # A tibble: 568 x 3
##    equipo                  goles  anio
##    <chr>                   <dbl> <dbl>
##  1 República Popular China     4  1991
##  2 Noruega                     0  1991
##  3 Dinamarca                   3  1991
##  4 Nueva Zelanda               0  1991
##  5 Japón                       0  1991
##  6 Brasil                      1  1991
##  7 Alemania                    4  1991
##  8 Nigeria                     0  1991
##  9 Suecia                      2  1991
## 10 Estados Unidos              3  1991
## # ... with 558 more rows

.. o todas las variables menos goles:

resultados_cmff %>% 
  select(-goles) 
## # A tibble: 568 x 7
##     anio equipo      codigo_pais ronda   resultado id_partido_anio numero_equipo
##    <dbl> <chr>       <chr>       <chr>   <chr>               <dbl>         <dbl>
##  1  1991 República ~ CHN         Fase d~ Victoria                1             1
##  2  1991 Noruega     NOR         Fase d~ Derrota                 1             2
##  3  1991 Dinamarca   DEN         Fase d~ Victoria                2             1
##  4  1991 Nueva Zela~ NZL         Fase d~ Derrota                 2             2
##  5  1991 Japón       JPN         Fase d~ Derrota                 3             1
##  6  1991 Brasil      BRA         Fase d~ Victoria                3             2
##  7  1991 Alemania    GER         Fase d~ Victoria                4             1
##  8  1991 Nigeria     NGA         Fase d~ Derrota                 4             2
##  9  1991 Suecia      SWE         Fase d~ Derrota                 5             1
## 10  1991 Estados Un~ USA         Fase d~ Victoria                5             2
## # ... with 558 more rows

Podemos seleccionar todas las variables que se encuentran entre equipo y ronda:

resultados_cmff %>% 
  select(equipo:ronda)
## # A tibble: 568 x 3
##    equipo                  codigo_pais ronda         
##    <chr>                   <chr>       <chr>         
##  1 República Popular China CHN         Fase de grupos
##  2 Noruega                 NOR         Fase de grupos
##  3 Dinamarca               DEN         Fase de grupos
##  4 Nueva Zelanda           NZL         Fase de grupos
##  5 Japón                   JPN         Fase de grupos
##  6 Brasil                  BRA         Fase de grupos
##  7 Alemania                GER         Fase de grupos
##  8 Nigeria                 NGA         Fase de grupos
##  9 Suecia                  SWE         Fase de grupos
## 10 Estados Unidos          USA         Fase de grupos
## # ... with 558 more rows

También podemos combinar select() con otras funciones:

contains() me permite seleccionar todas las variables que contengan cierta secuencia de caracteres en su nombre:

resultados_cmff %>% 
  select(contains("equipo")) # variables que contengan "equipo" en su nombre 
## # A tibble: 568 x 2
##    equipo                  numero_equipo
##    <chr>                           <dbl>
##  1 República Popular China             1
##  2 Noruega                             2
##  3 Dinamarca                           1
##  4 Nueva Zelanda                       2
##  5 Japón                               1
##  6 Brasil                              2
##  7 Alemania                            1
##  8 Nigeria                             2
##  9 Suecia                              1
## 10 Estados Unidos                      2
## # ... with 558 more rows
# Los valores no numéricos van entre "".

De forma similar, starts_with() me permite seleccionar todas las variables que comiencen con cierta secuencia de caracteres:

resultados_cmff %>% 
  select(starts_with("res")) # variables que empiecen con "res"
## # A tibble: 568 x 1
##    resultado
##    <chr>    
##  1 Victoria 
##  2 Derrota  
##  3 Victoria 
##  4 Derrota  
##  5 Derrota  
##  6 Victoria 
##  7 Victoria 
##  8 Derrota  
##  9 Derrota  
## 10 Victoria 
## # ... with 558 more rows

Mientras que ends_with() me permite seleccionar variables que terminen con una secuencia específica de caracteres:

resultados_cmff %>% 
  select(ends_with("io")) # variables que terminan en "io"
## # A tibble: 568 x 2
##     anio id_partido_anio
##    <dbl>           <dbl>
##  1  1991               1
##  2  1991               1
##  3  1991               2
##  4  1991               2
##  5  1991               3
##  6  1991               3
##  7  1991               4
##  8  1991               4
##  9  1991               5
## 10  1991               5
## # ... with 558 more rows

Podemos seleccionar variables de un tipo específico con select_if() (selecciona si..)

resultados_cmff %>% 
  select_if(is.numeric) # sólo las variables numéricas
## # A tibble: 568 x 4
##     anio goles id_partido_anio numero_equipo
##    <dbl> <dbl>           <dbl>         <dbl>
##  1  1991     4               1             1
##  2  1991     0               1             2
##  3  1991     3               2             1
##  4  1991     0               2             2
##  5  1991     0               3             1
##  6  1991     1               3             2
##  7  1991     4               4             1
##  8  1991     0               4             2
##  9  1991     2               5             1
## 10  1991     3               5             2
## # ... with 558 more rows

Resumiendo, la función select() nos permite seleccionar columnas o variables.

Para seleccionar filas u observaciones vamos a utilizar la función filter.

filter()

filter() nos permite seleccionar las filas que cumplen una o más condiciones especificadas por nosotros.

Por ejemplo, si sólo nos interesa la información del equipo argentino..

resultados_cmff %>% 
  filter(equipo == "Argentina") %>% 
  head(2)
## # A tibble: 2 x 8
##    anio equipo  codigo_pais ronda  resultado goles id_partido_anio numero_equipo
##   <dbl> <chr>   <chr>       <chr>  <chr>     <dbl>           <dbl>         <dbl>
## 1  2003 Argent~ ARG         Fase ~ Derrota       0               4             2
## 2  2003 Argent~ ARG         Fase ~ Derrota       0              12             2

Ejercicio 1

¿Qué podemos agregar al siguiente código si sólo queremos quedarnos solamente con el equipo y sus resultado? Pista: querés elegir esas variables..

resultados_cmff %>% 
  filter(equipo == "Argentina") %>% 
  select(________) %>% 
  head(2)

filter() utiliza operadores lógicos

En R los operadores lógicos son:

  • == igual a
  • != distinto de
  • > mayor a
  • >= mayor o igual
  • < menor a
  • <= menos o igual a
  • & y
  • | o

Las condiciones se indican como afirmaciones que se responden con TRUE (verdadero) o FALSE (falso):

# ¿2 es igual a 4?
2 == 4 
## [1] FALSE
# ¿2 en menos a 4?
2 < 4
## [1] TRUE
# ¿2 es diferente a 4?
2 != 4 
## [1] TRUE

filter() se queda con aquellas observaciones que responden con verdadero (TRUE) a la afirmación que escribimos.

resultados_cmff %>% 
  filter(equipo != "Argentina") %>% # retiene todos los equipos distintos del argentino.
  count(equipo) # Cuenta cuantas veces aparece cada equipo.
## # A tibble: 35 x 2
##    equipo              n
##    <chr>           <int>
##  1 Alemania           44
##  2 Australia          26
##  3 Brasil             34
##  4 Camerún             8
##  5 Canadá             27
##  6 Chile               3
##  7 China Taipei        4
##  8 Colombia            7
##  9 Corea del Norte    13
## 10 Corea del Sur      10
## # ... with 25 more rows

Muchas veces necesitamos quedarnos con aquellas filas que cumplen más de una condición.

Por ejemplo, si me interesa saber cuantos partidos jugó argentina antes del año 2010, puedo hacer lo siguiente:

resultados_cmff %>% 
  filter(equipo == "Argentina", anio < 2010) %>% 
  count()
## # A tibble: 1 x 1
##       n
##   <int>
## 1     6

Ejercicio 2

Cambiá el operador lógico en el código anterior para buscar todos los partidos que jugó argentina después del año 2010.

Para quedarnos con dos o mas valores distintos de una misma variable usamos %in%.

Por ejemplo, si quisieramos saber cuantos partidos jugaron Argentina, Chile y México, podemos hacer lo siguiente:

resultados_cmff %>% 
  filter(equipo %in% c("Argentina", "Chile", "México")) %>% 
  count(equipo)
## # A tibble: 3 x 2
##   equipo        n
##   <chr>     <int>
## 1 Argentina     9
## 2 Chile         3
## 3 México        9

Al igual que select, filter() puede combinarse con otras funciones.

between() me sirve para obtener todas las observaciones que estén dentro de un rango numérico. Por ejemplo, todos los partidos que se jugaron entre los años 2000 y 2010.

resultados_cmff %>% 
  filter(between(anio, 2000, 2010)) 
## # A tibble: 128 x 8
##     anio equipo  codigo_pais ronda resultado goles id_partido_anio numero_equipo
##    <dbl> <chr>   <chr>       <chr> <chr>     <dbl>           <dbl>         <dbl>
##  1  2003 Noruega NOR         Fase~ Victoria      2               1             1
##  2  2003 Francia FRA         Fase~ Derrota       0               1             2
##  3  2003 Nigeria NGA         Fase~ Derrota       0               2             1
##  4  2003 Corea ~ PRK         Fase~ Victoria      3               2             2
##  5  2003 Aleman~ GER         Fase~ Victoria      4               3             1
##  6  2003 Canadá  CAN         Fase~ Derrota       1               3             2
##  7  2003 Japón   JPN         Fase~ Victoria      6               4             1
##  8  2003 Argent~ ARG         Fase~ Derrota       0               4             2
##  9  2003 Estado~ USA         Fase~ Victoria      3               5             1
## 10  2003 Suecia  SWE         Fase~ Derrota       1               5             2
## # ... with 118 more rows

Ejercicio 3

El código que sigue genera el error “object ‘equipo’ not found” (objeto ‘equipo’ no encontrado). Intentá encontrár por qué y modificalo. Pista: ¡el orden es importante!

resultados_cmff %>% 
  select(anio, resultado) %>% 
    filter(equipo == "Argentina")

mutate() y summarise

mutate() y summarise() son otras dos funciones sumamente útiles.

Usamos mutate() para crear variables nuevas o modificar variables existentes. Usamos summarise() para obtener medidas que resumen los datos.

Por ejemplo, ¿Cuál es el promedio de goles?

resultados_cmff %>% 
  summarise(Promedio = mean(goles))
## # A tibble: 1 x 1
##   Promedio
##      <dbl>
## 1     1.61

No nos dice demasiado, ¿no?. Mejor calculemos cuál es el promedio de goles por mundial (anio) para cada equipo.

resultados_cmff %>% 
  group_by(anio, equipo) %>% 
  summarise(Promedio = mean(goles))
## # A tibble: 136 x 3
## # Groups:   anio [8]
##     anio equipo         Promedio
##    <dbl> <chr>             <dbl>
##  1  1991 Alemania          2    
##  2  1991 Brasil            0.333
##  3  1991 China Taipei      0.5  
##  4  1991 Dinamarca         1.75 
##  5  1991 Estados Unidos    4.17 
##  6  1991 Italia            2    
##  7  1991 Japón             0    
##  8  1991 Nigeria           0    
##  9  1991 Noruega           2.33 
## 10  1991 Nueva Zelanda     0.333
## # ... with 126 more rows

La función group_by me permite obtener medidas de resumen para grupos específicos.

Ahora bien, ¿cuál es la diferencia entre el promedio de goles de cada país por mundial y el promedio global?. Podemos utilizar la función mutate() para crear una variable que sea el la diferencia entre los valores obtenidos con el código anterior y el promedio total que calculamos antes (1.61).

resultados_cmff %>% 
  group_by(anio, equipo) %>% 
  summarise(promedio_goles = mean(goles)) %>%
  mutate(dif_medias = promedio_goles - 1.61)
## # A tibble: 136 x 4
## # Groups:   anio [8]
##     anio equipo         promedio_goles dif_medias
##    <dbl> <chr>                   <dbl>      <dbl>
##  1  1991 Alemania                2          0.39 
##  2  1991 Brasil                  0.333     -1.28 
##  3  1991 China Taipei            0.5       -1.11 
##  4  1991 Dinamarca               1.75       0.140
##  5  1991 Estados Unidos          4.17       2.56 
##  6  1991 Italia                  2          0.39 
##  7  1991 Japón                   0         -1.61 
##  8  1991 Nigeria                 0         -1.61 
##  9  1991 Noruega                 2.33       0.723
## 10  1991 Nueva Zelanda           0.333     -1.28 
## # ... with 126 more rows

Si quiero ver estos mismos resultados pero ordenados de menor a mayor según la diferencia de medias, puedo sumar al código anterior la función arrange():

resultados_cmff %>% 
  group_by(anio, equipo) %>% 
  summarise(promedio_goles = mean(goles)) %>%
  mutate(dif_medias = promedio_goles - 1.61) %>% 
  arrange(dif_medias)
## # A tibble: 136 x 4
## # Groups:   anio [8]
##     anio equipo                  promedio_goles dif_medias
##    <dbl> <chr>                            <dbl>      <dbl>
##  1  1991 Japón                            0          -1.61
##  2  1991 Nigeria                          0          -1.61
##  3  2003 Nigeria                          0          -1.61
##  4  2007 Nueva Zelanda                    0          -1.61
##  5  2011 Colombia                         0          -1.61
##  6  2011 Corea del Norte                  0          -1.61
##  7  2019 República Popular China          0.25       -1.36
##  8  1991 Brasil                           0.333      -1.28
##  9  1991 Nueva Zelanda                    0.333      -1.28
## 10  1999 Dinamarca                        0.333      -1.28
## # ... with 126 more rows

¿Cuántos partidos se jugaron por año?

resultados_cmff %>% 
  count(anio) 
## # A tibble: 8 x 2
##    anio     n
##   <dbl> <int>
## 1  1991    52
## 2  1995    52
## 3  1999    64
## 4  2003    64
## 5  2007    64
## 6  2011    64
## 7  2015   104
## 8  2019   104

Ejercicio 4

Completá el código siguiente para obtener una variable que sea la cantidad de partidos que se jugaron por año y quedate con aquellos años en que se hayan jugado más de 40 partidos.

(Tené en cuenta que cada partido aparece dos veces. Por ejemplo, un partido entre Argentina y Brasil se registra como un partido del equipo argentino, pero también como un partido del equipo brasilero).

resultados_cmff %>% 
  count(anio) %>% 
  mutate(n = n/2) %>% # divido porque cada partido se registra dos veces.
  filter(n ___ 40)

Vamos a cerrar viendo qué pasa con el promedio de goles a lo largo de los años.

resultados_cmff %>% 
  group_by(anio) %>%
  summarise(promedio_goles = mean(goles)) %>% 
  ggplot(aes(anio, promedio_goles)) +
  geom_line()

En el eje X podemos ver los años de los distintos mundiales y en el y el promedio de goles. El gráfico nos muestra que con los años, el promedio de goles fue disminuyendo.

El motivo de este fenómeno es desconocido para mí, pero los invito a continuar explorando estos datos y formar sus propias opiniones al respecto.

Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License.