-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhist4_paises_demog.qmd
453 lines (327 loc) · 16.9 KB
/
hist4_paises_demog.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
---
title: "¡Nos vamos a Noruega!"
author:
- Gema Fernández-Avilés ([email protected])
- Isidro Hidalgo ([email protected])
format:
html:
theme: cerulean
highlight-style: ayu-mirage
self-contained: true
lang: es
date: 01/16/2025
date-format: long
embed-resources: true
toc-title: Summary
toc: true
number-sections: true
preview-links: auto
code-link: true
code-fold: true
number-sections: true
execute:
echo: true
eval: true
output: true
include: true
freeze: auto
fig-height: 5
warning: false
comment: "#>"
code-line-numbers: true
code-copy: true
code-overflow: scroll
code-fold: true
---
::: {.callout-note}
Los datos que se utilizan en esta historia están disponibles en el repositorio GitHub "From data to viz": https://github.com/holtzy/data_to_viz.
:::
# ¡Nos vamos a Noruega!
Mi jefe quiere que le haga un análisis exploratorio (eso dice, pero siempre quiere gráficos guays con conclusiones interesantes...) de unos datos demográficos por países. Lo peor es que quiere que le acompañe a Noruega, que hay un workshop "fantástico" [sic]...
Con el frío que hace ahora en Noruega... Pero este hombre, ¿por qué no elige estas cosas con más criterio y nos vamos a Hawai? ¡Por ejemplo!
# Entender el contexto
::: {.callout-tip}
## Cómo definir el propósito y la audiencia de tu análisis
En este caso, puesto que lo que me pide el jefe es un análisis exploratorio, se trata simplemente de encontrar relaciones interesantes entre variables, mirar su evolución, por si se ven cosas interesantes, y preparar gráficos que vayan al grano, como ya sabemos hacer... ¡Que para algo sirven los cursos de la UCLM!
:::
```{r}
#| code-summary: Lectura de paquetes necesarios
library(tidyverse)
library(GGally)
library(NbClust)
library(igraph)
library(factoextra)
library(corrplot)
library(explore)
```
```{r}
#| code-summary: Lectura de datos formato `csv` en local desde la carpeta `data`
demog_data <- read.table("data/multivariate.csv", header = T, sep = ";")
```
```{r}
#| code-summary: Lectura de datos formato `csv` directamente desde la web
demog_data <- read.table("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/multivariate.csv", header = T, sep = ";")
```
```{r}
#| code-summary: Estilo de código. Cambio los puntos por guiones
colnames(demog_data) <- gsub("\\.", "_", colnames(demog_data))
colnames(demog_data)
```
```{r}
#| code-summary: Renombra la 9 variable eliminando el último guión
names(demog_data)[9] <- "Population_aged_65"
```
```{r}
#| code-summary: Primera vista de los datos
head(demog_data, 3)
```
::: {.callout-important title="Tu turno"}
Completa las partes del código señaladas por `_____` o `xxxxx` para obtener el resultado propuesto. ¿Te acuerdas de las funciones para explorar todas las variables a la vez?
:::
```{r}
#| code-summary: Exploración básica
#| eval: false
demog_data |> xxxxxxx_all()
```
```{r}
#| echo: false
demog_data |> explore_all()
```
```{r}
#| code-summary: Resumen
#| echo: false
summary(demog_data)
```
```{r}
#| eval: false
xxxxxxx(demog_data)
```
# Elegir una visualización adecuada
::: {.callout-tip}
## Selección de gráficos y visualizaciones que mejor representen tus datos.
:::
## Matriz diagramas de dispersión (*scatterplot matrix*)
Podemos comenzar por una matriz de puntos de las variables cuantitativas. El paquete `GGally` ofrece una visualización muy elaborada para un primer vistazo con la función `ggpairs()`...
::: {.callout-tip}
## Cuidado: solo variables cuantitativas.
:::
```{r}
#| code-summary: Selecciona las variables cuantitativas
demo_cuanti <- demog_data |>
select(Pop, Birth_rate, Mortality_rate, Life_expectancy,
Infant_mortality, Children_per_woman, Growth_rate,
Population_aged_65) |>
na.omit()
```
```{r}
#| code-summary: Matriz de correlaciones y diagramas de dispersión
demo_cuanti |>
ggpairs(progress = FALSE)
```
Hay muchas asociaciones interesantes entre diferentes variables. Aquí ya vemos mucha tela que cortar. Por no extendernos, analizaremos una de las relaciones más adelante. Pero primero, es muy interesante ver la matriz de correlaciones que, aunque con `ggpairs()` teníamos ya una primera impresión, el paquete `corrplot` nos ofrece una visualización ideal con la función `corrplot.mixed()`:
## Matriz de correlaciones
```{r}
#| code-summary: Matriz de correlaciones
demo_cuanti |>
cor() |>
corrplot.mixed( order = 'AOE')
```
## Gráfico de puntos entre o scatterplot `Growth_rate` y `Life_expectancy`
Como ejemplo, vamos a ver la relación entre la esperanza de vida y la tasa de crecimiento, que ya hemos visto que existe. Empecemos con un gráfico de puntos...
::: {.callout-important title="Tu turno"}
Completa las partes del código señaladas por `_____` o `xxxxx` para obtener el resultado propuesto. ¿Te acuerdas de la función de `ggplot2` para una capa de puntos?
:::
```{r}
#| code-summary: Diagrama de dispersión
#| eval: false
demog_data |>
ggplot(aes(x = Growth_rate, y = Life_expectancy)) +
geom_xxxxx) +
labs(title = "Esperanza de vida vs. Tasa de crecimiento",
x = "Tasa de crecimiento",
y = "Esperanza de vida") +
theme_minimal()
```
```{r}
#| code-summary: Diagrama de dispersión
#| echo: false
demog_data |>
ggplot(aes(x = Growth_rate, y = Life_expectancy)) +
geom_point() +
labs(title = "Esperanza de vida vs. Tasa de crecimiento",
x = "Tasa de crecimiento",
y = "Esperanza de vida") +
theme_minimal()
```
```{r}
#| code-summary: Hexbin plot
demog_data |>
ggplot(aes(x = Growth_rate, y = Life_expectancy)) +
geom_hex() +
labs(title = "Esperanza de vida vs. Tasa de crecimiento",
x = "Tasa de crecimiento",
y = "Esperanza de vida") +
theme_minimal()
```
# Eliminar el desorden. Enfocar la atención
En el gráfico anterior no se ve casi nada... solo una ligera tendencia parabólica, pero no sabemos nada de los puntos, ese gráfico aporta poco.
¿Qué herramientas tenemos a nuestro alcance para poner el foco sobre lo que nos interesa? Aquí podemos usar la estética y las facetas, para separar los puntos y dar más información a través de la visualización. Veamos...
## Herramienta 1: la estética
```{r}
#| code-summary: Diagrama de dispersión mejorado por estética
demog_data |>
ggplot(aes(x = Growth_rate, y = Life_expectancy, size = Pop,
color = Continent)) +
geom_point(alpha=0.5) +
scale_size(range = c(.1, 20)) +
labs(title = "De Europa a Norteamérica, Oceanía, Sudamérica y África, a través de Asia",
x = "Tasa de crecimiento",
y = "Esperanza de vida") +
theme_minimal() +
theme(axis.title.x = element_text(hjust = 0),
axis.title.y = element_text(hjust = 1))
```
Estamos usando **dos variables para enfocar la atención aportando información: el tamaño del país y el continente**. Solo con eso vemos enseguida por donde van los tiros: la mayor parte de los países de Europa tienen gran esperanza de vida y crecimiento moderado. Por el contrario, Sudamérica tiene tasas de crecimiento muy elevadas (son países en fases de expansión económica) y una menor esperanza de vida, a falta de consolidar sanidad y otros servicios en general.
También somos capaces de identificar China e India rápidamente, por su tamaño, y Japón arriba a la izquierda por su tamaño medio-grande y enorme esperanza de vida.
Sin embargo, hay colores muy parecidos, que exigen demasiada atención. Podemos usar la siguiente herramienta...
## Herramienta 2: facetas
Otra forma de eliminar el desorden y enfocar la atención es usar facetas, separando el gráfico según una o más variables interesantes. En este caso usamos solo el continente:
```{r}
#| code-summary: Diagrama de dispersión mejorado por facetas
demog_scatter <- ggplot(data = demog_data, # data
aes(x = Growth_rate, y = Life_expectancy, colour = Continent)) + #aesthetics
geom_point(alpha = 0.5) + #geometries
facet_wrap(~ Continent, scales = "free") + #facets
labs(title = "Life expectancy at birth vs. Per capita GDP",
x = "Growth_rate", y = "Life_expectancy", colour = "Continent") + #labels
theme_light() #themes
demog_scatter
```
::: {#exr-1}
¿Qué problema podría tener este gráfico?
:::
::: {.callout-tip}
## Pista
¡fijaos en los ejes!
:::
Exacto: las escalas. Pero hemos dicho "podría", no que tenga un problema en sí. Cuando nuestra intención es mirar dentro de cada faceta para ver la relación entre las variables, es posible que nos interese dejarlo como está.
Pero muchas veces es muy importante, cuando usamos facetas, que podamos comparar los diferentes grupos entre sí. En este caso, es imprescindible usar la misma escala en todas las facetas. Para ello, hay que especificar los límites de las escalas de los ejes.
¿Existe una forma fácil de saber cuáles poner? Claro, con un `summary()` de las variables, tal como indicamos a continuación, vemos rápidamente el valor mínimo y máximo de las variables que nos interesan:
```{r}
#| code-summary: Mejoramos la escala para comparar facetas
summary(demog_data$Life_expectancy)
summary(demog_data$Growth_rate)
demog_scatter_escala <- ggplot(data = demog_data,
aes(x = Growth_rate,
y = Life_expectancy,
colour = Continent)) +
geom_point(alpha = 0.5) +
facet_wrap(~ Continent, scales = "free") +
labs(title = "Esperanza de vida respecto al PIB per capita",
x = "Tasa de crecimiento", y = "Esperanza de vida",
colour = "Continent") +
scale_x_continuous(limits = c(-10, 45)) +
scale_y_continuous(limits = c(45, 85)) +
theme_light()
demog_scatter_escala
```
## Linea de suavizado
A veces, si hay una tendencia evidente, es conveniente usar una línea de suavizado que la identifique. En este caso, no está nada clara, por lo que la podemos omitir. Y aquí sí es interesante dejar libre la escala, para maximizar la visualización de la tendencia, que es lo que nos interesa:
::: {.callout-important title="Tu turno"}
Completa las partes del código señaladas por `_____` o `xxxxx` para obtener el resultado propuesto. ¿Qué objeto tienes que incluir sobre el que añadir la línea de tendencia?
:::
```{r}
#| code-summary: Añadimos línea de suavizado
#| eval: false
______ + geom_smooth(method = NULL, se = TRUE)
```
```{r}
#| code-summary: Añadimos línea de suavizado
#| echo: false
demog_scatter + geom_smooth(method = NULL, se = TRUE)
```
<!-- ## Técnicas de segmentación: -->
<!-- ### Cluster jerarquizado -->
<!-- Una forma de usar las variables en el análisis exploratorio es agrupar los registros haciendo segmentación. Los clusters se prestan a visualizaciones muy sofisticadas, pero hay que tener cuidado de simplificarlas, porque si no el desorden puede estropear el mensaje. Veamos qué podemos hacer... -->
<!-- ```{r} -->
<!-- #| code-summary: preparamos los datos para el clúster -->
<!-- cluster_data <- demog_data |> -->
<!-- select(Country) |> # añade esta variable a las cuantitativas -->
<!-- cbind(demo_cuanti) |> -->
<!-- column_to_rownames(var = "Country") -->
<!-- head(cluster_data) -->
<!-- ``` -->
<!-- Ahora ya podemos empezar la segmentación. Lo primero es estandarizar las variables para impedir que las de mayor rango (distancia entre mínimo y máximo) acaparen demasiado protagonismo... -->
<!-- ```{r} -->
<!-- #| code-summary: estandarizamos y calculamos las distancias -->
<!-- cluster_data_stand <- scale(cluster_data) -->
<!-- d_euclidea <- get_dist(x = cluster_data_stand, -->
<!-- method = "euclidea") -->
<!-- fviz_dist(dist.obj = d_euclidea, lab_size = 5) -->
<!-- ``` -->
<!-- Se aprecian agrupaciones entre países, pero... -->
<!-- ::: {#exr-1} -->
<!-- ...aquí se ve muy poco, de tanta información que hay... ¿qué variable es la culpable? -->
<!-- ::: -->
<!-- Aquí conviene hacerse una pregunta: ¿es suficiente agrupar los países por la variable `Group`, que va asociada a la ubicación del país? Si es así, calculamos las medias de las variables por grupo y simplificamos mucho la visualización. Si es imprescindible usar el país, hay que apechugar, porque no hay forma de evitar más de 200 registros... -->
<!-- ```{r} -->
<!-- #| code-summary: probamos la segmentación por grupos de países -->
<!-- cluster_data_group <- demog_data |> -->
<!-- select(Group) |> # añade esta variable a las cuantitativas -->
<!-- cbind(demo_cuanti) |> -->
<!-- group_by(Group) |> -->
<!-- mutate(across(where(is.numeric), mean)) |> -->
<!-- unique() -->
<!-- cluster_data_group <- data.frame(cluster_data_group, -->
<!-- row.names = 1) -->
<!-- cluster_data_group_stand <- scale(cluster_data_group) -->
<!-- d_euclidea_group <- get_dist(x = cluster_data_group_stand, -->
<!-- method = "euclidea") -->
<!-- fviz_dist(dist.obj = d_euclidea_group, lab_size = 5) -->
<!-- ``` -->
<!-- El resultado es mucho más claro pero, lógicamente, a costa de perder información. En este caso, probablemente se pueda hacer un filtrado de países por grupo, descartando los que nos interesan menos; o centrarnos en una zona geográfica que nos interese más. -->
<!-- ```{r} -->
<!-- #| code-summary: estimación del k óptimo -->
<!-- set.seed(2025) -->
<!-- num_cluster <- NbClust(cluster_data_stand, distance = "euclidean", method = "ward.D2", min.nc = 2, max.nc = 10) -->
<!-- num_cluster$Best.nc -->
<!-- head(num_cluster$Best.partition) -->
<!-- table(num_cluster$Best.partition) -->
<!-- ``` -->
<!-- El codo del gráfico se sitúa en k = 6, por lo que usaremos una segmentación de 6 grupos. -->
<!-- ```{r} -->
<!-- hc_ward <- hcut(cluster_data_stand , k = 6, hc_method = "ward.D2") -->
<!-- fviz_dend(hc_ward, cex = 0.5, k = 6, main = "Cluster jerárquico simple") -->
<!-- ``` -->
<!-- Ya lo habíamos advertido: cuando usamos segmentaciones, normalmente tenemos muchos registros que clasificar. La principal consecuencia es que es inevitable el exceso de información. ¿Lo podemos mejorar? Hay a quien le gustan los gráficos de segmentación circulares. Si es tu caso, esta es una forma de conseguirlo, pero desde el punto de vista de la visualización no creemos que mejore la interpretabilidad de la información: -->
<!-- ```{r} -->
<!-- set.seed(5665) -->
<!-- hc_ward <- hcut(cluster_data_stand, k = 6, hc_method = "ward.D2") -->
<!-- fviz_dend(x = hc_ward, k = 6, type = "circular", cex=0.5) -->
<!-- ``` -->
<!-- ### K-means -->
<!-- El paquete `factoextra` ofrece la función `eclust`, que nos permite visualizar un k-means instantáneamente. -->
<!-- ```{r} -->
<!-- set.seed(123) -->
<!-- eclust(cluster_data_stand, "kmeans", k = 6) -->
<!-- ``` -->
<!-- Volvemos a tener el mismo problema: las etiquetas de 201 países son demasiada información para presentarla gráficamente. -->
# Contar una historia
::: {.callout-tip}
## Cómo narrar una historia convincente con tus datos.
Hemos visto el **planteamiento**, en el que proporcionamos el contexto: trabajamos para un jefe que nos ha pedido algo muy concreto: un análisis exploratorio (y sabemos que lo quiere con conclusiones)...
El análisis exploratorio podemos usarlo para ir introduciendo la **trama**, donde vemos enseguida relaciones interesantes entre algunas parejas de variables... Solo hemos analizado la esperanza de vida al nacer respecto a la tasa de crecimiento, pero en la matriz de puntos hemos visto muchas, por lo que el jefe estará feliz.
La segmentación también nos ha proporcionado agrupaciones de países, aunque visualmente son difíciles de interpretar, por lo que lo más lógico sería seleccionar un conjunto de países de interés, que consiga un análisis (y su visualización) más interesante.
Como siempre, lo más importante es el **desenlace**, donde le estamos dando a nuestro jefe las claves que necesita:
- La matriz de puntos es vital, si nuestro superior está habituado al análisis, porque **se aprecia un número importante de relaciones claras entre variables**.
- En cada variable **podemos usar la estética y las facetas para potenciar la visualización**, determinando las variables que suministran información en las relaciones encontradas.
Finalmente, hemos visto que, cuando tenemos un número elevado de información, tenemos que adoptar una decisión equilibrada entre la información que suministramos en nuestros gráficos y nuestra habilidad para eliminar el desorden y enfocar la mirada del espectador a lo que nos interesa más. Para el caso que nos ocupa, podemos:
- Usar la agrupación previa por zonas geográficas, como hemos hecho antes.
- Restringir la visualización a una zona geográfica concreta.
- Filtrar determinados países para quedarnos con los que nos interesa comparar.
- Directamente usar una tabla, relacionando todos los países de interés.
:::
# Para pensar:
::: {.callout}
A veces no tenemos más remedio que proporcionar una visualización con mucha información, si ésta es clave para nuestro propósito.
:::