Transformar con dplyr

En este apartado aprenderemos a transformar el marco de datos. ¿Por qué queremos transformar un marco de datos? Estas son las funciones del paquete dplyr que más usaremos:

  • Filtrar: Si queremos reducir el número de observaciones utilizaremos la función filter().
  • Seleccionar: Si queremos reducir el número de columnas utilizaremos la función select().
  • Ordenar: Si queremos ordenar las observaciones por los valores de una determinada columna: utilizaremos la función arrange().
  • Mutar: Si queremos crear una nueva columna a partir de valores de otras columnas: utilizaremos la función mutate().
  • Resumir: Si queremos resumir varias observaciones mediante una operación: utilizaremos la función summarize().
  • Agrupar: Si queremos cambiar la unidad de analisis de las operaciones: utilizaremos la función group_by().

En este apartado aplicaremos las funciones de dplyr al marc de datos gapminder. Para proceder, descargaremos los dos paquetes:

#recordad que los paquetes deben estar previamente instalados 
library(gapminder)
library(dplyr)

El operador pipe

Es imprescindible que sepáis como funciona el símbolo %>%, que llamaremos el operador pipe. Hasta ahora, habéis aprendido que las funciones se aplican sí:

  • El primer argumento dentro de una función suele ser el marco de datos o un objeto. Por ejemplo:
    • funcion1(marcodatos, argumento2, argumento3 ...)
    • funcion2(marcodatos, argumento2, argumento3 ...)
  • Por lo tanto, si queremos aplicar varias funciones y argumentos al mismo marco de datos deberíamos hacer algo como por ejemplo:
    • funcion2(funcion1(marcodatos, argumento2), argumento2)
  • Resulta bastante complicado de leer una función así.

Lo que hace la función pipe es facilitarnos la lectura del código, ordenando las funciones de diferente manera. Con la pipe cambiamos el orden en que escribimos las funciones, por lo cual:

  • Primero indicamos el marco de datos de referencia seguido del símbolo pipe.
  • A continuación funcion1(argumento2, argumento3 ...) y también lo acabamos con una pipe.
  • A continuació funcion2(argumento2, argumento3 ...) y también lo acabamos con una pipe.
  • I así succesivamente, tal y como se muestra en el ejemplo del código siguiente:
marcodatos %>%
  funcion1(argumento2, argumento3) %>%
  funcion2(argumento2) %>%
  ...

Filtrar

Aplicamos filter() si queremos reducir el número de observaciones. Por ejemplo, si nos interesa trabajar con un solo país del marco de datos:

 gapminder %>%
 filter(country == "France")
## # A tibble: 12 x 6
##    country continent  year lifeExp      pop gdpPercap
##    <fct>   <fct>     <int>   <dbl>    <int>     <dbl>
##  1 France  Europe     1952    67.4 42459667     7030.
##  2 France  Europe     1957    68.9 44310863     8663.
##  3 France  Europe     1962    70.5 47124000    10560.
##  4 France  Europe     1967    71.6 49569000    13000.
##  5 France  Europe     1972    72.4 51732000    16107.
##  6 France  Europe     1977    73.8 53165019    18293.
##  7 France  Europe     1982    74.9 54433565    20294.
##  8 France  Europe     1987    76.3 55630100    22066.
##  9 France  Europe     1992    77.5 57374179    24704.
## 10 France  Europe     1997    78.6 58623428    25890.
## 11 France  Europe     2002    79.6 59925035    28926.
## 12 France  Europe     2007    80.7 61083916    30470.

Es importante tener en cuenta que el resultado de dentro del paréntesis de la función filter() debe ser un vector lógico. Podemos combinar diferentes operaciones con los siguientes símbolos:

  • Con la coma (,) o el símbolo & nos devuelve los valores que cumplen todos los requisitos.
  • Con el símbolo | nos devuelve los valores que cumplen uno o el otro requisito.
  • Con el símbolo %in% nos devuelve los valores que se indican en un vector.
