Transformación de datos
Hasta ahora hemos aprendido a importar datos, identificar las características de un marco de datos y recodificar sus variables si es necesario. A partir de ahora empezaremos a explorarlas más a fondo y aprenderemos a transformarlas con el objetivo de resumir la información que buscamos. Para ello será imprescindible conocer dplyr, probablemente el paquete más utilizado en la transformación de datos con R. Como veis en la imagen de la derecha (figura 1), el icono del paquete son unas tenazas, que es una forma de representar qué hacen la mayoría de las funciones que contiene el paquete. En inglés, esto se conoce como data wrangling: pelearse con los datos y atenazarlos para conseguir que tengan el aspecto que queremos.
Anteriormente ya hemos visto algunas funciones de dplyr, como tibble()
, count()
, glimpse()
, recode()
o rename()
. Todas tienen, más o menos, el mismo propósito: observar los datos y transformar algunos de sus valores. Todas estas funciones tienen las características siguientes:
- A nivel individual, trabajaremos un fragmento de la World Values Survey (Inglehart et al., 2020), una base de datos que mide las actitudes de individuos de varios países entre los años 1981 y 2022.
- A nivel regional, utilizaremos una base de datos que contiene información sobre regiones europeas, denominadas estadísticamente regiones NUTS1 (En la figura 2 vemos un ejemplo de las unidades de observación en datos según población.) Estos datos, creados para un proyecto que analizaba los determinantes de los movimientos regionalistas e independentistas en Europa (Sanjaume-Calvet et al., n.d.), incluyen datos de Eurostat, European Social Survey y European Quality of Government Dataset.
- A nivel estatal, utilizaremos el paquete de R de la base de datos Gapminder (Bryan, 2017), que contiene información socioeconómica básica de los países desde la década de 1950 hasta la actualidad.
- Finalmente, también utilizaremos la base de datos UN Votes (Robinson, 2021), que contiene información sobre las votaciones en Naciones Unidas desde sus orígenes hasta la actualidad. Esta base de datos se encuentra en el paquete de R
unvotes
, que contiene tres conjuntos de datos, cada uno con una unidad de observación diferente: votación (un_roll_call
), votación-tema (un_roll_call_issues
) y votación-país (un_votes
).
1 El acrónimo NUTS corresponde a Nomenclature des unités territoriales statistiques (Nomenclatura de las unidades territoriales estadísticas), un sistema de clasificación de las administraciones políticas estatales y regionales de la Unión Europea con fines estadísticos.
A partir de ahora tendremos que trabajar con conjuntos de datos cada vez más grandes, y transformarlos requerirá códigos de R cada vez más sofisticados. Y esto implica tener que aplicar varias funciones de manera simultánea en el mismo objeto. Combinar funciones es una tarea poco agradable visualmente, puesto que tenemos que poner funciones dentro de otras funciones y es complicado leer un código entre tantos paréntesis. Fijémonos en el código siguiente, donde hemos aplicado varias funciones a la variable turnout
del marco de datos elections
, que ya hemos trabajado anteriormente. Leer esta cadena de funciones es extremadamente complicado, entre otras cosas porque tenemos que ir contando los paréntesis para saber qué argumento corresponde a cada función.
Por suerte, el paquete dplyr contiene dos elementos que nos aligerarán mucho el trabajo. En primer lugar, dplyr contiene lo que se denomina pipe (símbolo |>
)2, herramienta que nos permite aplicar sobre el mismo objeto varias funciones de una manera mucho más intuitiva y ordenada. Lo que hace la pipe es cambiar la gramática de las funciones, de forma que nos transforma una función de varios argumentos: f(x, y)
en la estructura x |> f(y)
. Con el sistema pipe, el código anterior quedaría de la siguiente forma:
2 El atajo de teclado para crear la pipe es Cmd+Shift+M en PC y Cmd+Shift+M en Mac. También encontraréis la pipe con el formato %>%
.
Fijaos que ahora el código es mucho más fácil de leer porque la lectura es de arriba abajo, igual como cuando leemos normalmente un texto:
- “del marco de datos
elections
, coge la variableturnout
… - elige cuatro números al azar…
- redondea el resultado…
- haz la media del vector…
- y vuelve a redondear el resultado”
El otro aspecto de las funciones de dplyr que nos facilitará mucho el trabajo es que no necesitaremos utilizar el símbolo del dólar ($
) para separar el marco de datos del vector. En lugar del dólar, el marco de datos y el vector irán simplemente separados por una coma dentro de la función en cuestión. En general, las funciones de dplyr tienen las características siguientes:
- El primer argumento es un marco de datos.
- A partir del segundo argumento, indicamos los vectores que queremos transformar.
- El resultado de aplicar la función es siempre un nuevo marco de datos.
Por lo tanto, en lugar de:
funcion(marcodatos$vector)
en las funciones de dplyr escribiremos3:
3 Cuidado, hay muchas funciones que no son del entorno tidyverse en las que no podremos usar esta lógica y tendremos que utilizar el dólar.
funcion(marcodatos, vector)
La combinación de pipe y la eliminación del símbolo del dólar permiten hacer construcciones sintácticas como la siguiente, en la que en primer lugar especificamos qué marco de datos trabajaremos y a continuación iremos especificando qué vectores del marco de datos trabajaremos con cada función específica.
marcodatos |>
funcion1(vector4) |>
funcion2(vector22, vector51) |>
funcion(vector14)
Poco a poco, iremos comprendiendo la enorme utilidad que tiene este sistema. Lo importante es retener que podemos ordenar las funciones para trabajar con ellas más fácilmente y poder leer más cómodamente el contenido. Si queréis ver otro ejemplo, todavía más práctico, observad el desplegable siguiente: Nuestro día a día en una pipe.
Nuestro día a día no deja de ser un cúmulo de acciones encadenadas. Si las tradujéramos a código de R, sin una pipe la descripción sería más o menos de la siguiente forma:
ir_universidad(coger_transporte(ropa(salir_de la_cama(despertador(yo,
hora = "7:30"), lado = "derecha"), pantalones = TRUE, camisa = TRUE),
bus = TRUE, metro = FALSE), clase_datos = FALSE, bar = TRUE)
El código anterior es bastante complicado de leer. Ahora comprobamos cómo quedaría exactamente el mismo código pero con el sistema pipe:
|>
yo despertador(hora = "7:30") |>
la_cama(lado = "derecho") |>
salir_de ropa(pantalones = TRUE, camisa = TRUE) |>
coger_transporte(bus = TRUE, metro = FALSE) |>
ir_universidad(clase_datos = FALSE, bar = TRUE)
El ejemplo está inspirado en las fuentes siguientes: aquí y aquí.