-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.qmd
774 lines (581 loc) · 29.3 KB
/
index.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
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
---
title: "Ejercicio2: Tidyverse y Tidyr"
subtitle: "Una aplicación de análisis de Redes de Comercio Internacional"
author: "Cantillan, R. | Bucca, M."
institute: "ISUC"
page-layout: article
date: now
date-format: "D MMMM YYYY"
number-sections: true
format:
html:
theme:
- cosmo
- custom.scss
css: custom.scss
toc: true
toc-depth: 3
toc-title: "En este ejercicio"
toc-location: right
editor: visual
title-block-banner: true
title-block-style: default
title-block-categories: true
freeze: auto
execute:
echo: fenced
eval: true
output: true
warning: false
reference-location: margin
citation-location: margin
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
```
## Introducción
Este análisis se basa en el estudio de Luca De Benedictis y Lucia Tajoli (2011) sobre "La Red Mundial de Comercio" y utiliza datos del Proyecto "Correlates of War". Exploraremos cómo el comercio internacional ha evolucionado a lo largo del tiempo, utilizando técnicas de análisis de redes y las herramientas proporcionadas por Tidyverse y Tidyr.
### Datos
Los datos se encuentran en el archivo `trade.csv` y contienen la siguiente información:
- `country1`: Nombre del país exportador
- `country2`: Nombre del país importador
- `year`: Año
- `exports`: Valor total de las exportaciones (en decenas de millones de dólares)
Los datos cubren los años 1900, 1920, 1940, 1955, 1980, 2000 y 2009.
## Carga de librerías y datos
```{r}
library(tidyverse)
library(igraph)
#install.packages( "printr", type = 'source', repos = c('http://yihui.name/xran', 'http://cran.rstudio.com'))
library(printr)
library(igraph)
library(ggplot2)
library(tidyverse)
library(ggrepel)
library(ggplot2)
library(dplyr)
library(ggalluvial)
library(viridis)
data(trade, package = "qss")
head(trade)
```
```{r}
# dicotomizamos la red (en formato edgelist)
# Iniciamos una cadena de operaciones sobre el dataframe 'trade'
# El resultado final se asignará de vuelta a 'trade'
trade <- trade %>%
# Seleccionamos todas las columnas excepto '.row'
# El signo menos (-) indica que estamos excluyendo esta columna
select(-`.row`) %>%
# Modificamos la columna 'exports':
# Reemplazamos todos los valores NA en 'exports' con 0
# Esto se hace usando la función replace_na()
# Si hay otros valores en 'exports', se mantienen sin cambios
mutate(exports = replace_na(exports, 0))
head(trade)
```
## Ejercicio 1: Análisis de densidad de red
Analizaremos el comercio internacional como una red no ponderada y dirigida. Crearemos una matriz de adyacencia donde $(i,j)$ es 1 si el país $i$ exporta al país $j$, y 0 en caso contrario.
La densidad de la red se define como:
$$
\text{densidad de la red} = \frac{\text{número de aristas}}{\text{número de aristas potenciales}}
$$
En el ejericio siguiente:
- Identificamos todos los años únicos en los datos.
- Preparamos la estructura de datos para almacenar resultados (densidades y matrices de adyacencia).
- Para cada año:
- Filtra los datos relevantes.
- Crea una matriz de aristas (conexiones entre países).
- Convierte esta matriz en un objeto de grafo.
- Almacena el grafo.
- Calcula y almacena la densidad del grafo.
El resultado final es una lista de grafos (adj.mat) y un vector de densidades (densities), uno para cada año en los datos.
::: {.callout-note}
### Matrices de Adyacencia
Una matriz de adyacencia es una representación matemática de un grafo o red. En esta matriz, las filas y columnas representan los nodos (o vértices) del grafo, y los valores en la matriz indican si existe una conexión (arista) entre dos nodos.
Características principales:
1. Es una matriz cuadrada (mismo número de filas y columnas).
2. Para un grafo no dirigido, la matriz es simétrica.
3. Los elementos de la diagonal principal suelen ser cero (a menos que se permitan bucles).
4. Para grafos ponderados, los valores pueden representar el peso de las conexiones.
Ejemplo:
Consideremos un grafo simple con 3 nodos (A, B, C) y las siguientes conexiones:
- A está conectado con B
- B está conectado con C
- C está conectado con A
La matriz de adyacencia para este grafo sería:
```
A B C
A 0 1 1
B 1 0 1
C 1 1 0
```
En R, podríamos representar esta matriz así:
```r
matriz_adj <- matrix(c(0, 1, 1,
1, 0, 1,
1, 1, 0), nrow = 3, byrow = TRUE)
rownames(matriz_adj) <- colnames(matriz_adj) <- c("A", "B", "C")
print(matriz_adj)
```
Esta representación es útil para realizar cálculos y análisis sobre la estructura de la red.
:::
::: {.callout-note}
### El Loop: Procesamiento de Datos en Serie
Imagina un loop como una línea de producción para procesar datos:
```{r}
# for (registro in base_de_datos) {
# dato_limpio <- limpiar_dato(registro)
# dato_analizado <- analizar_dato(dato_limpio)
# almacenar_resultado(dato_analizado)
# }
```
Funcionamiento del Loop:
- base_de_datos es tu conjunto de datos a procesar.
- Cada registro es un elemento individual de la base de datos.
- El loop procesa cada registro de forma secuencial.
- Aplica las mismas operaciones (limpiar, analizar, almacenar) a cada registro.
- Continúa hasta procesar todos los registros de la base de datos.
Este método es eficiente para aplicar un conjunto de operaciones a múltiples elementos de datos de manera sistemática.
:::
```{r}
# Obtenemos todos los años únicos del conjunto de datos 'trade' y los guarda en 'years'
years <- unique(trade$year)
# Crea un vector 'densities' lleno de NA's, con la misma longitud que 'years'
densities <- rep(NA, length(years))
# Inicializa una lista vacía llamada 'adj.mat' para almacenar las matrices de adyacencia
adj.mat <- list()
# Inicia un bucle que se ejecutará para cada año en 'years'
for (i in seq_along(years)){
# Filtra los datos de 'trade' para el año actual y exportaciones positivas,
# selecciona solo los países exportador e importador, y convierte a matriz
temp_edges <- trade %>%
filter(year == years[i], exports > 0) %>%
select(country1, country2) %>%
as.matrix()
# Crea un objeto de grafo dirigido a partir de la matriz de aristas
temp_adj <- graph_from_edgelist(temp_edges, directed = TRUE)
# Guarda el grafo en la lista 'adj.mat' en la posición correspondiente al año actual
adj.mat[[i]] <- temp_adj
# Calcula la densidad del grafo y la guarda en 'densities' en la posición del año actual
densities[i] <- graph.density(temp_adj)
}
# nombres
names(adj.mat) <- years
# trasnformamos a tibble
plot_data <- tibble(year = years, density = densities)
# ploteamos la distirbución
ggplot(plot_data, aes(x = year, y = density)) +
geom_line() +
geom_point() +
labs(title = "Densidad de la Red de Comercio Internacional",
x = "Año", y = "Densidad") +
theme_minimal()
```
**Interpretación**: La densidad de la red de comercio internacional ha aumentado generalmente desde 1900 hasta 2009, lo que indica una creciente interconexión global. Sin embargo, se observa una caída notable alrededor de 1940, probablemente debido a las políticas proteccionistas y los efectos de la Segunda Guerra Mundial.
## Ejercicio 2: Medidas de centralidad
Calcularemos las medidas de centralidad basadas en grado, intermediación y cercanía para los años 1900, 1955 y 2009.
::: {.callout-note}
### La Función: Módulo de Análisis Reutilizable
Considera una función como un módulo de análisis especializado:
```{r}
# analizar_tendencias <- function(datos, periodo, variable) {
# datos_filtrados <- filtrar_por_periodo(datos, periodo)
# tendencia <- calcular_tendencia(datos_filtrados, variable)
# grafico <- generar_grafico(tendencia)
# return(list(tendencia = tendencia, grafico = grafico))
# }
```
Estructura y Lógica de la Función:
- `analizar_tendencias` es el nombre de tu módulo de análisis.
- `datos`, `periodo`, y `variable` son los parámetros de entrada.
- La función ejecuta una serie de pasos analíticos predefinidos.
- Procesa los datos de entrada según los parámetros especificados.
- Retorna resultados estructurados (en este caso, una lista con la tendencia y un gráfico).
- Se puede reutilizar para diferentes conjuntos de datos: `analizar_tendencias(datos_ventas, "2023", "ingresos")`
- Esta estructura permite crear componentes de análisis modulares y reutilizables, lo cual mejora la eficiencia y consistencia.
:::
```{r}
# Definimos una función que calcula las medidas de centralidad para un año dado
calculate_centralities <- function(year) {
# Obtiene el grafo correspondiente al año desde la lista adj.mat
graph <- adj.mat[[as.character(year)]]
# Crea un tibble con el país y sus medidas de centralidad
tibble(
country = names(V(graph)), # Nombres de los nodos (países)
degree = degree(graph), # Grado de centralidad
betweenness = betweenness(graph), # Intermediación
closeness = closeness(graph, mode = "all") # Cercanía
) %>%
mutate(year = year) # Añade el año como columna
}
# Aplica la función a los años 1900, 1955 y 2009, combinando los resultados en un único dataframe
centralities <- map_dfr(c(1900, 1955, 2009), calculate_centralities)
# Muestra los 5 países con mayor grado de centralidad para cada año
centralities %>%
group_by(year) %>%
slice_max(n = 5, order_by = degree) %>% # Selecciona los top 5 por grado
select(year, country, degree, betweenness, closeness) %>% # Selecciona solo estas columnas
arrange(year, desc(degree)) %>% # Ordena por año y grado descendente
knitr::kable(caption = "Top 5 países por grado de centralidad") # Crea una tabla bonita
```
**Interpretación**: En los primeros períodos, los países occidentales (por ejemplo, Reino Unido, Alemania, Estados Unidos) tendían a dominar la red de comercio internacional en términos de centralidad. Para 2009, los cinco países principales se habían diversificado significativamente, con China e India ocupando posiciones destacadas.
::: {.callout-note}
### La función `map_dfr` de purrr
La función `map_dfr` es parte de la familia de funciones `map` en el paquete purrr de R. Esta función es particularmente útil cuando se trabaja con listas o vectores y se desea aplicar una función a cada elemento, devolviendo los resultados como un único data frame.
Características principales:
1. **Aplicación de función**: Aplica una función dada a cada elemento de una lista o vector.
2. **Combinación de resultados**: Une los resultados de cada aplicación de la función en un único data frame.
3. **Preservación de filas**: El sufijo '_dfr' indica que los resultados se combinan por filas (row-binding).
Sintaxis básica:
```r
map_dfr(.x, .f, ...)
```
Donde:
- `.x` es la lista o vector de entrada
- `.f` es la función a aplicar
- `...` son argumentos adicionales pasados a la función
`map_dfr` es especialmente útil en análisis de datos cuando se necesita aplicar la misma operación a múltiples conjuntos de datos y combinar los resultados en un único data frame para su posterior análisis o visualización.
:::
## Ejercicio 3: Análisis de red ponderada
Ahora analizaremos la red de comercio como una red ponderada y dirigida, donde el peso de cada arista es proporcional al volumen de comercio.
```{r}
# Definimos una función para calcular centralidades ponderadas para un año específico
calculate_weighted_centralities <- function(year) {
# Filtramos los datos para el año especificado, seleccionando solo conexiones con exportaciones > 0
edges <- trade %>%
filter(year == !!year, exports > 0) %>%
select(country1, country2, weight = exports)
# Creamos un grafo dirigido a partir de los datos filtrados
graph <- graph_from_data_frame(edges, directed = TRUE)
# Calculamos las medidas de centralidad y las organizamos en un tibble
tibble(
country = names(V(graph)), # Nombres de los países (nodos)
strength = strength(graph), # Fuerza (grado ponderado)
betweenness = betweenness(graph, weights = E(graph)$weight), # Intermediación ponderada
closeness = closeness(graph, mode = "all", weights = E(graph)$weight) # Cercanía ponderada
) %>%
mutate(year = year) # Añadimos el año como columna
}
# Aplicamos la función a los años 1900, 1955 y 2009
weighted_centralities <- map_dfr(c(1900, 1955, 2009), calculate_weighted_centralities)
# Mostramos los 5 países con mayor fuerza de centralidad para cada año
weighted_centralities %>%
group_by(year) %>%
slice_max(n = 5, order_by = strength) %>%
select(year, country, strength, betweenness, closeness) %>%
arrange(year, desc(strength)) %>%
knitr::kable(caption = "Top 5 países por fuerza de centralidad (red ponderada)")
```
**Interpretación**: Las medidas de centralidad para las redes ponderadas producen resultados sustancialmente diferentes de los de las redes no ponderadas. En particular, asignan puntuaciones altas de centralidad de intermediación y cercanía a países que no tienen grandes economías. Esto sugiere que, aunque estos países pueden no comerciar en grandes cantidades, conectan a otros grandes socios comerciales que de otro modo estarían distantemente conectados.
::: {.callout-note}
### Grafos Dirigidos y su Representación Matricial
Un grafo dirigido es una estructura matemática que representa relaciones direccionales entre objetos.
Características principales:
1. **Nodos (o vértices)**: Representan los objetos o entidades.
2. **Aristas (o enlaces) dirigidos**: Conectan los nodos y tienen una dirección específica.
### Representación Matricial
Un grafo dirigido puede representarse mediante una matriz de adyacencia:
- Es una matriz cuadrada de tamaño $n \times n$, donde $n$ es el número de nodos.
- El elemento $a_{ij}$ de la matriz es 1 si hay una arista del nodo $i$ al nodo $j$, y 0 en caso contrario.
Algebraicamente, para un grafo $G$ con $n$ nodos, su matriz de adyacencia $A$ se define como:
$$
A = [a_{ij}] \quad \text{donde} \quad a_{ij} = \begin{cases}
1 & \text{si hay una arista de } i \text{ a } j \\
0 & \text{en caso contrario}
\end{cases}
$$
### Ejemplo con R
Consideremos un pequeño grafo dirigido que representa el comercio entre 4 países:
```r
library(igraph)
# Definir las aristas del grafo
edges <- matrix(c(
1, 2, # País 1 exporta al País 2
1, 3, # País 1 exporta al País 3
2, 3, # País 2 exporta al País 3
3, 4 # País 3 exporta al País 4
), ncol = 2, byrow = TRUE)
# Crear el grafo
g <- graph_from_edgelist(edges, directed = TRUE)
# Obtener la matriz de adyacencia
adj_matrix <- as_adjacency_matrix(g)
# Mostrar la matriz de adyacencia
print(adj_matrix)
# Visualizar el grafo
plot(g, edge.arrow.size = 0.5, vertex.label = V(g)$name)
```
:::
## Ejercicio 4: Algoritmo `PageRank`
Aplicaremos el algoritmo `PageRank` a la red de comercio ponderada para cada año.
::: {.callout-note}
### Algoritmo PageRank
El algoritmo `PageRank`, desarrollado por Larry Page y Sergey Brin en 1996, es un método para medir la importancia de los nodos en una red dirigida. Originalmente diseñado para clasificar páginas web en los resultados de búsqueda de Google, `PageRank` tiene aplicaciones en diversos tipos de redes, incluidas las redes de comercio internacional.
Definición formal:
Para un grafo dirigido $G$ con n nodos, el PageRank $PR(u)$ de un nodo u se define como:
$$PR(u) = \frac{1-d}{n} + d \sum_{v \in B_u} \frac{PR(v)}{L(v)}$$
Donde:
$d$ es un factor de amortiguación (típicamente 0.85)
$B_u$ es el conjunto de nodos que apuntan a u
$L(v)$ es el número de enlaces salientes desde el nodo v
En términos sustantivos, PageRank asigna una puntuación a cada nodo basándose en la estructura de enlaces de la red. Un nodo tiene un PageRank alto si:
- Muchos otros nodos apuntan a él (tiene muchos enlaces entrantes)
- Los nodos que apuntan a él también tienen un PageRank alto
En el contexto de redes de comercio internacional, un país con un alto PageRank sería uno que:
- Recibe exportaciones de muchos otros países
- Recibe exportaciones de países que a su vez son importantes en la red de comercio
Referencia:
Page, L., Brin, S., Motwani, R., & Winograd, T. (1999). The PageRank citation ranking: Bringing order to the web. Stanford InfoLab.
:::
```{r}
# Definimos una función para calcular PageRank para un año específico
calculate_pagerank <- function(year) {
# Filtramos los datos para el año especificado
# Seleccionamos solo las conexiones con exportaciones positivas
# Renombramos 'exports' a 'weight' para usar en el grafo
edges <- trade %>%
filter(year == !!year, exports > 0) %>%
select(country1, country2, weight = exports)
# Creamos un grafo dirigido a partir de los datos filtrados
graph <- graph_from_data_frame(edges, directed = TRUE)
# Calculamos PageRank y creamos un tibble con los resultados
tibble(
country = names(V(graph)), # Nombres de los países (nodos del grafo)
pagerank = page_rank(graph)$vector # Valores de PageRank para cada país
) %>%
mutate(year = year) # Añadimos el año como columna
}
```
::: {.callout-note}
### El operador de "unquoting" `!!` en rlang
En la expresión `year == !!year`:
- `year` (el primer `year`) se refiere a la columna 'year' en el dataframe.
- `!!year` (el segundo `year`) se refiere al argumento `year` de la función que contiene esta expresión.
El `!!` es un operador de "unquoting" en rlang, el lenguaje de metaprogramación de tidyverse. Su función es crucial en la programación con dplyr:
1. **Propósito**: Le indica a R que debe evaluar `year` en el entorno de la función, no en el dataframe.
2. **Funcionamiento**: "Desenvuelve" la variable `year`, insertando su valor en la expresión.
3. **Necesidad**: Sin `!!`, R buscaría una columna llamada `year` en el dataframe, lo cual no es lo deseado en este contexto.
4. **Uso en programación**: Permite crear funciones más flexibles que pueden trabajar con diferentes valores de variables.
Ejemplo:
```r
filter_by_year <- function(data, year_val) {
data %>% filter(year == !!year_val)
}
```
Aquí, `!!year_val` asegura que se use el valor pasado a `year_val`, no una columna llamada `year_val`.
Este operador es parte de la "programación no estándar" que hace que tidyverse sea poderoso y flexible para el análisis de datos.
:::
```{r}
# Aplicamos la función a los años 1900, 1955 y 2009
# map_dfr aplica la función a cada año y combina los resultados en un único dataframe
pagerank_results <- map_dfr(c(1900, 1955, 2009), calculate_pagerank)
# Mostramos los 5 países con mayor PageRank para cada año
pagerank_results %>%
group_by(year) %>% # Agrupamos por año
slice_max(n = 5, order_by = pagerank) %>% # Seleccionamos los top 5 por PageRank
arrange(year, desc(pagerank)) %>% # Ordenamos por año y PageRank descendente
knitr::kable(caption = "Top 5 países por PageRank") # Creamos una tabla formateada
# Visualizamos la evolución del PageRank para países seleccionados
pagerank_results %>%
# Filtramos para incluir solo los países especificados
filter(country %in% c("United States of America", "United Kingdom", "Russia", "Japan", "China")) %>%
# Creamos un gráfico de líneas
ggplot(aes(x = year, y = pagerank, color = country)) +
geom_line() + # Añadimos líneas
geom_point() + # Añadimos puntos para cada observación
labs(title = "Evolución del PageRank para países seleccionados",
x = "Año", y = "PageRank") +
theme_minimal() # Aplicamos un tema minimalista al gráfico
```
**Interpretación**: Estados Unidos ha tenido el PageRank más alto desde 1940. Antes de eso, el Reino Unido era el más influyente según el algoritmo PageRank. En los últimos años, las clasificaciones de Japón y luego de China han aumentado según los valores de PageRank, mientras que las clasificaciones de países como el Reino Unido y Rusia han disminuido.
## Análisis de comunidades
Utilizaremos el algoritmo de detección de comunidades de Louvain para identificar grupos de países que comercian más entre sí.
```{r}
detect_communities <- function(year) {
edges <- trade %>%
filter(year == !!year, exports > 0) %>%
select(country1, country2, weight = exports)
graph <- graph_from_data_frame(edges, directed = TRUE)
undirected_graph <- as.undirected(graph, mode = "collapse", edge.attr.comb = list(weight = "sum"))
communities <- cluster_louvain(undirected_graph)
tibble(
country = names(V(undirected_graph)),
community = communities$membership
) %>%
mutate(year = year)
}
community_results <- map_dfr(c(1900, 1955, 2009), detect_communities)
head(community_results, n=50)
community_results %>%
group_by(year, community) %>%
summarise(count = n(), .groups = "drop") %>%
ggplot(aes(x = factor(year), y = count, fill = factor(community))) +
geom_bar(stat = "identity", position = "stack") +
labs(title = "Distribución de países en comunidades comerciales",
x = "Año", y = "Número de países", fill = "Comunidad") +
theme_minimal()
```
```{r}
alluvial_data <- community_results %>%
group_by(year, community) %>%
summarise(count = n(), .groups = "drop") %>%
mutate(year = as.factor(year))
# Calcular el total de países por año para los porcentajes
total_by_year <- alluvial_data %>%
group_by(year) %>%
summarise(total = sum(count))
alluvial_data <- alluvial_data %>%
left_join(total_by_year, by = "year") %>%
mutate(percentage = count / total * 100)
head(alluvial_data)
```
```{r}
ggplot(alluvial_data,
aes(x = year, y = count, alluvium = community, stratum = community)) +
geom_flow(aes(fill = factor(community)), alpha = 0.8, curve_type = "quintic") +
geom_stratum(aes(fill = factor(community)), width = 0.5, alpha = 0.9) +
geom_text(stat = "stratum", aes(label = paste0(round(percentage, 1), "%")),
color = "white", size = 3, fontface = "bold") +
scale_fill_viridis_d(option = "D", direction = -1) +
scale_y_continuous(expand = c(0, 0)) +
labs(title = "Evolución de las Comunidades Comerciales",
subtitle = "Distribución y tamaño de las comunidades a lo largo del tiempo",
x = "Año",
y = "Número de Países",
fill = "Comunidad") +
theme_minimal() +
theme(
legend.position = "right",
axis.text.x = element_text(angle = 0, hjust = 0.5, size = 12, face = "bold"),
axis.text.y = element_text(size = 10),
axis.title = element_text(size = 12, face = "bold"),
plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 12, margin = margin(b = 20)),
panel.grid.major.x = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray90", linetype = "dashed"),
legend.title = element_text(size = 10, face = "bold"),
legend.text = element_text(size = 9),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20, unit = "pt")
) +
guides(fill = guide_legend(title.position = "top", ncol = 1))
```
**Interpretación**: Este análisis nos permite identificar comunidades de países que tienden a comerciar más entre sí. Observando cómo estas comunidades cambian a lo largo del tiempo, podemos inferir cambios en los patrones globales de comercio, como la formación de bloques comerciales regionales o el surgimiento de nuevos centros de comercio global.
::: {.callout-note}
### Intuición Teórica y Sociológica del Algoritmo de Detección de Comunidades
El algoritmo de `Louvain`, utilizado en este código para detectar comunidades, se basa en la optimización de la modularidad de la red. La modularidad es una medida que cuantifica la calidad de una división de la red en comunidades.
Formalmente, la modularidad Q se define como:
$$Q = \frac{1}{2m} \sum_{ij} \left[A_{ij} - \frac{k_i k_j}{2m}\right] \delta(c_i, c_j)$$
Donde:
- $A_{ij}$ es el peso de la arista entre los nodos i y j
- $k_i$ y $k_j$ son las sumas de los pesos de las aristas adjuntas a los nodos i y j respectivamente
- $m$ es la suma de todos los pesos de las aristas en la red
- $c_i$ y $c_j$ son las comunidades de los nodos i y j
- $\delta(c_i, c_j)$ es 1 si $c_i = c_j$ y 0 en caso contrario
Intuitivamente, el algoritmo busca grupos de nodos que están más densamente conectados entre sí que con el resto de la red.
En el contexto de redes de comercio internacional:
1. **Bloques comerciales**: Las comunidades detectadas pueden representar bloques comerciales o regiones económicas donde los países tienen relaciones comerciales más intensas entre sí.
2. **Globalización vs. Regionalización**: La evolución de estas comunidades a lo largo del tiempo puede reflejar tendencias hacia la globalización (menos comunidades, más interconectadas) o la regionalización (comunidades más definidas y separadas).
3. **Asimetrías en el comercio global**: La estructura de las comunidades puede revelar asimetrías en el sistema de comercio global, identificando grupos de países centrales y periféricos.
4. **Impacto de políticas comerciales**: Cambios en la estructura de las comunidades pueden reflejar el impacto de acuerdos comerciales, uniones aduaneras o cambios en las políticas económicas globales.
5. **Resiliencia económica**: La estructura de las comunidades puede ofrecer insights sobre la resiliencia de diferentes regiones económicas frente a shocks globales.
:::
### Network plots (EXTRA).
```{r}
# Definición de la función para detectar comunidades en un año específico
detect_communities <- function(year) {
# Filtrar los datos para el año específico y seleccionar columnas relevantes
edges <- trade %>%
filter(year == !!year, exports > 0) %>%
select(country1, country2, weight = exports)
# Crear un grafo dirigido a partir de los datos filtrados
graph <- graph_from_data_frame(edges, directed = TRUE)
# Convertir el grafo dirigido en no dirigido, sumando los pesos de las aristas
undirected_graph <- as.undirected(graph, mode = "collapse", edge.attr.comb = list(weight = "sum"))
# Detectar comunidades utilizando el algoritmo de Louvain
communities <- cluster_louvain(undirected_graph)
# Devolver una lista con el grafo no dirigido y las comunidades detectadas
list(
graph = undirected_graph,
communities = communities
)
}
# Definición de la función para crear y optimizar el plot de comunidades
plot_community_optimized <- function(year) {
# Detectar comunidades para el año especificado
result <- detect_communities(year)
graph <- result$graph
communities <- result$communities
# Crear un layout inicial utilizando el algoritmo Fruchterman-Reingold
layout_initial <- layout_with_fr(graph)
# Función para calcular el centro de una comunidad
community_center <- function(comm) {
members <- which(communities$membership == comm)
colMeans(layout_initial[members,, drop = FALSE])
}
# Calcular los centros de todas las comunidades
comm_centers <- sapply(unique(communities$membership), community_center)
# Ajustar el layout para agrupar nodos por comunidad
layout_adjusted <- layout_initial
for (comm in unique(communities$membership)) {
members <- which(communities$membership == comm)
center <- comm_centers[,comm]
# Mover los nodos hacia el centro de su comunidad (70% hacia el centro, 30% posición original)
layout_adjusted[members,] <- layout_initial[members,, drop = FALSE] * 0.3 +
matrix(center, nrow = length(members), ncol = 2, byrow = TRUE) * 0.7
}
# Normalizar el layout ajustado
layout_normalized <- scale(layout_adjusted)
# Crear un dataframe con la información de los nodos
node_data <- tibble(
name = V(graph)$name,
community = communities$membership,
x = layout_normalized[,1],
y = layout_normalized[,2]
)
# Crear un dataframe con la información de las aristas
edge_data <- as_tibble(get.edgelist(graph)) %>%
rename(from = V1, to = V2) %>%
left_join(node_data, by = c("from" = "name")) %>%
left_join(node_data, by = c("to" = "name"), suffix = c("_from", "_to"))
# Definir los colores específicos para las comunidades
color_palette <- c("#087e8b", "#ff5a5f", "#3c3c3c")
# Asignar colores a las comunidades, repitiendo si es necesario
num_communities <- length(unique(communities$membership))
community_colors <- rep_len(color_palette, num_communities)
# Crear el gráfico con ggplot2
ggplot() +
# Dibujar las aristas como segmentos grises semi-transparentes
geom_segment(data = edge_data,
aes(x = x_from, y = y_from, xend = x_to, yend = y_to),
alpha = 0.1, color = "gray") +
# Dibujar los nodos como puntos coloreados por comunidad
geom_point(data = node_data,
aes(x = x, y = y, color = factor(community)),
size = 4) +
# Añadir etiquetas de texto repelentes para los nombres de los países
geom_text_repel(data = node_data,
aes(x = x, y = y, label = name, color = factor(community)),
size = 3, max.overlaps = 20,
segment.color = "gray50", segment.alpha = 0.5) +
# Aplicar la paleta de colores personalizada
scale_color_manual(values = community_colors) +
# Usar un tema vacío para el fondo
theme_void() +
# Mantener la proporción de los ejes
coord_fixed() +
# Añadir título al gráfico
labs(title = paste("Comunidades comerciales en", year),
color = "Comunidad") +
# Ocultar la leyenda
theme(legend.position = "none")
}
# Crear gráficos para cada año de interés
plot_1900 <- plot_community_optimized(1900)
plot_1955 <- plot_community_optimized(1955)
plot_2009 <- plot_community_optimized(2009)
# Mostrar los gráficos
print(plot_1900)
print(plot_1955)
print(plot_2009)
```