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: DatacampPara 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))
## # 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
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