Este es un ejemplo de fichero R markdown que te sirve para aprender varias cosas:
Fijándote en el código, cómo funciona R. En particular, este código es un ejemplo típico de las distintas fases del análisis empírico: lectura de datos, manipulación de datos, modelización (en nuestro caso cálculo de medias), visualización, y comunicación (esta parte)
Cómo funcionan los ficheros R markdown. El fichero
.Rmd incluido en Studium sirve para generar el
.html.
El objetivo de este estudio es replicar el análisis sobre brecha de género en matemáticas realizado por smarterpoland.pl para los países participantes en Pisa2015, pero para las CCAA españolas con datos de 2018.
Leidos el fichero de datos en formato .sav
correspondiente a todos los estudiantes que participaron en PISA, lo
único que hice fuera de clase es seleccionar los datos correspondientes
a España en 2018 disponibles aquí
y crear una nueva variable. Para hacer el análisis replicable, este es
el código que lo generó (requiere tener cargadas las librerias
haven, tidyverse y stringr):
# Cargar datos spss habiendo descomprimido el fichero zip
library(haven); library(tidyverse)
esp2018 <- read_spss("ESP_06_Diciembre_PISA2018.sav") |>
mutate(sex=as_factor(ST004D01T),
CCAA=as_factor(STRATUM) |> as.character()) |>
mutate(CCAA=gsub(".*: (.*), .*","\\1",CCAA),
CCAA=gsub("(.*),.*","\\1",CCAA))
# Salvar los datos
save(esp2018,file="esp2018.RData")
Para comenzar el análisis tenemos que cargar los paquetes necesarios y los datos correspondientes.
R es un lenguaje extensible a través de los llamados
paquetes. En RStudio podemos ver en la pestaña
packages qué paquetes tenemos disponibles en nuestro
ordenador. Es posible instalar nuevos paquetes bien a través de esa
pestaña o de la función install.packages() que requiere
como argumento el nombre del paquete entre comíllas (para que sea un
objeto del tipo character).
Para tener accesibles los paquetes en una sesión de R
tenemos que cargarlos con la función library. La idea es
añadir los paquetes correspondientes a la lista de lugares donde
R busca las funciones (search path). Para saber dónde
está buscando R podemos utilizar la función
search, en mi caso -desde Rstudio- con los
siguientes resultados:
search()
## [1] ".GlobalEnv" "package:stats" "package:graphics"
## [4] "package:grDevices" "package:utils" "package:datasets"
## [7] "package:methods" "Autoloads" "package:base"
El primer sitio donde busca R en el entorno global (el que
RStudio muestra en environment). Los siguientes
son los paquetes básicos.
Al cargar los paquetes los añadimos a nuestra libreria:
library(intsvy) # Para análisis de encuestas commplejas
library(tidyverse) # Para análisis de datos
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.2 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.2 ✔ tibble 3.2.1
## ✔ lubridate 1.9.2 ✔ tidyr 1.3.0
## ✔ purrr 1.0.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
search()
## [1] ".GlobalEnv" "package:lubridate" "package:forcats"
## [4] "package:stringr" "package:dplyr" "package:purrr"
## [7] "package:readr" "package:tidyr" "package:tibble"
## [10] "package:ggplot2" "package:tidyverse" "package:intsvy"
## [13] "package:stats" "package:graphics" "package:grDevices"
## [16] "package:utils" "package:datasets" "package:methods"
## [19] "Autoloads" "package:base"
Los datos los cargamos con:
load("esp2018.RData")
Suponiendo que están en la carpeta que ha abierto Rstudio
(la que vemos inicialmente en la pestaña files). Si no es
así podemos hacer varias cosas:
files y, en el
botón de More seleccionar
Set as working directory. Esto nos permite, además,
aprender la función de R que cambia el directorio de
trabajo.Environment navegando hasta él.Al cargarlo veremos que ha aparecido el objeto esp2018
en la ventana Environment, que tiene dimensiones 35943
filas y 1120 columnas. Las filas se corresponden con los estudiantes
encuestados, las columnas con variables observadas para cada estudiante.
Por otro lado, dándo a la flecha azul podemos abrir la información sobre
la estructura del objeto, que es la misma que se obtendría con
str(esp2018).
Por último, si hacemos click en el nombre del objeto, se abrirá en
una pestaña nueva, lo mismo que conseguiríamos con
View(esp2018). Por último, para ver que tipo de objeto
tenemos, lo podemos ver con
class(esp2018)
## [1] "tbl_df" "tbl" "data.frame"
Los objetos data.frame son los objetos de datos más
sencillos en R. Se trata de una matriz de datos donde las
observaciones son filas y las variables columnas. Cada variable puede
ser de una clase distinta. Los objetos tbl_df, en inglés tibbles,
o tiablas, son una variación de la data.frame
típica del tidyverse con un mejor comportamiento al
imprimir.
intsvyUna vez cargados los datos podemos hacer el análisis. En nuestro
caso, el paquete intsvy contiene funciones de muy alto
nivel que permiten hacer análisis sofisticados de encuestas de las que
ya conoce el formato con una sóla linea. Es el caso de la función
pisa.mean.pv que calcula la media de una variable de PISA
2015 para las combinaciones de variables definidas por el argumento
by. Esta función particulariza la función
intsvy.mean.pv. Podemos aprender sobre los argumentos
utilizando la ayuda de esa función con ? intsvy.mean.pv o
help(intsvy.mean.pv)
Esta es la función y la parte inicial de los resultados:
mates2018 <- pisa.mean.pv(pvlabel = "MATH", by = c("CCAA", "sex"), data = esp2018)
head(mates2018)
## CCAA sex Freq Mean s.e. SD s.e
## 1 Andalusia Female 863 461.59 3.81 83.16 2.98
## 2 Andalusia Male 903 472.76 5.84 91.86 2.51
## 3 Aragon Female 897 494.56 6.14 85.83 2.96
## 4 Aragon Male 900 498.83 6.72 91.47 2.71
## 5 Asturias Female 945 487.44 5.51 86.32 2.95
## 6 Asturias Male 951 493.90 5.27 89.73 2.39
La función head sirve para mostrar sólo la primera parte
de un objeto. Podéis aprender sobre ella con ? head.
El objeto mates2018 contiene todos los elementos que necesitamos,
pero también otros (además de la media, las frecuencias absolutas, las
desviaciones típicas, …), y sobre todo, no está en la forma que queremos
para comparar en un gráfico las notas de chicos y chicas. Para ello
necesitamos que la nota media de chicos y chicas este en sendas
variables, y que las CCAA sean las observaciones. Ahora las
observaciones son las combinaciones de sexo y CCAA.
Este tipo de tareas de manipulación de datos se hace de forma muy
eficiente con las funciones contenidas en el paquete
tidyverse. pivot_wider sirve para pasar de
forma larga a ancha. En este caso especificamos qué
variable contiene los nombres de las nuevas columnas
(names_from=sex) y cuál contiene los valores (en nuestro
caso values_from=Mean). Pero antes, tenemos que seleccionar
las columnas que nos interese con select.
En R es muy normal concatenar manipulaciones de objetos. Si
se utiliza la notación habitual funcion(argumentos)
acabamos con código del tipo f3(f2(f1(arg1),arg2)) que son
muy difíciles de leer. El paquete tidyverse está pensado
para concatenar acciones con el operador después
(|>), que se puede sacar en RStudio con
ALT-MAYUSC-M. Lo puedes recordar como un triángulo
orientado. De este modo escribiríamos:
arg1 |> f1 |> f2(arg2) |> f3, mucho más claro.
Existe una versión antigua del operador despúes, %>%,
que podrás encontrar en ocasiones y, básicamente, es reemplazable por
|>.
Esfuérzate por comprender lo que hace el código:
matesw <- mates2018 |>
select(CCAA, sex, Mean) |>
pivot_wider(names_from=sex,values_from=Mean)
matesw
## # A tibble: 19 × 3
## CCAA Female Male
## <fct> <dbl> <dbl>
## 1 Andalusia 462. 473.
## 2 Aragon 495. 499.
## 3 Asturias 487. 494.
## 4 Balearic Islands 476. 489.
## 5 Basque Country 501. 498.
## 6 Canary Islands 456. 465.
## 7 Cantabria 492. 506.
## 8 Castile – La Mancha 475. 482.
## 9 Castile and Leon 497. 508.
## 10 Catalonia 490. 490.
## 11 Ceuta 415. 408.
## 12 Extremadura 467. 472.
## 13 Galicia 499 497.
## 14 La Rioja 490. 505.
## 15 Madrid 480. 491.
## 16 Melilla 425. 439.
## 17 Murcia 470. 477.
## 18 Navarra 500. 505.
## 19 Valencia 472. 475.
Estos datos ya están en la forma que queríamos. Por último, para no
poner los nombres de todas las CCAA en el gráfico, podemos seleccionar
unas cuántas para identificarlas. Con la función filter
seleccionamos las observaciones que nos interesan
mateswsel <- matesw |>
filter(CCAA %in% c("Castile and Leon", "Navarra","Extremadura","Madrid","Canary Islands","Basque Country","Ceuta","Melilla"))
mateswsel
## # A tibble: 8 × 3
## CCAA Female Male
## <fct> <dbl> <dbl>
## 1 Basque Country 501. 498.
## 2 Canary Islands 456. 465.
## 3 Castile and Leon 497. 508.
## 4 Ceuta 415. 408.
## 5 Extremadura 467. 472.
## 6 Madrid 480. 491.
## 7 Melilla 425. 439.
## 8 Navarra 500. 505.
ggplotEn R existen varios mecanismos para representar gráficamente
los datos. El más desarrollado es el paquete
[ggplot2](http://docs.ggplot2.org/current/) que forma parte deltidyverse`.
Existe una chuleta
en español.
La función básica es ggplot que requiere un primer
argumento con el objeto de datos (en nuestro caso) matesw,
y una declaración del aspecto del gráfico: qué va en cada eje.
A continuación, separados por + podemos añadir cosas al
gráfico, como puntos, líneas, texto, etc. Examina el código y trata de
comprender qué define cada línea.
ples <- matesw |> ggplot(aes(x=Female, y=Male)) +
geom_point() +
geom_point(data=mateswsel, color="red") +
geom_text(data=mateswsel,aes(label=CCAA), color="grey20") +
geom_abline(slope=1, intercept = 0) +
geom_abline(slope=1, intercept = 20, linetype = 2, color="grey") +
geom_abline(slope=1, intercept = -20, linetype = 2, color="grey") +
geom_text(x=435, y=465, label="Chicos +20 puntos", angle=45, color="grey", size=8) +
geom_text(x=465, y=435, label="Chicas +20 puntos", angle=45, color="grey", size=8) +
coord_fixed(xlim = c(400,510), ylim = c(400,510)) +
theme_bw() + ggtitle("PISA 2018 - Brecha de género en matemáticas") +
xlab("Nota media para chicas PISA 2018") +
ylab("Nota media para chicos PISA 2018")
Como ves, la instrucción anterior no genera el gráfico. Genera un
nuevo objeto ples, que aparece como de tipo lista
(list) en RStudio, pero que si preguntamos vemos
que corresponde a un gráfico ggplot
class(ples)
## [1] "gg" "ggplot"
Si no hacemos asignación, habría salido directamente el gráfico. La asignación es útil si queremos seguir configurando el gráfico añadiendo más información o configurando la que aparece. Lo podemos imprimir con:
ples
Vemos que el gráfico capta muy bien las diferencias entre hombres y mujeres en las CCAA españolas. Existen importantes diferencias entre CCAA, con los mejores resultados de matemáticas en Navarra (para chicas) y Castilla y León (para chicos) y los peores en Canarias, Ceuta y Melilla. Respecto a la brecha de género, en la mayor parte de los casos los chicos tienen media superior a las chicas. Las excepciones son Galicia y País Vasco, con buenas notas, y Ceuta con las peores notas para ambos sexos. En todos los casos las diferencias son menores de 20 puntos. En Castilla y León los resultados son buenos, mejores tanto para chicos como para chicas que en comunidades limítrofes como Madrid o Extremadura. Si comparamos con medias de países, nuestra región está al nivel de Finlandia, mientras que Ceuta está al nivel de Colombia.
Como véis, es posible hacer en R análisis sofisticados de
manera relativamente sencilla, y es muy sencillo poder comunicar los
resultados del análisis en formato html, pdf o
doc utilizando el formato RMarkdown. Para ello
sólo hace falta dar al botón de knit en
RStudio.
library(intsvy)
library(tidyverse)
load("esp2018.RData")
# España
mates2018 <- pisa.mean.pv(pvlabel = "MATH", by = c("CCAA", "sex"), data = esp2018)
matesw <- mates2018 |>
select(CCAA, sex, Mean) |>
pivot_wider(names_from=sex,values_from=Mean)
mateswsel <- matesw |>
filter(CCAA %in% c("Castile and Leon", "Navarra","Extremadura","Madrid","Canary Islands","Basque Country","Ceuta","Melilla"))
ples <- matesw |> ggplot(aes(x=Female, y=Male)) +
geom_point() +
geom_point(data=mateswsel, color="red") +
geom_text(data=mateswsel,aes(label=CCAA), color="grey20") +
geom_abline(slope=1, intercept = 0) +
geom_abline(slope=1, intercept = 20, linetype = 2, color="grey") +
geom_abline(slope=1, intercept = -20, linetype = 2, color="grey") +
geom_text(x=435, y=465, label="Chicos +20 puntos", angle=45, color="grey", size=8) +
geom_text(x=465, y=435, label="Chicas +20 puntos", angle=45, color="grey", size=8) +
coord_fixed(xlim = c(400,510), ylim = c(400,510)) +
theme_bw() + ggtitle("PISA 2018 - Brecha de género en matemáticas") +
xlab("Nota media para chicas PISA 2018") +
ylab("Nota media para chicos PISA 2018")
ples