gapminder %>%
 filter(year == 1992, gdpPercap > 30000)

gapminder %>%
 filter(year >= 1992 | gdpPercap > 24000)

gapminder %>%
 filter(year != 1992 & gdpPercap <= 24000)

gapminder %>%
 filter(country %in% c("France", "Germany", "Spain"))
## # A tibble: 4 x 6
##   country       continent  year lifeExp       pop gdpPercap
##   <fct>         <fct>     <int>   <dbl>     <int>     <dbl>
## 1 Kuwait        Asia       1992    75.2   1418095    34933.
## 2 Norway        Europe     1992    77.3   4286357    33966.
## 3 Switzerland   Europe     1992    78.0   6995447    31872.
## 4 United States Americas   1992    76.1 256894189    32004.
## # A tibble: 592 x 6
##    country     continent  year lifeExp      pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Afghanistan Asia       1992    41.7 16317921      649.
##  2 Afghanistan Asia       1997    41.8 22227415      635.
##  3 Afghanistan Asia       2002    42.1 25268405      727.
##  4 Afghanistan Asia       2007    43.8 31889923      975.
##  5 Albania     Europe     1992    71.6  3326498     2497.
##  6 Albania     Europe     1997    73.0  3428038     3193.
##  7 Albania     Europe     2002    75.7  3508512     4604.
##  8 Albania     Europe     2007    76.4  3600523     5937.
##  9 Algeria     Africa     1992    67.7 26298373     5023.
## 10 Algeria     Africa     1997    69.2 29072015     4797.
## # … with 582 more rows
## # A tibble: 1,468 x 6
##    country     continent  year lifeExp      pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Afghanistan Asia       1952    28.8  8425333      779.
##  2 Afghanistan Asia       1957    30.3  9240934      821.
##  3 Afghanistan Asia       1962    32.0 10267083      853.
##  4 Afghanistan Asia       1967    34.0 11537966      836.
##  5 Afghanistan Asia       1972    36.1 13079460      740.
##  6 Afghanistan Asia       1977    38.4 14880372      786.
##  7 Afghanistan Asia       1982    39.9 12881816      978.
##  8 Afghanistan Asia       1987    40.8 13867957      852.
##  9 Afghanistan Asia       1997    41.8 22227415      635.
## 10 Afghanistan Asia       2002    42.1 25268405      727.
## # … with 1,458 more rows
## # A tibble: 36 x 6
##    country continent  year lifeExp      pop gdpPercap
##    <fct>   <fct>     <int>   <dbl>    <int>     <dbl>
##  1 France  Europe     1952    67.4 42459667     7030.
##  2 France  Europe     1957    68.9 44310863     8663.
##  3 France  Europe     1962    70.5 47124000    10560.
##  4 France  Europe     1967    71.6 49569000    13000.
##  5 France  Europe     1972    72.4 51732000    16107.
##  6 France  Europe     1977    73.8 53165019    18293.
##  7 France  Europe     1982    74.9 54433565    20294.
##  8 France  Europe     1987    76.3 55630100    22066.
##  9 France  Europe     1992    77.5 57374179    24704.
## 10 France  Europe     1997    78.6 58623428    25890.
## # … with 26 more rows

El siguiente vídeo os lo explica.

Fuente: Datacamp

Para trabajar con un marco de datos filtrado siempre es más práctico guardarlo como un nuevo objeto. En este caso hemos pedido sólo los valores del continente africano y lo hemos guardado como objeto gap_afr.

gap_afr <- gapminder %>%
  filter(continent == "Africa")

unique(gap_afr$continent) #tened en cuenta que esta variable és un vector
## [1] Africa
## Levels: Africa Americas Asia Europe Oceania
#podemos eliminar los niveles con droplevels()

Seleccionar

