Transformar amb dplyr
En aquest apartat aprendrem a transformar el marc de dades. Per què volem transformar un marc de dades? Aquestes són les funcions del paquet dplyr que més utilitzarem:
- Filtrar: Si volem reduir el nombre d’observacions utilitzarem la funció
filter()
. - Seleccionar: Si volem reduir el nombre de columnes utilitzarem la funció
select()
. - Ordenar: Si volem ordenar les observacions pels valors d’una determinada columna: utilitzarem la funció
arrange()
. - Mutar: Si volem crear una nova columna a partir de valors d’altres columnes: utilitzarem la funció
mutate()
. - Resumir: Si volem resumir vàries observacions mitjançant una operació: utilitzarem la funció
summarize()
. - Agrupar: Si volem canviar la unitat d’anàlisi de les operacions: utilitzarem la funció
group_by()
.
En aquest apartat aplicarem les funcions del paquet dplyr al marc de dades gapminder
. Per procedir, haurem de carregar els dos paquets:
#recordeu que els paquets han d'estar prèviament instal·lats
library(gapminder)
library(dplyr)
L’operador pipe
És imprescindible que sapigueu com funciona el símbol %>%
, que en direm l’operador pipe. Fins ara, hem après que les funcions s’apliquen així:
- El primer argument dins d’una funció acostuma a ser el marc de dades o un objecte. Per exemple:
funcio1(marcdades, argument2, argument3 ...)
funcio2(marcdades, argument2, argument3 ...)
- Per tant, si volem aplicar vàries funcions i arguments al mateix marc de dades hauríem de fer quelcom com per exemple:
funcio2(funcio1(marcdades, argument2), argument2)
- Resulta bastant complicat de llegir una funció així.
El que fa la funció pipe és facilitar-nos la lectura del codi, ordenant les funcions de diferent manera. Amb la pipe canviem l’ordre amb què escrivim les funcions, de manera que:
- Primer indiquem el marc de dades de referència seguit del símbol pipe.
- A continuació
funcio1(argument2, argument3 ...)
i també ho acabem amb una pipe. - A continuació
funcio2(argument2, argument3 ...)
i també ho acabem amb una pipe. - I així successivament, com es mostra en l’exemple del codi següent:
marcdades %>%
funcio1(argument2) %>%
funcio2(argument2, argument3) %>%
funcio3(argument2)
...
Filtrar
Apliquem filter()
si volem reduir el nombre d’observacions. Per exemple, si només ens interessa treballar amb un sol país del marc de dades:
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.
És important tenir en compte que el resultat de dins el parèntesi de la funció filter()
ha de ser un vector lògic. Podem combinar diferents operacions amb els següents símbols:
- Amb la coma (,) o el símbol & ens retorna els valors que compleixen tots els requisits.
- Amb el símbol | ens retorna els valors que compleixen un o l’altre requisit.
- Amb el símbol %in% ens retorna els valors que indiquem 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 següent vídeo us ho explica.
Font: DatacampPer treballar amb un marc de dades filtrat sempre és més pràctic guardar-lo com a un nou objecte. En aquest cas hem demanat només els valors del continent africà i ho hem guardat com a objecte gap_afr
.
gap_afr <- gapminder %>%
filter(continent == "Africa")
unique(gap_afr$continent) #fixeu-vos com aquesta variable és un vector
## [1] Africa
## Levels: Africa Americas Asia Europe Oceania
#podem eliminar els nivells amb droplevels()
Seleccionar
Reduïm el nombre de columnes amb select()
:
- Ens retornarà el marc de dades amb l’ordre de les columnes que hem indicat a dins la funció. Les columnes que no indiquem ens les eliminarà.
- El símbol
-
ens elimina la columna que indiquem. - El símbol
:
ens retorna de la columna que indiquem a l’esquerra del símbol a la columna que indiquem a la dreta. - Podem utilitzar la funció
select()
simplement per reordenar columnes.
gapminder %>% #seleccionem country, year i pop
select(country, year, pop)
gapminder %>% #eliminem gdpPercap
select(-gdpPercap)
gapminder %>% #seleccionem de country fins a year i gdpPercap
select(country:year, gdpPercap)
gapminder %>% #reordenem les columnes
select(country, year, continent, lifeExp, gdpPercap, pop)
Ordenar
Ordenem amb arrange()
per una o més columnes. Podem introduir més d’una columna. Ens ordenarà primer per la primera columna, després per la segona columna i així successivament.
gapminder %>%
arrange(continent, lifeExp)
Per defecte ordenem en ordre ascendent. Si volem que ens ordeni en ordre descendent haurem d’introduir 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
Amb mutate()
creem una nova columna a través dels valors d’una altra columna. Funciona de la següent manera:
- Primer introduïm el nom de la columna de destí, seguit d’un igual i de l’operació que vulguem fer.
- Si com a columna de destí indiquem el nom d’una columna que ja figura al marc de dades, ens sobreescriurà els resultats (exemple
pop
). - Si com a columna de destí indiquem el nom d’una columna que no figura al marc de dades, ens crearà una nova columna amb el nom de la columna de destí (exemple
gdp
).
gapminder %>%
mutate(pop = pop / 1000000) #substitueix la columna pop
gapminder %>%
mutate(gdp = gdpPercap * pop) %>% #crea la columna gdp perquè no existia prèviament en el marc de dades
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.
Amb les funcions que coneixem fins ara podem enllaçar les operacions següents:
gap_asia <- gapminder %>%
filter(year == 1952, #demanem dades de l'any 1952 i (AND) ...
continent == "Asia") %>% # ... del continent asiàtic
select(-continent, -year) %>% #eliminem les columnes continent i any
mutate(gdp = gdpPercap * pop, #creem la variable gdp
perc_gdp = gdp / sum(gdp)) %>% #creem la variable perc_gdp
arrange(desc(gdp)) #ordenem per la columna gdp
gdp
i acte seguit l’hem utilitzat per crear una nova variable.Resumir
Amb summarize()
demanem un resum d’una variable. Per exemple, en la següent funció demanem que ens resumeixi el marc de dades gap_asia
de la següent manera:
- Volem saber quant suma la població.
- Quina és la mitjana del PIB per càpita.
- Quina és la proporció de països que tenen un PIB per càpita superior a la mitjana.
- En quants casos l’esperança de vida és superior a 60.
- De quin nombre total de casos disposem.
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
Amb la funció group_by()
agrupem les operacions posteriors a partir d’una variable categòrica. Per exemple, a continuació hem demanat sumaris molt semblants al codi anterior, però agrupats per continent. Ens retornarà un sumari per cada valor de la variable continent, per tant, per cada un dels cinc continents.
gapminder %>%
filter(year == 1952) %>%
group_by(continent) %>% #agrupem per una o més variables categòriques
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
Recapitulant dplyr
Aquí podeu veure totes les funcions en un mateix codi:
gapminder %>%
filter(year == 2002) %>% #filtrem per l'any 2002
mutate(gdp = gdpPercap * pop) %>% #creem la nova variable gdp
group_by(continent) %>% #agrupem per continent
summarize(max_pop = max(pop), #quin és el máxim de població? (a cada continent)
min_pop = min(pop), #quin és el mínim de població? (a cada continent)
diff = max_pop - min_pop, #quina és la diferència entre la població màxima i mínima? (a cada continent)
count = n()) %>% #quantes observacions tenim? (a cada continent)
arrange(desc(diff)) %>% #ordena per la columna diff en ordre descendent
select(continent, diff, everything()) #primer vull veure les columnes continent i diff i després la resta
## # 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
Molt important per al domini de dplyr:
- Ajudeu-vos del Cheat Sheet de dplyr.
- Utilitzeu la pàgina web del paquet i cliqueu a cada una de les funcions per obtenir més informació del seu ús.
- Ajudeu-vos d’altres manuals. Un de molt interessant és del de R Para Ciencia de Datos (Grolemund and Wickham 2020).
Podeu trobar un resum d’aquest capítol en aquest vídeo:
Font: Datacamp