Método Exacto para el Grupo K-Medoids.

El algoritmo k-medoids es un enfoque de agrupamiento similar al k-means para dividir un conjunto de datos en k grupos o clusters. En k-medoids, cada cluster se representa por un punto del conjunto de datos, llamado medoid. Un medoid es un objeto dentro del cluster cuya disimilitud promedio con todos los demás miembros es mínima, siendo el punto más central del cluster. Esto lo hace un representante útil del cluster en ciertas situaciones. A diferencia de k-means, que utiliza la media de los puntos para determinar el centro del cluster, k-medoids es menos sensible al ruido y a los valores atípicos, ya que usa medoids como centros de los clusters. El usuario debe especificar k, el número de clusters a generar. Un método útil para determinar el número óptimo de clusters es el método del silhouette. El método más común de k-medoids es el algoritmo PAM (Partitioning Around Medoids).

#_https://rstudio-pubs-static.s3.amazonaws.com/1186600_3bd61f62725d425488649f1045ab3626.html_

library(imf.data)   # Extracción de datos desde la API del FMI
library(dplyr)      # Manipulación de datos
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)      # Transformación de formatos (pivot_wider)
library(cluster)    # Algoritmo PAM (K-Medianas)
library(factoextra) # Visualización de clústeres y siluetas
## Cargando paquete requerido: ggplot2
## Welcome to factoextra!
## Want to learn more? See two factoextra-related books at https://www.datanovia.com/library/principal-component-methods
library(knitr)
library(kableExtra)
## 
## Adjuntando el paquete: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows

1. EXTRACCIÓN Y SELECCIÓN DE VARIABLES (API FMI - WEO)

paises <- c("SLV", "GTM", "HND", "NIC", "CRI", "PAN")
datos_weo <- get_data(
  "WEO",
  agency_id = "IMF.RES",
  filters   = list(
    COUNTRY   = paises, 
    INDICATOR = c("NGDP_RPCH", "PCPIPCH"),                   
    FREQUENCY = "A"                           
  )
)
datos_macro <- datos_weo %>%
  mutate(
    TIME_PERIOD = as.numeric(TIME_PERIOD),
    OBS_VALUE   = as.numeric(OBS_VALUE)
  ) %>%
  filter(TIME_PERIOD == 2023) %>%
  select(COUNTRY, INDICATOR, OBS_VALUE) %>%
  pivot_wider(names_from = INDICATOR, values_from = OBS_VALUE)

datos_macro %>% 
  kable(caption = "Proyección de indicadores en la región Centroamericana para el año 2023") %>% 
  kable_classic(html_font = "Times New Roman", font_size = 13) %>% 
  kable_styling(full_width = FALSE)
Proyección de indicadores en la región Centroamericana para el año 2023
COUNTRY NGDP_RPCH PCPIPCH
CRI 4.791877 0.525186
GTM 3.533157 6.209335
HND 3.575892 6.663167
NIC 4.427794 8.445432
PAN 7.166329 1.486421
SLV 3.539157 4.046867

2. RECOMENDACIONES TÉCNICAS: TRATAMIENTO DE NA Y ESTANDARIZACIÓN

datos <- datos_macro %>%
  mutate(across(where(is.numeric), ~ ifelse(is.na(.), mean(., na.rm = TRUE), .)))

matriz_datos <- as.data.frame(datos[, -1])
rownames(matriz_datos) <- datos$COUNTRY

datos_escalados <- scale(matriz_datos)

n_paises <- nrow(datos_escalados)
print(paste("Cantidad de países en el análisis:", n_paises))
## [1] "Cantidad de países en el análisis: 6"
as.data.frame(datos_escalados) %>% 
  kable(caption = "Matriz de Datos Estandarizados (Z-Scores)") %>% 
  kable_classic(html_font = "Times New Roman", font_size = 12) %>% 
  kable_styling(full_width = FALSE)
Matriz de Datos Estandarizados (Z-Scores)
NGDP_RPCH PCPIPCH
CRI 0.2032584 -1.3000014
GTM -0.6907558 0.5301689
HND -0.6604030 0.6762928
NIC -0.0553340 1.2501427
PAN 1.8897286 -0.9905050
SLV -0.6864943 -0.1660980

3. SELECCIÓN DEL NÚMERO ÓPTIMO DE CLÚSTERES.

max_k <- min(10, n_paises - 1)

grafico_k_optimo <- fviz_nbclust(
  x = datos_escalados, 
  FUNcluster = pam, 
  method = "silhouette",
  k.max = max_k 
) +
  labs(
    title = "Número Óptimo de Clústeres - Algoritmo PAM (K-Medianas)",
    subtitle = "Criterio de Silueta Media con datos de la API del FMI",
    x = "Número de clústeres (k)",
    y = "Ancho promedio de silueta"
  ) +
  theme_minimal()

print(grafico_k_optimo)

# 4. EJECUCIÓN DEL ALGORITMO PAM (K-MEDIANAS)

# Asumiendo k = 2 según el resultado óptimo de la silueta
k_opt <- 2
resultado_pam <- pam(x = datos_escalados, k = k_opt, metric = "euclidean")
medoides_reales <- rownames(datos_escalados)[resultado_pam$id.med]
cat("Los países seleccionados como medoides son:", paste(medoides_reales, collapse = ", "), "\n")
## Los países seleccionados como medoides son: PAN, GTM
library(factoextra)
fviz_cluster(
  object = resultado_pam,
  data = datos_escalados,
  ellipse.type = "convex",
  star.plot = TRUE,       
  repel = TRUE,           
  show.clust.cent = TRUE, 
  palette = "jco",        
  ggtheme = theme_minimal()
) +
  labs(
    title = "Grupos Macroeconómicos y sus Países Medoides",
    subtitle = "Las líneas conectan cada país con su medoide asignado (GTM, PAN)",
    caption = "Fuente: Elaboración propia con datos del FMI"
  )

# 5. REPRESENTACIÓN GRÁFICA CORRESPONDIENTE AL ALGORITMO

# A) Gráfico de Elipsoides de Concentración y Medoides
grafico_clusters <- fviz_cluster(
  object = resultado_pam,
  data = datos_escalados,
  ellipse.type = "convex", 
  repel = TRUE,            
  show.clust.cent = TRUE,  
  star.plot = TRUE        
) +
  labs(
    title = "Agrupación mediante K-Medianas (PAM)",
    subtitle = "Clustering Particional Robusto basado en Medoides Reales (API FMI)",
    caption = "Fuente: Elaboración propia con datos de la API del FMI"
  ) +
  theme_minimal()

print(grafico_clusters)

# B) Gráfico de Silueta de la Partición
grafico_silueta <- fviz_silhouette(resultado_pam) +
  labs(
    title = "Gráfico de Silueta para Clustering PAM (k = 2)",
    subtitle = "Evaluación del ajuste individual y promedio de los clústeres"
  ) +
  theme_minimal()
##   cluster size ave.sil.width
## 1       1    2          0.29
## 2       2    4          0.66
print(grafico_silueta)