Ejercicio2: Tidyverse y Tidyr

Una aplicación de análisis de Redes de Comercio Internacional

Author
Affiliation

Cantillan, R. | Bucca, M.

ISUC

Published

20 August 2024

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

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

2 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)
```
.row country1 country2 year exports
1 United States of America Haiti 1900 NA
2 United States of America Dominican Republic 1900 NA
3 United States of America Mexico 1900 17.08
4 United States of America Guatemala 1900 NA
5 United States of America Honduras 1900 NA
6 United States of America El Salvador 1900 NA
```{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)
```
country1 country2 year exports
United States of America Haiti 1900 0.00
United States of America Dominican Republic 1900 0.00
United States of America Mexico 1900 17.08
United States of America Guatemala 1900 0.00
United States of America Honduras 1900 0.00
United States of America El Salvador 1900 0.00

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

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í:

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.

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.

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

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
```
Top 5 países por grado de centralidad
year country degree betweenness closeness
1900 United Kingdom 65 419.45519 0.0270270
1900 United States of America 54 133.10400 0.0238095
1900 France 47 60.04964 0.0217391
1900 Germany 47 63.79488 0.0222222
1900 Belgium 42 37.43019 0.0204082
1955 United Kingdom 151 296.91710 0.0123457
1955 German Federal Republic 147 210.47082 0.0121951
1955 Netherlands 146 138.47309 0.0121951
1955 Italy 146 244.81575 0.0121951
1955 France 145 153.91901 0.0120482
2009 United Kingdom 363 440.36355 0.0052083
2009 China 363 461.00904 0.0052356
2009 India 362 462.69186 0.0052356
2009 United States of America 361 521.24579 0.0052083
2009 France 361 414.56138 0.0052083
2009 Japan 361 473.51765 0.0052083

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.

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:

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.

5 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)")
```
Top 5 países por fuerza de centralidad (red ponderada)
year country strength betweenness closeness
1900 United Kingdom 2836.4000 311.000000 0.0391651
1900 Germany 2081.9900 0.000000 0.0314140
1900 United States of America 1857.0103 184.000000 0.0438884
1900 France 1242.0400 44.000000 0.0255090
1900 Belgium 750.0987 300.000000 0.0439504
1955 United States of America 26285.5229 87.333333 0.0440882
1955 United Kingdom 15852.2630 78.000000 0.0461879
1955 German Federal Republic 11387.9900 78.000000 0.0379170
1955 Canada 9845.7020 119.333333 0.0580142
1955 France 6418.7470 0.000000 0.0549100
2009 United States of America 2550432.7900 0.000000 0.0001485
2009 China 2441328.3500 0.000000 0.0001489
2009 Japan 1182584.7600 0.000000 0.0001489
2009 France 867601.3080 187.379081 0.0001489
2009 United Kingdom 733534.1520 7.349355 0.0001489

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.

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.

5.1 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} \]

5.2 Ejemplo con R

Consideremos un pequeño grafo dirigido que representa el comercio entre 4 países:

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)

6 Ejercicio 4: Algoritmo PageRank

Aplicaremos el algoritmo PageRank a la red de comercio ponderada para cada año.

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
}
```
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:

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
```
Top 5 países por PageRank
country pagerank year
United Kingdom 0.2148234 1900
Germany 0.1241042 1900
United States of America 0.1036946 1900
France 0.0737686 1900
Belgium 0.0474671 1900
United States of America 0.1192706 1955
United Kingdom 0.0981821 1955
German Federal Republic 0.0619836 1955
Russia 0.0436273 1955
Canada 0.0414142 1955
United States of America 0.1166511 2009
China 0.0828028 2009
France 0.0405142 2009
Japan 0.0380871 2009
United Kingdom 0.0356402 2009

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.

7 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()
```
country community year
United States of America 1 1900
Haiti 1 1900
Dominican Republic 1 1900
Mexico 1 1900
Colombia 1 1900
Venezuela 1 1900
Ecuador 1 1900
Peru 1 1900
Brazil 1 1900
Bolivia 1 1900
Chile 1 1900
Argentina 1 1900
Uruguay 1 1900
United Kingdom 1 1900
Netherlands 1 1900
Belgium 1 1900
France 1 1900
Switzerland 2 1900
Spain 1 1900
Portugal 1 1900
Germany 2 1900
Austria-Hungary 2 1900
Italy 2 1900
Yugoslavia 2 1900
Greece 2 1900
Romania 2 1900
Russia 2 1900
Sweden 2 1900
Denmark 2 1900
Morocco 1 1900
Iran 2 1900
Turkey 1 1900
China 3 1900
Korea 3 1900
Japan 3 1900
Thailand 1 1900
United States of America 1 1955
Canada 1 1955
Cuba 1 1955
Haiti 1 1955
Dominican Republic 1 1955
Mexico 1 1955
Guatemala 1 1955
Honduras 1 1955
El Salvador 1 1955
Nicaragua 1 1955
Costa Rica 1 1955
Panama 1 1955
Colombia 1 1955
Venezuela 1 1955

```{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)
```
year community count total percentage
1900 1 22 36 61.111111
1900 2 11 36 30.555556
1900 3 3 36 8.333333
1955 1 30 80 37.500000
1955 2 11 80 13.750000
1955 3 27 80 33.750000
```{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.

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.

7.1 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)
```