Reducimos el número de columnas con select():

  • Nos devolverá el marco de datos con el orden de las columnas que hemos indicado dentro de la función. Las columnas que no indicamos nos las eliminará.
  • El símbolo - nos elimina la columna que indicamos.
  • El símbolo : nos devuelve de la columna que indicamos a la izquierda del símbolo en la columna que indicamos a la derecha.
  • Podemos utilizar la función select() simplemente para reordenar columnas.
gapminder %>% #seleccionamos country, year y pop
 select(country, year, pop)

gapminder %>% #eliminamos gdpPercap
 select(-gdpPercap)

gapminder %>% #seleccionamos de country hasta year y gdpPercap
 select(country:year, gdpPercap)

gapminder %>% #reordenamos las columnas
 select(country, year, continent, lifeExp, gdpPercap, pop)

Ordenar

Ordenamos con arrange() para una o más columnas. Podemos introducir más de una columna. Nos ordenará primero por la primera columna, luego por la segunda columna y así sucesivamente.

gapminder %>%
 arrange(continent, lifeExp)

Por defecto ordenamos en orden ascendente. Si queremos que nos ordene en orden descendente deberemos introducir desc().

gapminder %>%
 arrange(desc(lifeExp)) %>%
  head()
## # A tibble: 6 x 6
##   country          continent  year lifeExp       pop gdpPercap
##   <fct>            <fct>     <int>   <dbl>     <int>     <dbl>
## 1 Japan            Asia       2007    82.6 127467972    31656.
## 2 Hong Kong, China Asia       2007    82.2   6980412    39725.
## 3 Japan            Asia       2002    82   127065841    28605.
## 4 Iceland          Europe     2007    81.8    301931    36181.
## 5 Switzerland      Europe     2007    81.7   7554661    37506.
## 6 Hong Kong, China Asia       2002    81.5   6762476    30209.

Mutar

Con mutate() creamos una nueva columna a través de los valores de otra columna. Funciona de la siguiente manera:

  • Primero introducimos el nombre de la columna de destino, seguido de un igual y del operación que queramos hacer.
  • Si como columna de destino indicamos el nombre de una columna que ya figura en el marco de datos, nos sobrescribirá los resultados (ejemplo pop).
  • Si como columna de destino indicamos el nombre de una columna que no figura al marco de datos, nos creará una nueva columna con el nombre de la columna de destino (ejemplo gdp).
gapminder %>%
 mutate(pop = pop / 1000000) #sustituye la columna pop
gapminder %>%
 mutate(gdp = gdpPercap * pop) %>% #crea la columna gdp porque no existía previamente en el marco de datos
 head()
## # A tibble: 6 x 7
##   country     continent  year lifeExp      pop gdpPercap          gdp
##   <fct>       <fct>     <int>   <dbl>    <int>     <dbl>        <dbl>
## 1 Afghanistan Asia       1952    28.8  8425333      779.  6567086330.
## 2 Afghanistan Asia       1957    30.3  9240934      821.  7585448670.
## 3 Afghanistan Asia       1962    32.0 10267083      853.  8758855797.
## 4 Afghanistan Asia       1967    34.0 11537966      836.  9648014150.
## 5 Afghanistan Asia       1972    36.1 13079460      740.  9678553274.
## 6 Afghanistan Asia       1977    38.4 14880372      786. 11697659231.

Con las funciones que conocemos hasta ahora podemos enlazar las operaciones siguientes:

gap_asia <- gapminder %>%
  filter(year == 1952, #pedimos datos del año 1952 y (AND) ...
         continent == "Asia") %>% # ... del continente asiático
  select(-continent, -year) %>% #eliminamos las columnas continente y año
  mutate(gdp = gdpPercap * pop, #creamos la variable gdp
         perc_gdp = gdp / sum(gdp)) %>% #creamos la variable perc_gdp
  arrange(desc(gdp)) #ordenamos por la columna gdp

Tened en cuenta que siempre podemos hacer operaciones sobre columnas que acabamos de crear. En el ejemplo hemos creado la columna gdp y acto seguido lo hemos utilizado para crear una nueva variable.

Resumir

