Mostrar código.
cron <- read_xlsx("CRON_fin.xlsx")cron <- read_xlsx("CRON_fin.xlsx")Se carga el marco de datos CRONOS, CROss-National Online Survey (ESS 2023), de la European Social Survey, para realizar una exploración rápida del mismo siguiendo las indicaciones del módulo de estudio (Mas y Vall-Prat 2024) y otras fuentes complementarias (Wickham 2023). Se trata de un archivo que acumula las respuestas de múltiples rondas de encuestas organizadas por la ESS sobre el desarrollo social en Europa:
glimpse(cron)Rows: 6,032
Columns: 24
$ cntry <chr> "AT", "AT", "AT", "AT", "AT", "AT", "AT", "AT", "AT", "AT", "…
$ gndr <dbl> 1, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 1…
$ agea <dbl> 73, 41, 35, 55, 65, 27, 35, 20, 68, 51, 66, 56, 51, 67, 48, 3…
$ eduyrs <dbl> 11, 13, 14, 12, 12, 21, 20, 14, 25, 14, 13, 16, 13, 11, 25, 1…
$ eisced <dbl> 3, 6, 5, 3, 2, 6, 7, 4, 7, 5, 3, 4, 5, 3, 55, 3, 7, 5, 3, 3, …
$ hincfel <dbl> 1, 2, 1, 1, 1, 2, 2, 3, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2…
$ hinctnta <dbl> 10, 77, 3, 77, 7, 77, 6, 8, 8, 7, 5, 7, 8, 7, 5, 5, 8, 6, 10,…
$ netusoft <dbl> 5, 5, 5, 4, 5, 5, 5, 5, 5, 4, 5, 5, 5, 2, 5, 5, 5, 5, 5, 3, 4…
$ region <chr> "AT32", "AT22", "AT22", "AT34", "AT12", "AT31", "AT31", "AT12…
$ w4q1 <dbl> 4, 4, 4, 3, 4, 4, 5, 3, 3, 3, 4, 4, 4, 2, 4, 4, 4, 4, 4, 3, 3…
$ w4q2 <dbl> 4, 4, 5, 3, 5, 4, 3, 3, 2, 4, 4, 3, 4, 3, 4, 5, 4, 4, 4, 3, 3…
$ w4q3 <dbl> 3, 3, 4, 3, 3, 2, 1, 1, 4, 3, 2, 4, 3, 3, 2, 1, 3, 1, 2, 2, 3…
$ w4q4 <dbl> 3, 4, 3, 3, 4, 3, 4, 2, 3, 2, 3, 3, 4, 2, 3, 1, 2, 4, 3, 2, 3…
$ w4q5 <dbl> 4, 4, 5, 4, 5, 4, 5, 4, 3, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 4, 3…
$ w4q6 <dbl> 5, 4, 5, 4, 5, 4, 5, 5, 4, 4, 5, 5, 5, 5, 5, 5, 5, 4, 5, 3, 4…
$ w4q7 <dbl> 4, 2, 4, 2, 5, 2, 3, 3, 2, 2, 3, 2, 2, 2, 1, 2, 3, 2, 2, 4, 3…
$ w4q8 <dbl> 4, 4, 2, 4, 5, 4, 5, 4, 4, 3, 5, 3, 2, 2, 5, 1, 4, 4, 2, 3, 4…
$ w4q9 <dbl> 5, 4, 4, 4, 5, 4, 5, 5, 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 4, 4, 3…
$ w4q10 <dbl> 4, 3, 5, 4, 4, 3, 5, 3, 2, 3, 4, 4, 4, 3, 3, 4, 4, 4, 4, 2, 4…
$ w4q11 <dbl> 5, 3, 5, 2, 1, 2, 3, 3, 2, 3, 5, 2, 3, 4, 1, 3, 4, 1, 4, 3, 3…
$ w4q12 <dbl> 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 4, 3, 4, 4, 4, 4, 4, 3, 4, 3, 2…
$ w4q13 <dbl> 5, 4, 2, 4, 5, 4, 4, 5, 4, 3, 5, 4, 5, 4, 5, 5, 3, 4, 4, 4, 3…
$ w4q14 <dbl> 5, 4, 3, 4, 5, 4, 5, 4, 4, 4, 5, 5, 5, 4, 5, 5, 4, 4, 4, 4, 3…
$ w4q15 <dbl> 4, 4, 3, 4, 5, 4, 4, 2, 4, 3, 4, 5, 3, 4, 4, 5, 4, 4, 4, 3, 3…
La función glimpse() permite visualizar un resumen compacto del marco que ofrece el número total de observaciones (6032) y variables (24), así como el nombre y vector de éstas últimas, dos datos clave para identificar su tipo:
cntry y region: país y región. Variables categóricas nominales no ordenables ni operables.gndr: género. Variable categórica nominal sin significado cuantitativo, ya que las opciones que puede tomar (“masculino”, “femenino” o “sin respuesta”) no se ordenan según su nivel.agea y eduyrs: edad y años educación. Variables numéricas de ratio operables en las que el valor 0 aporta información.El resto, incluyendo eisced (nivel educativo), hincfel (satisfacción ingresos), hinctnta (nivel ingresos). netusoft (uso internet) y las 15 w4q, son categóricas ordinales porque posicionan el abanico de respuestas siguiendo un orden ascendente asociado a unos valores numéricos preestablecidos en el libro de códigos.
Por último, la unidad de observación es país-región-género-edad-años educación (cntry-region-gndr-agea-eduyrs) puesto que, si se retira alguna de las variables citadas, ya no es posible identificar cada una de las filas de manera unívoca. Este hecho se puede comprobar mediante la función filter():
cron |>
filter(cntry == "AT" & region == "AT32" & gndr == "2" & agea == "34")# A tibble: 2 × 24
cntry gndr agea eduyrs eisced hincfel hinctnta netusoft region w4q1 w4q2
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
1 AT 2 34 14 7 2 6 5 AT32 2 5
2 AT 2 34 13 3 2 10 5 AT32 4 4
# ℹ 13 more variables: w4q3 <dbl>, w4q4 <dbl>, w4q5 <dbl>, w4q6 <dbl>,
# w4q7 <dbl>, w4q8 <dbl>, w4q9 <dbl>, w4q10 <dbl>, w4q11 <dbl>, w4q12 <dbl>,
# w4q13 <dbl>, w4q14 <dbl>, w4q15 <dbl>
Como muestra la tabla reducida que se ha obtenido, existen observaciones distintas sobre personas del mismo género y edad que habitan en la misma región de un mismo país, haciendo necesaria la presencia de eduyrs a modo de característica diferenciadora.
Con el soporte del libro de códigos adjunto al marco de datos, se profundiza en un análisis más detallado:
w4q13 hace referencia a la “protección de los derechos humanos” y una forma sencilla de valorar las respuestas que se han recogido es mediante una tabla de frecuencias, constituida con la función count():cron |>
count(w4q13, sort = T)# A tibble: 6 × 2
w4q13 n
<dbl> <int>
1 5 3370
2 4 2094
3 3 429
4 2 68
5 9 54
6 1 17
Se ha añadido el argumento sort para ordenar descendentemente las frecuencias. Así, se aprecia que la moda, o frecuencia más repetida, es el valor 5, que corresponde a la categoría “máxima prioridad”, apareciendo a continuación el resto de opciones ordenadas tanto en frecuencia de respuestas como en el grado de importancia otorgado respecto a lo que se pregunta. La única excepción es el valor 9 (“sin respuesta”), cuya frecuencia es superior a la del 1 (“ninguna prioridad”).
table(), en este caso para la variable cntry, además de representarlas en un gráfico de barras con barplot():barplot(table(cron$cntry), col = "skyblue", border = "darkblue", main = "Frecuencias absolutas por países")La moda de la distribución es SE (Suecia), que supera las 800 observaciones, seguida de FI (Finlandia) y FR (Francia) con más de 700 en cada caso. En el otro extremo destacan IT (Italia) y CZ (República Checa), que traspasan la barrera de las 200.
w4q3 sobre “enfatizar los valores religiosos”, ordenada en una escala del 1 al 5 según el grado ascendente de relevancia, se filtra para mostrar solamente las respuestas de Francia, Suecia y Portugal en la tabla de frecuencias:cron |>
filter(cntry %in% c("PT", "FR", "SE")) |>
count(cntry, w4q3) # A tibble: 18 × 3
cntry w4q3 n
<chr> <dbl> <int>
1 FR 1 355
2 FR 2 140
3 FR 3 147
4 FR 4 51
5 FR 5 16
6 FR 9 15
7 PT 1 96
8 PT 2 89
9 PT 3 139
10 PT 4 49
11 PT 5 17
12 PT 9 6
13 SE 1 312
14 SE 2 309
15 SE 3 159
16 SE 4 48
17 SE 5 9
18 SE 9 8
No obstante, la aparición conjunta de los 3 países y sus tamaños de muestra diferentes hacen incómoda la visualización, siendo preferible apostar por tres tablas individuales a las que se les añade con mutate() la columna adyacente per, recogiéndose en ella las frecuencias relativas a modo de porcentaje:
cron |>
filter(cntry == "FR") |>
count(cntry, w4q3) |>
mutate(per = round(n / sum(n) * 100, 1))# A tibble: 6 × 4
cntry w4q3 n per
<chr> <dbl> <int> <dbl>
1 FR 1 355 49
2 FR 2 140 19.3
3 FR 3 147 20.3
4 FR 4 51 7
5 FR 5 16 2.2
6 FR 9 15 2.1
FR (Francia): cerca de la mitad de las observaciones no da prioridad alguna a los valores religiosos y otro 19,3% le da poca, es decir, alrededor de un 70% del total.cron |>
filter(cntry == "SE") |>
count(cntry, w4q3) |>
mutate(per = round(n / sum(n) * 100, 1))# A tibble: 6 × 4
cntry w4q3 n per
<chr> <dbl> <int> <dbl>
1 SE 1 312 36.9
2 SE 2 309 36.6
3 SE 3 159 18.8
4 SE 4 48 5.7
5 SE 5 9 1.1
6 SE 9 8 0.9
SE (Suecia): el agregado de 1 y 2, que abarca casi tres cuartas partes de las respuestas, otorga equitativamente o ninguna o poca prioridad a la religión.cron |>
filter(cntry == "PT") |>
count(cntry, w4q3) |>
mutate(per = round(n / sum(n) * 100, 1))# A tibble: 6 × 4
cntry w4q3 n per
<chr> <dbl> <int> <dbl>
1 PT 1 96 24.2
2 PT 2 89 22.5
3 PT 3 139 35.1
4 PT 4 49 12.4
5 PT 5 17 4.3
6 PT 9 6 1.5
PT (Portugal): el grupo mayoritario es un 35,1% que le da prioridad media a la religión, una cifra que sumada al 12,4% que le da mucha y al 4,3% que la sube a máxima, supera el 50%. En consecuencia, dicho bloque ideológico domina frente al 24,2% y el 22,5% que le da o nula o poca, respectivamente.Los resultados del país luso señalan que la fe está más arraigada entre la población que en los casos de Francia y Suecia, dos sociedades donde la religión ha perdido fuerza como ideal de bienestar.
w4q15 para el “fortalecimiento de los lazos sociales”, simplificando el código del apartado anterior es posible averiguar el porcentaje, o frecuencia relativa, de personas que opinan que es un asunto de máxima prioridad:cron |>
count(w4q15) |>
mutate(per = round(n / sum(n) * 100, 1))# A tibble: 6 × 3
w4q15 n per
<dbl> <int> <dbl>
1 1 19 0.3
2 2 150 2.5
3 3 1379 22.9
4 4 3101 51.4
5 5 1313 21.8
6 9 70 1.2
El dato asciende al 21,8% de los encuestados (1313 respuestas).
w4q1, asociada a “erradicar la pobreza”, basta con recuperar la función count() para conocer la moda:cron |>
count(w4q1, sort = T)# A tibble: 6 × 2
w4q1 n
<dbl> <int>
1 4 3067
2 5 1890
3 3 896
4 2 117
5 1 42
6 9 20
La frecuencia más representada es la categoría 4, “alta prioridad”, con 3067 observaciones.
Ya mencionada anteriormente, la variable eduyrs (años educación) puede servir como ejemplo del cálculo de otras medidas de centralidad:
mean(): la media es el promedio del sumatorio de los valores dividido entre el total de casos.median(): la mediana es el elemento central de un conjunto ordenado.Para obtenerlas, se procede con la función group_by() que muestra los resultados según la unidad de observación escogida (cntry), summarize() que aglutina variables enteras en una única cifra (eduyrs) y na.rm que descarta los datos perdidos:
cron |>
group_by(cntry) |>
summarize(media = mean(eduyrs, na.rm = T),
mediana = median(eduyrs, na.rm = T))# A tibble: 11 × 3
cntry media mediana
<chr> <dbl> <dbl>
1 AT 15.8 14
2 BE 15.3 15
3 CZ 17.1 13
4 FI 15.8 16
5 FR 15.1 14
6 GB 15.7 16
7 IS 16.9 17
8 IT 15.5 14
9 PT 13.7 12
10 SE 16.4 14
11 SI 14.5 14
La media más baja corresponde a Portugal con 13,7 años y la más alta a República Checa con 17,1. No obstante, mientras en el primer caso la mediana es representativa al tomar un valor cercano (12), en el segundo se aleja notablemente (13). Este hecho indica que existen observaciones atípicas en el extremo superior de la distribución, empujando el cálculo de la media hacia arriba.
filter() y el argumento != de no igualdad, es posible limitar el rango de las variables, eliminando inespecifidades como 77 (“rechaza”), 88 (“no sabe”) o 99 (“sin respuesta”):cron_2 <- cron |>
filter(eduyrs != 77 & eduyrs != 88 & eduyrs != 99)
cron_2# A tibble: 5,963 × 24
cntry gndr agea eduyrs eisced hincfel hinctnta netusoft region w4q1 w4q2
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
1 AT 1 73 11 3 1 10 5 AT32 4 4
2 AT 2 41 13 6 2 77 5 AT22 4 4
3 AT 1 35 14 5 1 3 5 AT22 4 5
4 AT 1 55 12 3 1 77 4 AT34 3 3
5 AT 2 65 12 2 1 7 5 AT12 4 5
6 AT 2 27 21 6 2 77 5 AT31 4 4
7 AT 2 35 20 7 2 6 5 AT31 5 3
8 AT 2 20 14 4 3 8 5 AT12 3 3
9 AT 1 68 25 7 1 8 5 AT12 3 2
10 AT 1 51 14 5 1 7 4 AT21 3 4
# ℹ 5,953 more rows
# ℹ 13 more variables: w4q3 <dbl>, w4q4 <dbl>, w4q5 <dbl>, w4q6 <dbl>,
# w4q7 <dbl>, w4q8 <dbl>, w4q9 <dbl>, w4q10 <dbl>, w4q11 <dbl>, w4q12 <dbl>,
# w4q13 <dbl>, w4q14 <dbl>, w4q15 <dbl>
Se efectúa el cambio propuesto sobre eduyrs y se registra en un nuevo objeto llamado cron_2, que cuenta con 69 observaciones menos que el original.
cron_2, se plantea un diagrama de cajas para analizar la distribución de eduyrs por países mediante la herramienta geom_boxplot() del paquete ggplot2, añadiendo instrucciones adicionales para personalizar el diseño:cron_2 |>
ggplot(aes(x = cntry, y = eduyrs)) +
geom_boxplot(fill = "skyblue", color = "darkblue") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
labs(title = "Años de educación por países",
x = "",
y = "") +
scale_x_discrete(labels = c("AT" = "Austria", "BE" = "Bélgica", "CZ" = "Rep. Checa", "FI" = "Finlandia",
"FR" = "Francia", "GB" = "Reino Unido", "IS" = "Islandia", "IT" = "Italia",
"PT" = "Portugal", "SE" = "Suecia", "SI" = "Eslovenia"))Cada caja representa el rango intercuartílico, es decir, la amplitud entre el 25% y el 75% del tamaño total de la muestra de cada país. La mediana, en forma de línea gruesa, marca el centro de los conjuntos, los bigotes verticales definen la tendencia de los casos fuera del rango y los puntos son las observaciones atípicas cuyo valor se aleja del resto.
El rango intercuartílico y la mediana más elevados pertenecen a Islandia y los más bajos a Portugal. Pese a que el diagrama de cajas no ofrece el dato exacto de la media, se puede inferir que, en base al nuevo marco cron_2, Portugal se mantiene como el país con menor cantidad de años de educación, pero República Checa pierde posiciones y cede el primer puesto a Islandia.
Se aprecian países con respuestas más dispersas que se traducen en un rango amplio, véase el propio Portugal o Reino Unido. En contraposición, las de Bélgica, República Checa, Francia y Suecia se concentran en menos espacio. Igualmente, países como Reino Unido tienen pocos casos atípicos pero de valores extremos, mientras en Francia, Islandia o Suecia hay muchos pero no tan distanciados del centro.
Finalizado el estudio de CRONOS, vale la pena centrar la atención en el marco gapminder (Gapminder 2024) contenido en el paquete dslabs. Se trata de un proyecto que recopila datos sobre el desarrollo de los países en ámbitos diversos.
gap <- tibble(dslabs::gapminder)glimpse(gap)Rows: 10,545
Columns: 9
$ country <fct> "Albania", "Algeria", "Angola", "Antigua and Barbuda"…
$ year <int> 1960, 1960, 1960, 1960, 1960, 1960, 1960, 1960, 1960,…
$ infant_mortality <dbl> 115.40, 148.20, 208.00, NA, 59.87, NA, NA, 20.30, 37.…
$ life_expectancy <dbl> 62.87, 47.50, 35.98, 62.97, 65.39, 66.86, 65.66, 70.8…
$ fertility <dbl> 6.19, 7.65, 7.32, 4.43, 3.11, 4.55, 4.82, 3.45, 2.70,…
$ population <dbl> 1636054, 11124892, 5270844, 54681, 20619075, 1867396,…
$ gdp <dbl> NA, 13828152297, NA, NA, 108322326649, NA, NA, 966778…
$ continent <fct> Europe, Africa, Africa, Americas, Americas, Asia, Ame…
$ region <fct> Southern Europe, Northern Africa, Middle Africa, Cari…
Con un vistazo rápido se detecta que dispone de una buena cantidad de observaciones (10545) pero no de excesivas variables (9). Sin embargo, destaca la aparición de numerosos valores codificados como NA, por lo se ejecuta la función vis_miss() del paquete naniar que dibuja una suerte de código de barras de los datos perdidos:
vis_miss(gap)El reparto se produce entre 4 variables: infant_mortality (14%), fertility (2%), population (2%) y gdp (28%). No obstante, en el caso de la primera y la última, la distribución es relativamente uniforme a lo largo de la muestra para acabar concentrándose en las últimas observaciones, característica que comparten también las otras dos variables, carentes de datos únicamente en ese tramo.
gapminder es la variable fertility (fertilidad), un indicador demográfico que mide el promedio de hijos nacidos vivos por mujer de edad entre 15 y 49 años.Se seleccionan dos países, en este caso España y Luxemburgo (mis países de nacimiento y residencia, respectivamente) y se traza un diagrama de líneas con geom_line(), personalizado mediante el uso de diversos argumentos estéticos, que plantea la evolución de la tasa de fertilidad en los países escogidos desde 1966 hasta 2016:
gap |>
filter(country == "Spain" | country == "Luxembourg") |>
filter(year >= 1966, year <= 2016) |>
ggplot(aes(x = year, y = fertility, col = country)) +
geom_line() +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
labs(title = "Fertilidad en España y Luxemburgo (1966-2016)",
x = "",
y = "",
col = "Países") +
scale_color_manual(values = c("Spain" = "orangered", "Luxembourg" = "purple"),
labels = c("Spain" = "España", "Luxembourg" = "Luxemburgo"))Ambos índices sufrieron una caída pronunciada en el último tercio del siglo XX, especialmente el español, más fuerte y prolongada debido a las décadas perdidas durante la dictadura, la apertura tardía a Europa y, con ella, multitud de cambios en las dinámicas sociales, culturales y familiares. En Luxemburgo también cayó, pero se frenó y comenzó a aplanarse años antes, motivado también por un punto de partida más discreto, de alrededor de 2,3 nacimientos en 1966 frente a los casi 3 de España.
Actualmente, ambos países cuentan con unas cifras muy bajas, ligeramente superiores al 1,5. El caso luxemburgués lo explica la propia idiosincrasia del país, con un 70% de población expatriada, en muchos casos centrada en progresar laboralmente y alejada del estereotipo de familia tradicional. Del lado español, una mayoría de personas en edad fértil se enfrentan a precariedad profesional y económica, dificultades para independizarse y, en consecuencia, no reúnen las condiciones para tener hijos.
ggplot2 cuenta con herramientas para profundizar en el diseño visual de las representaciones. Utilizando el mismo conjunto de datos del apartado anterior, se propone un histograma con un facet:gap |>
filter(country == "Spain" | country == "Luxembourg") |>
filter(year >= 1966, year <= 2016) |>
ggplot(aes(x = year, y = fertility, fill = country)) +
facet_wrap(~ country) +
geom_col(color = "black") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
labs(title = "Fertilidad en España y Luxemburgo (1966-2016)",
x = "",
y = "",
fill = "Países") +
scale_fill_manual(values = c("Spain" = "salmon", "Luxembourg" = "plum"),
labels = c("Spain" = "España", "Luxembourg" = "Luxemburgo")) +
theme(strip.text = element_blank())life_expectancy) con el paso de los años (year) en China, Nigeria, Singapur y Suiza?gap |>
filter(country == "China" | country == "Nigeria" | country == "Singapore" | country == "Switzerland") |>
ggplot(aes(x = year, y = life_expectancy, color = country)) +
geom_point() +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
labs(title = "Evolución de la esperanza de vida (1960-2016)",
x = "",
y = "",
color = "Países") +
scale_x_continuous(breaks = c(1960, 1970, 1980, 1990, 2000, 2010, 2016)) +
scale_color_manual(values = c("China" = "red", "Nigeria" = "darkgreen", "Singapore" = "gold", "Switzerland" = "brown"),
labels = c("Singapore" = "Singapur", "Switzerland" = "Suiza"))La mejora en los hábitos de vida y los avances tecnológicos y médicos en los últimos 60 años han contribuido a impulsar muy sustancialmente la esperanza de vida en países como Nigeria, aunque el continente africano sigue teniendo camino por recorrer.
El caso de China es distinto, convertida en potencia mundial en la actualidad pero cuya población rural, de alrededor de 500 millones de personas, limita en parte la velocidad a que podría progresar el indicador.
Singapur se ha convertido en las últimas décadas en uno de los mayores centros tecnológicos del mundo, con los mejores índices demográficos y económicos del Sudeste Asiático.
Y para terminar, Suiza no sorprende, pues ocupa los primeros puestos en todas las listas de desarrollo a nivel mundial.