Este es un ejemplo de fichero R markdown que te sirve para aprender varias cosas:

Introducción

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.

Análisis previo de los datos

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")

Cargar los paquetes y los datos

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:

  1. Cambiar la carpeta por defecto de RStudio navegando hasta la que contiene el fichero en la pestaña 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.
  2. Cargar el fichero buscándolo desde el botón de cargar de la pestaña 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.

Análisis de datos: Cálculo de medias para encuestas complejas con intsvy

Una 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.

Transformación de datos: De formato largo a ancho

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.

Gráficos ggplot

En 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

Análisis de resultados

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.

Código completo

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