Con summarize() pedimos un resumen de una variable. Por ejemplo, en la siguiente función pedimos que nos resuma el marco de datos gap_asia de la siguiente manera:

  • Queremos saber cuánto suma la población.
  • Cuál es la media del PIB per cápita.
  • Cuál es la proporción de países que tienen un PIB per cápita superior a la media.
  • En cuántos casos la esperanza de vida es superior a 60.
  • De qué número total de casos disponemos.
gap_asia %>%
  summarize(tpop = sum(pop),
            mean_gdpcap = mean(gdpPercap, na.rm = TRUE),
            prop = mean(gdpPercap > mean_gdpcap),
            esp = sum(lifeExp > 60),
            count = n())
## # A tibble: 1 x 5
##         tpop mean_gdpcap   prop   esp count
##        <int>       <dbl>  <dbl> <int> <int>
## 1 1395357351       5195. 0.0909     4    33

Agrupar

Con la función group_by() agrupamos las operaciones posteriores a partir de una variable categórica. Por ejemplo, después hemos pedido sumarios muy similares al código anterior, pero agrupados por continente. Nos devolverá un sumario para cada valor de la variable continente, por lo tanto, por cada uno de los cinco continentes.

gapminder %>%
  filter(year == 1952) %>%
  group_by(continent) %>% #agrupamos por una o más variables categóricas
  summarize(tpop = sum(pop),
            mean_gdpcap = mean(gdpPercap, na.rm = TRUE),
            prop = mean(gdpPercap > mean_gdpcap),
            esp = sum(lifeExp > 60),
            count = n())
## # A tibble: 5 x 6
##   continent       tpop mean_gdpcap   prop   esp count
##   <fct>          <int>       <dbl>  <dbl> <int> <int>
## 1 Africa     237640501       1253. 0.327      0    52
## 2 Americas   345152446       4079. 0.24       6    25
## 3 Asia      1395357351       5195. 0.0909     4    33
## 4 Europe     418120846       5661. 0.433     23    30
## 5 Oceania     10686006      10298. 0.5        2     2

Recapitulando dplyr

Aquí podéis ver todas las funciones en un mismo código:

gapminder %>%
  filter(year == 2002) %>% #filtraremos por el año 2002
  mutate(gdp = gdpPercap * pop) %>% #creamos la nueva variable gdp
  group_by(continent) %>% #agrupamos por continente
  summarize(max_pop = max(pop), #cuál es el máximo de población? (en cada continente)
            min_pop = min(pop), #cuál es el mínimo de población? (en cada continente)
            diff = max_pop - min_pop, #cuál es la diferencia entre la población máxima y mínima? (en cada continente)
            count = n()) %>% #cuantas observaciones tenemos? (en cada continente)
  arrange(desc(diff)) %>% #ordena por la columna diff en ordren descendiente
  select(continent, diff, everything()) #primero quiero ver las columnnas continente y diff y luego el resto
## # A tibble: 5 x 5
##   continent       diff    max_pop min_pop count
##   <fct>          <int>      <int>   <int> <int>
## 1 Asia      1279743603 1280400000  656397    33
## 2 Americas   286573694  287675526 1101832    25
## 3 Africa     119730902  119901274  170372    52
## 4 Europe      82062641   82350671  288030    30
## 5 Oceania     15638755   19546792 3908037     2

Muy importante para dominar dplyr:

  • Ayudaros del Cheat Sheet de dplyr.
  • Utilizad la página web del paquete y pulsad en cada una de las funciones para obtener más información de su uso.
  • Ayudaros de otros manuales. Uno de muy interesante es del de R Para Ciencia de Datos (Grolemund and Wickham 2020).

Podéis encontrar un resumen de este capítulo en este video:

Fuente: Datacamp

Referencias

Grolemund, Garrett, and Hadley Wickham. 2020. R para Ciencia de Datos. O’Reilly. https://es.r4ds.hadley.nz/index.html.

Previous
Next