Universidad
Universidad del Valle
Facultad
Facultad de Ingeniería
Asignatura
Gestión de Datos
Profesor
Orlando Joaqui Barandica
Fecha del reporte
13 de noviembre de 2026

1 Introducción

El desarrollo económico y social de un país es un fenómeno multidimensional que rara vez puede explicarse con un solo indicador. Organismos como el Banco Mundial recopilan información sobre economía, demografía, tecnología e infraestructura de la mayoría de los países del mundo, lo que genera un problema de alta dimensionalidad: al analizar muchas variables de forma simultánea, resulta difícil visualizar la estructura que subyace a las diferencias entre naciones.

Ante este panorama, resulta pertinente examinar si, más allá del ingreso per cápita, existen dimensiones subyacentes que resuman las diferencias entre los países, y qué grupos emergen cuando estos se comparan por su similitud en múltiples indicadores, sin una clasificación predefinida. Las preguntas que orientan el trabajo se formulan en la sección 1.1.1.

Para abordar estas preguntas se utiliza la base de datos de los Indicadores del Desarrollo Mundial (World Development Indicators), con un corte transversal del año 2019. Se eligió ese año por ser el más reciente previo a la pandemia de COVID-19, cuyos efectos alteraron de manera atípica varios indicadores macroeconómicos y sociales en los años posteriores. Se seleccionaron 15 variables cuantitativas que caracterizan a 150 países desde cuatro frentes: el económico (PIB per cápita, ingreso nacional bruto, inflación, inversión extranjera directa, exportaciones, importaciones y desempleo), el sociodemográfico (esperanza de vida, mortalidad infantil, tasa de fertilidad y densidad poblacional), el tecnológico (suscripciones a telefonía móvil y uso de internet) y el de infraestructura y entorno (área forestal y acceso a electricidad).

Metodológicamente, se emplea el Análisis de Componentes Principales (ACP) para reducir la dimensionalidad y resumir la información en pocos componentes interpretables, y posteriormente un agrupamiento jerárquico aglomerativo con el método de Ward sobre los componentes retenidos. Dado que las variables se miden en escalas muy distintas (porcentajes, años, tasas y dólares), es necesario estandarizarlas antes del análisis; de lo contrario, las variables con mayor magnitud podrían dominar el cálculo de distancias y el peso de las demás dimensiones quedaría subestimado.

Los resultados se interpretarán describiendo el perfil de cada grupo, examinando su tamaño y la presencia de valores atípicos, y visualizando su distribución geográfica.

1.1 Pregunta de investigación principal

Pregunta principal: ¿Qué tan parecidos son los países del mundo en su nivel de desarrollo social, económico y tecnológico, y qué grupos o perfiles se forman al compararlos justo antes de la pandemia (2019)?

1.1.1 Preguntas secundarias

El análisis se apoya en dos preguntas secundarias:

  1. ¿Qué pilares o dimensiones subyacentes, más allá del ingreso per cápita, resumen las diferencias entre los países?
  1. ¿Cuántos bloques de desarrollo se forman y qué perfil caracteriza a cada uno?

1.2 Objetivo General

Identificar perfiles de desarrollo entre 150 países a partir de 15 indicadores del Banco Mundial para el año 2019, mediante el Análisis de Componentes Principales y el agrupamiento jerárquico de Ward, e interpretar los grupos resultantes.

2 Metodología

El presente trabajo se estructura como un problema de aprendizaje no supervisado. A diferencia de los modelos de clasificación previa (donde se contaba con una variable de respuesta predefinida), en este ejercicio las agrupaciones emergerán de la estructura latente de los datos. A continuación, se detalla el proceso de obtención de la información, el tratamiento de las variables, los algoritmos implementados y la definición del conjunto de datos.

2.1 Criterio de selección del año y fuente de datos

2.1.1 Justificación de la selección del año 2019

La elección de 2019 obedece a tres criterios principales:

Ausencia de distorsiones por la pandemia

Los indicadores de 2020 y 2021 reflejan choques extraordinarios (caídas del PIB, aumentos del desempleo, interrupciones del comercio y excesos de mortalidad) que dificultan identificar las relaciones estructurales de largo plazo entre las variables. 2019 permite caracterizar el “estado base” del desarrollo mundial.

Cobertura y disponibilidad de datos

Para 2019 los indicadores de los World Development Indicators (WDI) del Banco Mundial presentan una cobertura amplia y una menor proporción de datos faltantes que los años más recientes, cuyas cifras suelen estar sujetas a revisión o aún no han sido publicadas para todos los países.

Comparabilidad internacional

Al tratarse de un único corte transversal, todos los países se comparan en un mismo momento del tiempo, lo que evita mezclar efectos de coyuntura de distintos años y simplifica la interpretación de los componentes principales y de los grupos resultantes.

2.1.2 Fuente de los datos y depuración

La base de datos se construyó extrayendo información directamente de los Indicadores del Desarrollo Mundial World Development Indicators (WDI) del banco mundial, la principal colección de indicadores de desarrollo a nivel internacional, disponible en https://databank.worldbank.org/source/world-development-indicators. Para garantizar la reproducibilidad y evitar la manipulación manual de archivos Excel, se utilizó el paquete WDI de R, conectándose a la API oficial. Se extrajo la información transversal para un año específico (2019), seleccionando 15 variables cuantitativas que abarcan dimensiones económicas, sociodemográficas, tecnológicas y de infraestructura y entorno. Durante el proceso de limpieza, se eliminaron los agregados regionales y bloques económicos (filtrando la región “Aggregates” del Banco Mundial) para garantizar que cada observación correspondiera exclusivamente a un país soberano o territorio independiente. Posteriormente, se aplicó la eliminación de valores faltantes (drop_na), conservando únicamente los países que contaran con información completa en los 15 indicadores, consolidando la base final de 150 países, con 16 columnas: el identificador country y las 15 variables cuantitativas descritas en la Tabla 1.

2.2 Procesamiento de Variables

Las variables presentan escalas de medición drásticamente distintas (porcentajes frente a decenas de miles de dólares) y varianzas muy dispares. Debido a que el Análisis de Componentes Principales maximiza la varianza y el método de Ward minimiza las distancias geométricas, ambos son algoritmos hipersensibles a la escala. Para evitar que los indicadores monetarios dominen artificialmente la segmentación, todas las variables cuantitativas fueron estandarizadas (Z-score). Al centrar los datos (media de 0) y escalarlos (desviación estándar de 1), se garantiza que cada uno de los 15 indicadores contribuya equitativamente a la formación de las distancias multidimensionales, independientemente de su unidad de medida original.

2.3 Modelado

Los métodos de aprendizaje no supervisado permiten descubrir estructura en los datos sin partir de una variable respuesta ni de una clasificación predefinida. Esta característica es especialmente útil en el estudio del desarrollo internacional, donde las categorías tradicionales (países “desarrollados” y “en desarrollo”, clasificaciones por nivel de ingreso o por región geográfica) se construyen con frecuencia a partir de uno o pocos indicadores y de criterios normativos o históricos. Al dejar que sean los propios datos los que revelen las similitudes entre países, se reducen los sesgos apriorísticos del analista.

En este contexto, las dos técnicas empleadas cumplen funciones complementarias:

2.3.0.1 Reducción de Dimensionalidad (ACP)

Se aplicó el Análisis de Componentes Principales para transformar el conjunto original de 15 variables correlacionadas en un nuevo conjunto menor de variables incorrelacionadas (componentes principales). Cada componente es una combinación lineal de las variables originales y se extraen en orden de importancia, de modo que las primeras capturen la mayor proporción de la varianza total. Esto elimina la multicolinealidad y aísla el “ruido” estadístico.

2.3.0.2 Clusterización (Método de Ward)

Sobre los factores estimados (las puntuaciones o scores de los primeros componentes principales retenidos), se ejecutó un algoritmo de agrupamiento jerárquico aglomerativo. Se seleccionó el método de Ward debido a que no utiliza una distancia simple entre centroides, sino que en cada paso fusiona los clústeres que generen el menor incremento en la varianza intra-grupo (Suma de Cuadrados del Error). Esto tiende a producir grupos mucho más compactos, esféricos y homogéneos, ideales para segmentar perfiles de países.

2.4 Descripción de la base de datos y de las variables

Diccionario de las variables escogidas:

diccionario <- data.frame(
  N = 1:16,
  Variable = c(
    "country", "PIB_per_capita", "Esperanza_vida", "Telefonia_movil",
    "Uso_Internet_pct", "Inversion_extranjera", "Inflacion", "Desempleo_pct",
    "Densidad_poblacional", "Exportaciones_PIB", "Importaciones_PIB",
    "Acceso_electricidad_pct", "Tasa_fertilidad", "Mortalidad_infantil",
    "Area_forestal_pct", "INB_per_capita"
  ),
  Descripcion = c(
    "Identificador del país",
    "Producto Interno Bruto per cápita",
    "Esperanza de vida al nacer",
    "Suscripciones a telefonía celular móvil (por cada 100 hab.)",
    "Porcentaje de la población que usa Internet",
    "Inversión extranjera directa, entrada neta (% del PIB)",
    "Tasa de inflación anual (%)",
    "Tasa de desempleo (% de la fuerza laboral)",
    "Personas por km² de superficie terrestre",
    "Exportaciones de bienes y servicios (% del PIB)",
    "Importaciones de bienes y servicios (% del PIB)",
    "Acceso a la electricidad (% de la población)",
    "Tasa de fertilidad (nacimientos por mujer)",
    "Mortalidad infantil (por cada 1.000 nacidos vivos)",
    "Superficie forestal (% del área terrestre)",
    "Ingreso Nacional Bruto per cápita"
  ),
  Unidad = c(
    "—", "USD", "Años", "Suscripciones/100 hab.", "% población", "% del PIB",
    "% anual", "% fuerza laboral", "Personas/km²", "% del PIB", "% del PIB",
    "% población", "Hijos/mujer", "Por 1.000 nacidos", "% superficie", "USD"
  ),
  # Cuatro dimensiones (7 + 4 + 2 + 2 = 15 indicadores), iguales a las de la Introducción
  # y a los grupos de histogramas de los resultados descriptivos
  Dimension = c(
    "Identificación", "Económica", "Sociodemográfica", "Tecnológica",
    "Tecnológica", "Económica", "Económica", "Económica",
    "Sociodemográfica", "Económica", "Económica", "Infraestructura y entorno",
    "Sociodemográfica", "Sociodemográfica", "Infraestructura y entorno", "Económica"
  ),
  stringsAsFactors = FALSE
)

vars_diccionario <- diccionario$Variable   # nombres originales (se usan para verificar la base)

cls_dim <- c("Identificación" = "id", "Económica" = "eco", "Sociodemográfica" = "soc",
             "Tecnológica" = "tec", "Infraestructura y entorno" = "inf")
diccionario$Variable  <- paste0("<code>", diccionario$Variable, "</code>")
diccionario$Dimension <- paste0('<span class="badge-dim ', cls_dim[diccionario$Dimension],
                                '">', diccionario$Dimension, '</span>')

tabla(
  diccionario,
  col.names = c("N.º", "Variable", "Descripción", "Unidad", "Dimensión"),
  caption   = "Tabla 1. Descripción de las variables (16 columnas: identificador + 15 indicadores cuantitativos, 2019)"
)
Tabla 1. Descripción de las variables (16 columnas: identificador + 15 indicadores cuantitativos, 2019)
N.º Variable Descripción Unidad Dimensión
1 country Identificador del país — Identificación
2 PIB_per_capita Producto Interno Bruto per cápita USD Económica
3 Esperanza_vida Esperanza de vida al nacer Años Sociodemográfica
4 Telefonia_movil Suscripciones a telefonía celular móvil (por cada 100 hab.) Suscripciones/100 hab. Tecnológica
5 Uso_Internet_pct Porcentaje de la población que usa Internet % población Tecnológica
6 Inversion_extranjera Inversión extranjera directa, entrada neta (% del PIB) % del PIB Económica
7 Inflacion Tasa de inflación anual (%) % anual Económica
8 Desempleo_pct Tasa de desempleo (% de la fuerza laboral) % fuerza laboral Económica
9 Densidad_poblacional Personas por km² de superficie terrestre Personas/km² Sociodemográfica
10 Exportaciones_PIB Exportaciones de bienes y servicios (% del PIB) % del PIB Económica
11 Importaciones_PIB Importaciones de bienes y servicios (% del PIB) % del PIB Económica
12 Acceso_electricidad_pct Acceso a la electricidad (% de la población) % población Infraestructura y entorno
13 Tasa_fertilidad Tasa de fertilidad (nacimientos por mujer) Hijos/mujer Sociodemográfica
14 Mortalidad_infantil Mortalidad infantil (por cada 1.000 nacidos vivos) Por 1.000 nacidos Sociodemográfica
15 Area_forestal_pct Superficie forestal (% del área terrestre) % superficie Infraestructura y entorno
16 INB_per_capita Ingreso Nacional Bruto per cápita USD Económica

La base tiene 16 columnas: el identificador country y 15 variables cuantitativas, descritas una a una en el diccionario anterior. En resumen, los 15 indicadores miden cuatro dimensiones del desarrollo:

  • Económica (7: PIB_per_capita, INB_per_capita, Inversion_extranjera, Inflacion, Desempleo_pct, Exportaciones_PIB, Importaciones_PIB): nivel de ingreso, estabilidad, empleo y apertura comercial.
  • Sociodemográfica (4: Esperanza_vida, Mortalidad_infantil, Tasa_fertilidad, Densidad_poblacional): salud, estructura y concentración de la población.
  • Tecnológica (2: Telefonia_movil, Uso_Internet_pct): conectividad de la población.
  • Infraestructura y entorno (2: Acceso_electricidad_pct, Area_forestal_pct): servicios básicos y dotación de bosques.

Nota sobre el tratamiento de los datos. Las variables tienen unidades y escalas muy distintas, por lo que se estandarizan (media cero y varianza uno) antes del análisis. Además, algunos indicadores (inflación, inversión extranjera, densidad poblacional, PIB e INB per cápita) son muy asimétricos y tienen valores extremos; su efecto se evaluará en los resultados.

2.5 Carga y verificación de los datos

# --- Lectura robusta del CSV (detecta delimitador, BOM y columnas de índice sobrantes) ---
archivo <- "datos_banco_mundial_2019.csv"
if (!file.exists(archivo)) {
  stop("No se encuentra '", archivo, "' en la carpeta de trabajo (", getwd(),
       "). Coloque el CSV en la misma carpeta que el archivo .Rmd.")
}
primera_linea <- readLines(archivo, n = 1, warn = FALSE, encoding = "UTF-8")
n_coma <- lengths(regmatches(primera_linea, gregexpr(",", primera_linea)))
n_pyc  <- lengths(regmatches(primera_linea, gregexpr(";", primera_linea)))
sep_csv <- if (n_pyc > n_coma) ";" else ","

mis_datos <- read.csv(archivo, sep = sep_csv, dec = if (sep_csv == ";") "," else ".",
                      check.names = FALSE, stringsAsFactors = FALSE)
# Quita un posible BOM al inicio del primer nombre de columna y espacios sobrantes
names(mis_datos) <- trimws(sub("^(\ufeff|\u00ef\u00bb\u00bf)", "", names(mis_datos)))

# Si el CSV trae columnas de más (p. ej. un índice "X"), se conservan solo las del diccionario
if (all(vars_diccionario %in% names(mis_datos))) {
  mis_datos <- mis_datos[, vars_diccionario]
}

if (ncol(mis_datos) != 16) {
  stop("La base debe tener 16 columnas, pero '", archivo, "' (leído desde ", getwd(),
       ") tiene ", ncol(mis_datos), ". Columnas encontradas: ",
       paste(names(mis_datos), collapse = ", "))
}

# --- Verificaciones de estructura: 16 columnas = country + 15 variables cuantitativas ---
es_num <- vapply(mis_datos[, setdiff(names(mis_datos), "country")], is.numeric, logical(1))
stopifnot(
  "La base debe tener 16 columnas"                     = ncol(mis_datos) == 16,
  "Falta la columna 'country'"                         = "country" %in% names(mis_datos),
  "Deben existir 15 variables cuantitativas"           = length(es_num) == 15 && all(es_num),
  "Hay valores faltantes en la base"                   = !anyNA(mis_datos),
  "Hay países repetidos"                               = !anyDuplicated(mis_datos$country)
)

# Las columnas deben coincidir con el diccionario (Tabla 1); si no, se avisa pero se continúa
fuera_dic <- setdiff(names(mis_datos), vars_diccionario)
if (length(fuera_dic) > 0) {
  warning("Columnas que no están en el diccionario: ", paste(fuera_dic, collapse = ", "))
}

# --- Objetos de trabajo para el ACP y el clustering ---
datos_num <- mis_datos %>% dplyr::select(-country) %>% as.data.frame()
rownames(datos_num) <- mis_datos$country
datos_esc <- scale(datos_num)          # variables estandarizadas (media 0, desv. est. 1)

tarjetas(
  valores   = c(nrow(mis_datos), ncol(mis_datos), ncol(datos_num), sum(is.na(mis_datos))),
  etiquetas = c("Países (filas)", "Columnas totales", "Variables cuantitativas", "Valores faltantes")
)
150
Países (filas)
16
Columnas totales
15
Variables cuantitativas
0
Valores faltantes
datos_tabla_visual <- mis_datos %>%
  mutate(across(where(is.numeric), ~ round(., 2)))

DT::datatable(datos_tabla_visual,
          extensions = 'Buttons',
          options = list(
            dom = 'Bfrtip',
            buttons = c('copy', 'csv', 'excel', 'pdf', 'print'),
            pageLength = 10,
            scrollX = TRUE,
            autoWidth = TRUE
          ),
          rownames = FALSE,
          caption = "Tabla 2. Base de datos de Indicadores de Desarrollo del Banco Mundial (2019)")

La base final reúne 150 países (sin grupos regionales ni bloques económicos) y 16 columnas: el identificador country y 15 indicadores cuantitativos del Banco Mundial de 2019. Con ellos se busca identificar los pilares que más diferencian a los países, agruparlos en perfiles de desarrollo parecidos e interpretar qué significa cada grupo.

2.6 Técnicas multivariadas utilizadas

Cada técnica responde a una de las preguntas secundarias: el ACP identifica los pilares que más diferencian a los países (pregunta 1), y el clustering de Ward forma los bloques de desarrollo de países parecidos (pregunta 2).

2.6.1 Análisis de Componentes Principales (ACP)

El ACP es una técnica de reducción de dimensionalidad que transforma un conjunto de \(p\) variables cuantitativas correlacionadas en un nuevo conjunto de \(p\) variables no correlacionadas, llamadas componentes principales, ordenadas de modo que las primeras retienen la mayor parte de la variabilidad total de los datos (Jolliffe, 2002; Johnson y Wichern, 2007).

1. Estandarización y matriz de correlaciones

Sea \(X\) la matriz de datos de dimensión \(n \times p\) (con \(n = 150\) países y \(p = 15\) indicadores cuantitativos). Cada variable se estandariza:

\[ z_{ij} = \frac{x_{ij} - \bar{x}_j}{s_j}, \qquad i = 1, \dots, n; \; j = 1, \dots, p, \]

donde \(\bar{x}_j\) y \(s_j\) son la media y la desviación estándar muestrales de la variable \(j\). Con datos estandarizados, la matriz de covarianzas de \(Z\) coincide con la matriz de correlaciones:

\[ R = \frac{1}{n-1} Z^{\top} Z . \]

Trabajar con \(R\) en lugar de la matriz de covarianzas es lo adecuado cuando las variables tienen unidades distintas, como ocurre en este taller.

2. Autovalores y autovectores

Los componentes se obtienen de la descomposición espectral de \(R\):

\[ R\, v_k = \lambda_k\, v_k, \qquad \lambda_1 \ge \lambda_2 \ge \dots \ge \lambda_p \ge 0, \]

donde \(\lambda_k\) es el autovalor y \(v_k\) el autovector (de norma unitaria y ortogonal a los demás) asociado al componente \(k\). Los autovectores contienen los coeficientes (loadings) con que cada variable original contribuye a cada componente. El \(k\)-ésimo componente principal se calcula como la combinación lineal

\[ C_k = Z\, v_k = v_{1k}\, Z_1 + v_{2k}\, Z_2 + \dots + v_{pk}\, Z_p , \]

y los valores de \(C_k\) para cada país se denominan puntuaciones (scores) o factores estimados. Las puntuaciones de componentes distintos son no correlacionadas, y la varianza de \(C_k\) es igual a \(\lambda_k\).

3. Varianza explicada

Como \(R\) es una matriz de correlaciones, su traza es igual a \(p\) y la variabilidad total es \(\sum_{k=1}^{p} \lambda_k = p\). La proporción de varianza explicada por el componente \(k\) y la proporción acumulada por los primeros \(m\) componentes son:

\[ PVE_k = \frac{\lambda_k}{\sum_{j=1}^{p} \lambda_j} = \frac{\lambda_k}{p}, \qquad PVE_{1:m} = \sum_{k=1}^{m} \frac{\lambda_k}{p}. \]

4. Criterios para elegir el número de componentes

Se utilizarán de manera conjunta: (i) el criterio de Kaiser (Kaiser, 1960), que retiene los componentes con \(\lambda_k > 1\), es decir, aquellos que explican más varianza que una variable original estandarizada; (ii) el gráfico de sedimentación (scree plot), buscando el “codo” donde la ganancia marginal de varianza se vuelve pequeña; y (iii) un porcentaje de varianza acumulada suficientemente alto (usualmente entre 70 % y 80 %), contrastado con la interpretabilidad de los componentes.

2.6.2 Clustering jerárquico aglomerativo de Ward

El agrupamiento jerárquico aglomerativo construye una jerarquía de particiones: parte de \(n\) grupos de un solo país y, en cada paso, fusiona los dos grupos más parecidos hasta reunirlos todos en uno (Johnson y Wichern, 2007; James et al., 2021). El método de Ward define “más parecidos” mediante la pérdida de homogeneidad interna que produce la fusión (Ward, 1963).

1. Factores de entrada y distancia

El agrupamiento se aplica sobre las puntuaciones (scores) de los \(m\) componentes principales retenidos, \(c_i = (c_{i1}, \dots, c_{im})\), que resumen los 15 indicadores y no están correlacionadas entre sí. La disimilitud entre dos países \(i\) y \(j\) es la distancia euclidiana en ese espacio de factores:

\[ d(i,j) = \sqrt{\sum_{k=1}^{m} \left(c_{ik} - c_{jk}\right)^2 } . \]

2. Criterio de Ward y algoritmo

En cada paso se fusionan los grupos \(A\) y \(B\) que generan el menor incremento de la suma de cuadrados intra-grupo:

\[ \Delta(A,B) = \frac{n_A \, n_B}{n_A + n_B} \; \left\lVert \bar{c}_A - \bar{c}_B \right\rVert^2 , \]

donde \(n_A\), \(n_B\) son los tamaños y \(\bar{c}_A\), \(\bar{c}_B\) los centroides de los grupos. Se implementa con hclust(method = "ward.D2") sobre las distancias euclidianas, que corresponde al criterio original de Ward (Murtagh y Legendre, 2014). El resultado tiende a grupos compactos y de tamaño similar.

3. Dendrograma y corte

La historia de fusiones se representa en un dendrograma: la altura de cada unión es el incremento de varianza intra-grupo que produjo. Cortar el árbol a una altura determinada equivale a elegir el número de grupos \(k\). La calidad de la jerarquía se resume con el coeficiente de correlación cofenético, que compara las distancias originales con las implícitas en el árbol (valores cercanos a 1 indican que el árbol conserva bien las distancias).

4. Número de clusters y validación

Como la solución con k = 2 solo separa dos bloques gruesos y la pregunta de investigación busca perfiles, se define de antemano como criterio de selección el k con mayor silueta promedio entre las soluciones con k ≥ 3, contrastado con la inercia explicada, el tamaño de los grupos y su interpretabilidad. Dado que la silueta mide la nitidez de la separación y no la utilidad descriptiva de la partición, sus valores se interpretan junto con el resto de criterios.

2.7 Herramientas computacionales

El análisis se realizó en R. Las siguientes tarjetas indican qué paquetes complementarios estuvieron disponibles al compilar este reporte (✓ disponible, ✗ no disponible):

tarjetas(ifelse(paquetes_disponibles, "✓", "✗"), names(paquetes_disponibles),
         clase = ifelse(paquetes_disponibles, "kpi peq", "kpi peq warn"),
         contenedor = "kpi-fila peq-fila")
✓
corrplot
✓
factoextra
✓
FactoMineR
✓
plotly
✓
cluster
✓
dendextend
✓
DT
✓
ggcorrplot
✓
maps

3 Resultados Descriptivos

Antes de aplicar técnicas de análisis multivariado, como el Análisis de Componentes Principales (ACP) y los métodos de clusterización, es fundamental examinar el comportamiento general de las variables seleccionadas. Esto permite identificar tendencias, niveles de dispersión y posibles diferencias estructurales entre los países de la base de datos.

El análisis descriptivo es una etapa fundamental del proyecto, ya que permite detectar patrones preliminares de similitud y diferencia entre los países seleccionados.

3.1 Contexto Geográfico Global

library(maps)
library(plotly)

mapa_mundo <- map_data("world")

# Nombres del Banco Mundial -> nombres de la cartografía del paquete maps
ajustar_nombres_mapa <- function(x) {
  dplyr::case_when(
    x == "United States"            ~ "USA",
    x == "United Kingdom"           ~ "UK",
    x == "Russian Federation"       ~ "Russia",
    x == "Egypt, Arab Rep."         ~ "Egypt",
    x == "Iran, Islamic Rep."       ~ "Iran",
    x == "Venezuela, RB"            ~ "Venezuela",
    x == "Korea, Rep."              ~ "South Korea",
    x == "Turkiye"                  ~ "Turkey",
    x == "Congo, Dem. Rep."         ~ "Democratic Republic of the Congo",
    x == "Congo, Rep."              ~ "Republic of Congo",
    x == "Gambia, The"              ~ "Gambia",
    x == "Bahamas, The"             ~ "Bahamas",
    x == "Slovak Republic"          ~ "Slovakia",
    x == "Kyrgyz Republic"          ~ "Kyrgyzstan",
    x == "Lao PDR"                  ~ "Laos",
    x == "Cote d'Ivoire"            ~ "Ivory Coast",
    x == "Czechia"                  ~ "Czech Republic",
    x == "Yemen, Rep."              ~ "Yemen",
    x == "Syrian Arab Republic"     ~ "Syria",
    x == "Brunei Darussalam"        ~ "Brunei",
    TRUE                            ~ x
  )
}

datos_mapa <- mis_datos %>% mutate(country = ajustar_nombres_mapa(country))

mapa_datos_unidos <- left_join(mapa_mundo, datos_mapa, by = c("region" = "country"))

grafico_mapa <- ggplot(mapa_datos_unidos,
                       aes(x = long, y = lat, group = group,
                           fill = Uso_Internet_pct,
                           text = paste("País:", region, "<br>Uso de Internet:", round(Uso_Internet_pct, 1), "%"))) +
  geom_polygon(color = "white", linewidth = 0.1) +
  scale_fill_gradientn(colours = c("#FDF2F2", "#F1948A", "#C0392B", "#7A0016", "#4A000E"),
                       na.value = "gray85", name = "Uso de\nInternet (%)") +
  theme_void() +
  labs(title = "Dispersión Geográfica del Uso de Internet (2019)",
       subtitle = "Porcentaje de la población conectada por país") +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5, color = "#7A0016"),
    plot.subtitle = element_text(size = 10, hjust = 0.5),
    legend.position = "right"
  )

mapa_dinamico <- ggplotly(grafico_mapa, tooltip = "text")

mapa_dinamico

El mapa coroplético permite una primera aproximación a las profundas brechas estructurales del desarrollo global en el año 2019. Tomando el uso de internet como proxy de penetración tecnológica y de infraestructura, se observa una fractura geográfica evidente: naciones del norte global y países del Golfo Pérsico (como Bahréin y Qatar) exhiben niveles de conectividad cercanos a la saturación, con tasas superiores al 99.5%. En agudo contraste, la región del África Subsahariana presenta un profundo rezago, con países como la República Centroafricana y el Chad donde la cobertura no supera el 8% de la población. Las áreas del mapa sin relleno reflejan aquellos países que fueron rigurosamente filtrados del modelo por presentar datos incompletos en las 15 dimensiones de estudio (o cuyo nombre no coincide con el de la cartografía utilizada), garantizando así la calidad del algoritmo de segmentación posterior.

3.2 Estadísticas descriptivas

A continuación se verá una tabla con estadísticas descriptivas como las Medidas de tendencia central y dispersión para cada variable:

# Asimetría (coeficiente de Fisher-Pearson, g1 = m3 / m2^1.5)
asimetria <- function(x) { x <- x[!is.na(x)]; m <- mean(x); mean((x - m)^3) / mean((x - m)^2)^1.5 }

tabla_desc <- data.frame(
  Variable = names(datos_num),
  N        = vapply(datos_num, function(x) sum(!is.na(x)), numeric(1)),
  Media    = vapply(datos_num, mean, numeric(1)),
  Mediana  = vapply(datos_num, median, numeric(1)),
  DE       = vapply(datos_num, sd, numeric(1)),
  Min      = vapply(datos_num, min, numeric(1)),
  Max      = vapply(datos_num, max, numeric(1)),
  Asim     = vapply(datos_num, asimetria, numeric(1))
)
tabla_desc$CV <- tabla_desc$DE / tabla_desc$Media * 100
tabla_desc <- tabla_desc[, c("Variable", "N", "Media", "Mediana", "DE", "CV", "Min", "Max", "Asim")]
tabla_desc$Variable <- paste0("<code>", tabla_desc$Variable, "</code>")

tabla(tabla_desc, digits = 2,
      caption = "Tabla 3. Estadísticas descriptivas de los indicadores de desarrollo (2019)",
      col.names = c("Variable", "N", "Media", "Mediana", "Desv. Est.", "CV (%)", "Mínimo", "Máximo", "Asimetría"))
Tabla 3. Estadísticas descriptivas de los indicadores de desarrollo (2019)
Variable N Media Mediana Desv. Est. CV (%) Mínimo Máximo Asimetría
PIB_per_capita 150 15.906,93 6.188,34 21.078,10 132,51 449,23 112.696,65 1,94
Esperanza_vida 150 73,02 74,24 8,17 11,19 31,53 84,36 -1,15
Telefonia_movil 150 110,95 115,26 31,64 28,52 32,26 209,03 -0,21
Uso_Internet_pct 150 61,29 68,53 27,41 44,73 7,51 99,70 -0,47
Inversion_extranjera 150 8,80 2,38 43,09 489,78 -13,69 431,79 7,91
Inflacion 150 5,30 2,24 21,47 404,96 -3,23 255,30 10,73
Desempleo_pct 150 7,04 5,01 5,67 80,55 0,10 28,47 1,70
Densidad_poblacional 150 215,61 83,59 695,14 322,41 2,10 7.973,67 9,59
Exportaciones_PIB 150 41,78 35,37 30,01 71,82 7,78 206,58 2,57
Importaciones_PIB 150 45,26 39,50 25,55 56,45 14,47 176,08 2,20
Acceso_electricidad_pct 150 85,84 99,85 24,33 28,34 8,40 100,00 -1,64
Tasa_fertilidad 150 2,55 2,06 1,26 49,48 0,92 6,54 1,10
Mortalidad_infantil 150 26,49 14,40 32,52 122,73 2,40 254,70 3,07
Area_forestal_pct 150 31,42 31,12 22,26 70,87 0,00 91,57 0,48
INB_per_capita 150 15.629,73 6.025,00 20.108,13 128,65 500,00 84.160,00 1,66

La inspección de la Tabla 3 revela un total de 150 observaciones para cada una de las quince variables. El primer reto metodológico se observa en la extrema heterogeneidad de las escalas de medición. Mientras que indicadores acotados como la Tasa de Desempleo varían entre un mínimo de 0.10% y un máximo de 28.47%, las variables macroeconómicas fluctúan en magnitudes de miles. El Producto Interno Bruto per cápita presenta un valor mínimo de 449.23 dólares y un techo máximo de 112696.65 dólares, evidenciando una brecha económica masiva.

Esta volatilidad se confirma al observar la columna del Coeficiente de Variación. La Inversión Extranjera Directa y la Inflación presentan las dispersiones relativas más altas de toda la base, con coeficientes de 489.78% y 404.96% respectivamente. En el extremo opuesto, la Esperanza de Vida muestra la mayor homogeneidad de los datos con un coeficiente de apenas 11.19%.

Adicionalmente, se nota una marcada distancia entre las medias y las medianas. El Ingreso Nacional Bruto per cápita tiene un promedio de 15629.73 dólares, pero su mediana es mucho menor ubicándose en 6025.00 dólares. Esta abismal diferencia de escalas numéricas y varianzas hace indispensable centrar y escalar todas las variables antes de ejecutar el Análisis de Componentes Principales. De omitirse la estandarización, el algoritmo asignaría la mayor parte del peso del modelo a las variables monetarias simplemente por su gran magnitud numérica.

3.3 Distribución de los Datos

library(dplyr); library(tidyr); library(ggplot2); library(plotly)

# 1. Dimensión y unidad de cada variable
info_vars <- tibble::tribble(
  ~Variable,                 ~Etiqueta,                                  ~Grupo,
  "PIB_per_capita",          "PIB per cápita (USD)",                     "Económico",
  "INB_per_capita",          "INB per cápita (USD)",                     "Económico",
  "Inflacion",               "Inflación (% anual)",                      "Económico",
  "Inversion_extranjera",    "Inversión extranjera (% del PIB)",         "Económico",
  "Exportaciones_PIB",       "Exportaciones (% del PIB)",                "Económico",
  "Importaciones_PIB",       "Importaciones (% del PIB)",                "Económico",
  "Desempleo_pct",           "Desempleo (% fuerza laboral)",             "Económico",
  "Esperanza_vida",          "Esperanza de vida (años)",                 "Sociodemográfico",
  "Mortalidad_infantil",     "Mortalidad infantil (por 1.000 nacidos)",  "Sociodemográfico",
  "Tasa_fertilidad",         "Tasa de fertilidad (hijos por mujer)",     "Sociodemográfico",
  "Densidad_poblacional",    "Densidad poblacional (personas/km²)",      "Sociodemográfico",
  "Telefonia_movil",         "Telefonía móvil (suscripciones/100 hab.)", "Tecnológico",
  "Uso_Internet_pct",        "Uso de internet (% población)",            "Tecnológico",
  "Acceso_electricidad_pct", "Acceso a electricidad (% población)",      "Infraestructura y entorno",
  "Area_forestal_pct",       "Área forestal (% superficie)",             "Infraestructura y entorno"
)

# 2. Base en formato largo
datos_largos2 <- mis_datos %>%
  pivot_longer(-country, names_to = "Variable", values_to = "Valor") %>%
  inner_join(info_vars, by = "Variable")

# 3. Función: un gráfico de histogramas por dimensión
histogramas_grupo <- function(grupo, ncol = 3, alto = 450) {
  niveles <- info_vars$Etiqueta[info_vars$Grupo == grupo]
  d <- datos_largos2 %>% filter(Grupo == grupo)
  d$Etiqueta <- factor(d$Etiqueta, levels = niveles)

  medias <- d %>% group_by(Etiqueta) %>% summarise(media = mean(Valor), .groups = "drop")

  # un color distinto por variable, en tonos rojos
  colores <- setNames(colorRampPalette(c("#7A0016", "#C0392B", "#F1948A"))(length(niveles)), niveles)

  p <- ggplot(d, aes(x = Valor, fill = Etiqueta)) +
    geom_histogram(bins = 15, color = "white", alpha = 0.85, show.legend = FALSE) +
    geom_vline(data = medias, aes(xintercept = media),
               linetype = "dashed", color = "#D97706", linewidth = 0.7) +
    scale_fill_manual(values = colores) +
    facet_wrap(~ Etiqueta, scales = "free", ncol = ncol) +
    theme_minimal(base_family = "sans") +
    labs(title = paste0("Distribución de variables: ", grupo),
         x = "", y = "Frecuencia") +
    theme(plot.title       = element_text(face = "bold", size = 14, hjust = 0.5),
          strip.background = element_rect(fill = "#FADBD8", color = NA),
          strip.text       = element_text(face = "bold", size = 9, color = "#7A0016"),
          panel.grid.minor = element_blank(),
          panel.spacing    = unit(1, "lines"))

  ggplotly(p, height = alto) %>% layout(showlegend = FALSE)
}

3.3.1 Variables económicas

histogramas_grupo("Económico", ncol = 3, alto = 650)

La distribución de las variables económicas revela la profunda desigualdad estructural entre las naciones. Los indicadores de ingreso (PIB e INB per cápita) exhiben una asimetría positiva extrema (sesgo a la derecha): la inmensa mayoría de los países se aglomera en niveles de ingresos bajos y medios-bajos (por debajo de los 20.000 USD), mientras que una larga cola se extiende impulsada por unas pocas economías de muy altos ingresos que superan los 80.000 USD. Este mismo comportamiento asimétrico se repite en el comercio internacional (Exportaciones e Importaciones) y en la Inversión Extranjera, donde la masa de datos se concentra en niveles bajos, pero es fuertemente sesgada por “paraísos fiscales” o hubs logísticos. Por su parte, variables de estabilidad como la inflación y el desempleo muestran una mayor concentración en un rango normal (1% a 10%), aunque la inflación presenta valores atípicos severos causados por crisis hiperinflacionarias en casos puntuales.

3.3.2 Variables sociodemográficas

histogramas_grupo("Sociodemográfico", ncol = 2, alto = 520)

Las variables sociodemográficas ilustran claramente la transición demográfica global. La Mortalidad Infantil y la Tasa de Fertilidad presentan una marcada asimetría positiva, lo que indica que la mayor parte del mundo ha logrado reducir significativamente ambos indicadores (concentrándose en menos de 20 muertes por cada 1.000 nacidos y menos de 2.5 hijos por mujer). No obstante, la persistencia de una cola larga a la derecha refleja el fuerte rezago de una región específica (principalmente África Subsahariana) que aún convive con tasas de fertilidad y mortalidad altísimas. Inversamente, la Esperanza de Vida muestra asimetría negativa (cola hacia la izquierda), demostrando que la longevidad es hoy la norma general (picos entre 70 y 80 años), aislando a los países con menor esperanza de vida en la cola inferior. Finalmente, la Densidad Poblacional es el indicador más comprimido, con la mayoría de los países por debajo de 500 hab/km², salvo por excepciones extremas (ciudades-estado).

3.3.3 Variables tecnológicas

histogramas_grupo("Tecnológico", ncol = 2, alto = 420)

La adopción tecnológica exhibe comportamientos duales. La Telefonía Móvil presenta una distribución que se asemeja más a una normal, con su media y mediana muy cercanas (alrededor de 110 a 115 suscripciones por cada 100 habitantes). Esto evidencia que la telefonía móvil ha alcanzado un nivel de saturación global, donde incluso las naciones en desarrollo tienen altas tasas de penetración. En contraste, el Uso de Internet muestra una distribución mucho más dispersa y casi bimodal (plana), lo que subraya que la verdadera brecha digital de 2019 no estaba en el acceso a líneas celulares móviles, sino en la adopción de internet, separando fuertemente a los países altamente conectados (más del 80%) de los desconectados (menos del 20%).

3.3.4 Variables de infraestructura y entorno

histogramas_grupo("Infraestructura y entorno", ncol = 2, alto = 420)

El Acceso a la Electricidad muestra la asimetría negativa más extrema de toda la base de datos. Una enorme barra se concentra en el extremo superior (100%), demostrando que la electrificación universal es un hito ya alcanzado por la gran mayoría de la población mundial. La varianza de este indicador está dada exclusivamente por los países rezagados que conforman la cola izquierda. Por otro lado, el Área Forestal presenta una distribución mucho más homogénea y dispersa en todo el rango (0% a 90%), evidenciando que la cobertura boscosa obedece más a condiciones geográficas, climáticas y de tamaño territorial, que a un patrón de desarrollo económico directo.

3.4 Boxplot de variables

datos_boxplot <- mis_datos %>%
  select(country, Inflacion, Inversion_extranjera, Densidad_poblacional) %>%
  pivot_longer(
    cols = c(Inflacion, Inversion_extranjera, Densidad_poblacional),
    names_to = "Variable",
    values_to = "Valor"
  ) %>%
  mutate(
    Variable_Etiqueta = case_when(
      Variable == "Inflacion"            ~ "Inflación (% anual)",
      Variable == "Inversion_extranjera" ~ "Inversión Extranjera (% del PIB)",
      Variable == "Densidad_poblacional" ~ "Densidad Poblacional (hab/km²)"
    )
  )

p_box <- ggplot(datos_boxplot, aes(x = Variable_Etiqueta, y = Valor, fill = Variable_Etiqueta)) +
  geom_boxplot(alpha = 0.75, outlier.color = "#7A0016", outlier.size = 2, outlier.alpha = 0.85) +
  facet_wrap(~ Variable_Etiqueta, scales = "free", ncol = 3) +
  scale_fill_manual(values = c("#C0392B", "#D97706", "#5B6B7B")) +
  theme_minimal(base_family = "sans") +
  labs(
    title = "Diagrama de Cajas (Boxplots) de Inflación, Inversión Extranjera y Densidad Poblacional",
    x = "",
    y = "Valor en unidades originales"
  ) +
  theme(
    plot.title       = element_text(face = "bold", size = 13, hjust = 0.5, color = "#7A0016"),
    strip.background = element_rect(fill = "#FADBD8", color = NA),
    strip.text       = element_text(face = "bold", size = 9, color = "#7A0016"),
    axis.text.x      = element_blank(),
    axis.ticks.x     = element_blank(),
    panel.grid.minor = element_blank(),
    legend.position  = "bottom",
    legend.title     = element_blank()
  )

ggplotly(p_box) %>% 
  layout(legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.15))

El análisis mediante diagramas de caja refleja anomalías y distorsiones severas en la distribución de las tres variables, lo que respalda la necesidad de estandarizar previamente y tener cautela en las etapas de ACP y Agrupamiento Jerárquico:

1.Inflación (% anual): Exhibe una marcada asimetría positiva con un rango intercuartílico concentrado entre 1,4 % y 4,5 % (mediana de 2,24 % y media de 5,30 %), pero con la presencia de valores atípicos hiperinflacionarios extremos. Sobresale Zimbabue (255,30 %), seguido por Argentina (53,55 %) e Irán (39,91 %). Estos atípicos elevan artificialmente la media muestral y responden a crisis monetarias y macroeconómicas coyunturales del año 2019.

  1. Inversión Extranjera Directa (% del PIB): Presenta una de las varianzas relativas más elevadas del estudio (coeficiente de variación de 489,8 %). La gran mayoría de países registra flujos de IED entre 0 % y 5 % del PIB, pero existen enclaves financieros y centros logísticos internacionales con valores atípicos masivos, encabezados por Chipre (431,79 %), Luxemburgo (234,31 %), Malta (198,20 %) y Singapur (28,18 %). Estos valores no corresponden necesariamente a formación de capital productivo, sino a movimientos financieros transfronterizos y regímenes fiscales especiales.

  2. Densidad Poblacional (personas por km²):¨ Exhibe una compresión extrema del cuerpo del boxplot, dado que la mediana es de tan solo 83,59 hab/km², mientras que la masa de datos se extiende en una cola derecha extremadamente larga encabezada por ciudades-estado e islas microterritoriales como Singapur (7.973,67 hab/km²), Bahréin (1.902,25 hab/km²), Maldivas (1.625,77 hab/km²) y Malta (1.574,73 hab/km²).

Implicación metodológica: Si estas tres variables ingresaran al ACP o al cálculo de distancias euclidianas del agrupamiento de Ward en su escala original, sus magnitudes y su dispersión dominarían la varianza total del modelo. Por ello se estandarizan (Z-score), de modo que ninguna variable pese más que otra por su unidad de medida. La estandarización iguala las escalas pero no elimina el efecto de los valores extremos. No se aplicaron transformaciones para conservar la interpretación directa de los indicadores; por ello, los grupos que dependen de estos países (en particular el Grupo 1) deben leerse con cautela. ## Valores atípicos

atip_base <- datos_largos2 %>%
  group_by(Variable, Etiqueta, Grupo) %>%
  mutate(q1  = quantile(Valor, 0.25),
         q3  = quantile(Valor, 0.75),
         iqr = q3 - q1,
         z   = as.numeric(scale(Valor))) %>%
  ungroup() %>%
  filter(Valor < q1 - 1.5 * iqr | Valor > q3 + 1.5 * iqr)

3.4.1 Atípicos por variable

tab_var <- atip_base %>%
  arrange(desc(abs(z))) %>%
  group_by(Grupo, Etiqueta) %>%
  summarise(`N.º atípicos` = n(),
            `Países más extremos (valor)` =
              paste0(head(country, 5), " (", fmt(head(Valor, 5), 1), ")", collapse = ", "),
            .groups = "drop")

tabla(tab_var, caption = "Tabla 4. Países atípicos por variable (regla de 1,5 × IQR)")
Tabla 4. Países atípicos por variable (regla de 1,5 × IQR)
Grupo Etiqueta N.º atípicos Países más extremos (valor)
Económico Desempleo (% fuerza laboral) 9 South Africa (28,5), Eswatini (28,2), Djibouti (26,3), West Bank and Gaza (25,3), Congo, Rep. (20,5)
Económico Exportaciones (% del PIB) 5 Luxembourg (206,6), Singapore (176,8), Djibouti (166,7), Ireland (131,2), Malta (124,5)
Económico INB per cápita (USD) 18 Switzerland (84.160,0), Norway (82.500,0), Luxembourg (79.280,0), Iceland (75.560,0), United States (65.840,0)
Económico Importaciones (% del PIB) 5 Luxembourg (176,1), Djibouti (154,2), Singapore (147,5), Ireland (126,4), Malta (108,6)
Económico Inflación (% anual) 14 Zimbabwe (255,3), Argentina (53,5), Iran, Islamic Rep. (39,9), Haiti (18,7), Angola (17,1)
Económico Inversión extranjera (% del PIB) 15 Cyprus (431,8), Luxembourg (234,3), Malta (198,2), Hungary (59,6), Netherlands (-13,7)
Económico PIB per cápita (USD) 18 Luxembourg (112.696,6), Switzerland (85.873,0), Ireland (81.827,7), Norway (79.329,3), Iceland (69.296,3)
Infraestructura y entorno Acceso a electricidad (% población) 25 Chad (8,4), Malawi (11,2), Central African Republic (14,3), Burkina Faso (17,6), Niger (18,5)
Sociodemográfico Densidad poblacional (personas/km²) 19 Singapore (7.973,7), Bahrain (1.902,3), Maldives (1.625,8), Malta (1.574,7), Bangladesh (1.266,9)
Sociodemográfico Esperanza de vida (años) 1 Central African Republic (31,5)
Sociodemográfico Mortalidad infantil (por 1.000 nacidos) 6 Central African Republic (254,7), Niger (120,8), Chad (114,0), Sierra Leone (108,3), Guinea (105,4)
Sociodemográfico Tasa de fertilidad (hijos por mujer) 4 Niger (6,5), Chad (6,4), Central African Republic (6,1), Mali (5,9)
Tecnológico Telefonía móvil (suscripciones/100 hab.) 1 United Arab Emirates (209,0)
n_atip <- nrow(atip_base)
n_obs  <- nrow(datos_largos2)
top_v  <- tab_var %>% arrange(desc(`N.º atípicos`)) %>% head(3)

analisis(
  "En total se detectan **", n_atip, "** valores atípicos (", fmt(100 * n_atip / n_obs, 1),
  " % de las ", n_obs, " observaciones país-indicador) con la regla de 1,5 × IQR. ",
  "Las variables con más atípicos son ",
  lista_es(paste0("**", top_v$Etiqueta, "** (", top_v$`N.º atípicos`, ")")), ". ",
  "Estos puntos corresponden a países con condiciones extremas en ese indicador; por las razones ",
  "expuestas en la sección anterior se conservan en el análisis y su influencia se vigila al caracterizar los grupos."
)

En total se detectan 140 valores atípicos (6,2 % de las 2250 observaciones país-indicador) con la regla de 1,5 × IQR. Las variables con más atípicos son Acceso a electricidad (% población) (25), Densidad poblacional (personas/km²) (19) y INB per cápita (USD) (18). Estos puntos corresponden a países con condiciones extremas en ese indicador; por las razones expuestas en la sección anterior se conservan en el análisis y su influencia se vigila al caracterizar los grupos.

3.4.2 Gráfico de barras de atípicos por país

tab_pais <- atip_base %>%
  group_by(country) %>%
  summarise(n_atip = n(),
            Variables = paste(Variable, collapse = ", "),
            .groups = "drop") %>%
  arrange(desc(n_atip))


top15 <- head(tab_pais, 15)

p_at <- ggplot(top15, aes(x = reorder(country, n_atip), y = n_atip,
                          text = paste0(country, ": ", n_atip, " variables"))) +
  geom_col(fill = "#C0392B", alpha = 0.9) +
  coord_flip() +
  theme_minimal(base_family = "sans") +
  labs(title = "Países con más variables atípicas", x = "", y = "N.º de variables atípicas") +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0.5))

ggplotly(p_at, tooltip = "text", height = 480)
top_p <- head(tab_pais, 3)

analisis(
  "Los países con más variables atípicas son ",
  lista_es(paste0("**", top_p$country, "** (", top_p$n_atip, " variables)")), ". ",
  "En total, **", nrow(tab_pais), "** de los ", nrow(mis_datos), " países (", fmt(100 * nrow(tab_pais) / nrow(mis_datos), 1),
  " %) presentan al menos un valor atípico, de modo que la atipicidad ",
  ifelse(nrow(tab_pais) / nrow(mis_datos) < 0.5,
         "se concentra en una minoría de países con perfiles particulares.",
         "alcanza a la mayoría de los países de la muestra, aunque en pocos casos afecta a muchas variables a la vez.")
)

Los países con más variables atípicas son Singapore (6 variables), Luxembourg (5 variables) y Central African Republic (4 variables). En total, 75 de los 150 países (50,0 %) presentan al menos un valor atípico, de modo que la atipicidad alcanza a la mayoría de los países de la muestra, aunque en pocos casos afecta a muchas variables a la vez.


4 Resultados del Modelo

4.1 Análisis de Componentes Principales (ACP)

El ACP se desarrolla en el orden que pide el taller: primero se examina la matriz de correlaciones para comprobar que los indicadores comparten información; luego se reporta la proporción de varianza explicada de cada componente para decidir cuántos retener; después se interpretan los componentes retenidos a partir de sus cargas; y, por último, se obtienen los factores estimados (puntuaciones de los países) que alimentan el clustering de Ward.

4.1.1 Matriz de correlaciones

El ACP resulta útil cuando las variables están correlacionadas, porque los componentes principales recogen precisamente esa información compartida. La matriz de correlaciones (ordenada por agrupamiento jerárquico) permite ver qué indicadores se mueven juntos y cuáles lo hacen en sentido contrario.

library(ggcorrplot)

matriz_corr <- cor(mis_datos %>% select(-country))

grafico_correlacion <- ggcorrplot(matriz_corr, 
           hc.order = TRUE, 
           type = "lower",  
           lab = TRUE,      
           lab_size = 2.5,  
           colors = c("#e74c3c", "white", "#3498db"), 
           title = "Matriz de Correlaciones de Indicadores de Desarrollo",
           ggtheme = theme_minimal()) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 8),
        axis.text.y = element_text(size = 8))

ggplotly(grafico_correlacion)
R <- cor(datos_num)
n <- nrow(datos_num); p <- ncol(datos_num)

# Parejas de variables ordenadas por |r|
idx   <- which(upper.tri(R), arr.ind = TRUE)
pares <- data.frame(V1 = rownames(R)[idx[, 1]], V2 = colnames(R)[idx[, 2]], r = R[idx])
pares <- pares[order(-abs(pares$r)), ]
etq_corta <- setNames(sub(" \\(.*$", "", info_vars$Etiqueta), info_vars$Variable)
nom <- function(v) unname(etq_corta[v])
top_pos <- head(pares[pares$r > 0, ], 2)
top_neg <- head(pares[pares$r < 0, ], 2)
prop_fuertes <- mean(abs(pares$r) >= 0.5)

# Esfericidad de Bartlett y medida KMO (cálculo directo, sin paquetes adicionales)
chi2   <- -(n - 1 - (2 * p + 5) / 6) * log(det(R))
gl     <- p * (p - 1) / 2
p_bart <- pchisq(chi2, gl, lower.tail = FALSE)
iR     <- tryCatch(solve(R), error = function(e) NULL)
if (!is.null(iR)) {
  P <- -iR / sqrt(outer(diag(iR), diag(iR))); diag(P) <- 0
  R0 <- R; diag(R0) <- 0
  kmo <- sum(R0^2) / (sum(R0^2) + sum(P^2))
} else kmo <- NA_real_
kmo_txt <- if (is.na(kmo)) "no calculable" else
  as.character(cut(kmo, c(-Inf, .5, .6, .7, .8, .9, Inf),
                   labels = c("inaceptable", "mala", "mediocre", "aceptable", "meritoria", "excelente")))

analisis(
  "Las asociaciones positivas más fuertes se dan entre ",
  lista_es(paste0("**", nom(top_pos$V1), "** y **", nom(top_pos$V2), "** (r = ", fmt(top_pos$r, 2), ")")),
  "; las negativas más fuertes, entre ",
  lista_es(paste0("**", nom(top_neg$V1), "** y **", nom(top_neg$V2), "** (r = ", fmt(top_neg$r, 2), ")")),
  ". El ", fmt(100 * prop_fuertes, 1), " % de las ", nrow(pares),
  " parejas de variables tiene |r| ≥ 0,5. ",
  "La prueba de esfericidad de Bartlett (χ² = ", fmt(chi2, 1), ", gl = ", gl, ", p ",
  ifelse(p_bart < 0.001, "< 0,001", paste0("= ", fmt(p_bart, 3))), ") ",
  ifelse(p_bart < 0.05, "rechaza que la matriz de correlaciones sea la identidad", "no rechaza que la matriz de correlaciones sea la identidad"),
  ", y el índice KMO es de **", ifelse(is.na(kmo), "—", fmt(kmo, 2)), "** (adecuación ", kmo_txt, "). ",
  "En conjunto, hay suficiente estructura de correlación para que el ACP tenga sentido."
)

Las asociaciones positivas más fuertes se dan entre PIB per cápita y INB per cápita (r = 0,99) y Exportaciones y Importaciones (r = 0,91); las negativas más fuertes, entre Esperanza de vida y Mortalidad infantil (r = -0,91) y Acceso a electricidad y Tasa de fertilidad (r = -0,85). El 21,9 % de las 105 parejas de variables tiene |r| ≥ 0,5. La prueba de esfericidad de Bartlett (χ² = 2.139,2, gl = 105, p < 0,001) rechaza que la matriz de correlaciones sea la identidad, y el índice KMO es de 0,81 (adecuación meritoria). En conjunto, hay suficiente estructura de correlación para que el ACP tenga sentido.

Lectura. Las dos asociaciones positivas más fuertes son PIB per cápita con INB per cápita (r = 0,99, prácticamente la misma información) y exportaciones con importaciones (r = 0,91); las negativas más fuertes son esperanza de vida con mortalidad infantil (r = −0,91) y acceso a electricidad con tasa de fertilidad (r = −0,85). Solo el 21,9 % de las 105 parejas tiene |r| ≥ 0,5: la correlación se concentra en un bloque grande de indicadores de desarrollo (ingreso, salud, conectividad, fertilidad) y en un par de variables de comercio, mientras que inflación, desempleo, área forestal y densidad se asocian poco con el resto. Por eso el primer componente explica mucho, pero no todo, y hacen falta otros componentes. La prueba de Bartlett (χ² = 2.139,2; gl = 105; p < 0,001) rechaza que las variables sean independientes y el KMO de 0,81 indica una adecuación meritoria para el ACP.

4.1.2 Proporción de varianza explicada

Se ajusta el ACP sobre las 15 variables estandarizadas (matriz de correlaciones). Dado que el signo de cada componente es arbitrario, se orienta cada uno de modo que la variable de mayor carga en valor absoluto tenga signo positivo, para facilitar la lectura: en CP1, un puntaje alto corresponde a mayor esperanza de vida. La interpretación sustantiva de cada componente se presenta en la sección de cargas.

library(factoextra)

res.pca <- prcomp(datos_num, center = TRUE, scale. = TRUE)

# Orientación de los signos (no altera la varianza explicada ni las distancias entre países)
orientar <- function(pca, var, k, signo) {
  if (sign(pca$rotation[var, k]) != signo) {
    pca$rotation[, k] <- -pca$rotation[, k]
    pca$x[, k]        <- -pca$x[, k]
  }
  pca
}
res.pca <- orientar(res.pca, "Esperanza_vida",     1, +1)
res.pca <- orientar(res.pca, "Importaciones_PIB",  2, -1)
res.pca <- orientar(res.pca, "Desempleo_pct",      3, +1)
res.pca <- orientar(res.pca, "Area_forestal_pct",  4, +1)

eig <- get_eigenvalue(res.pca)
pve <- eig$variance.percent        # % de varianza por componente
tabla_varianza <- data.frame(
  Componente    = paste0("CP", seq_len(nrow(eig))),
  Autovalor     = eig$eigenvalue,
  Varianza_Pct  = eig$variance.percent,
  Acumulada_Pct = eig$cumulative.variance.percent,
  Kaiser        = ifelse(eig$eigenvalue > 1, "Sí", "No")
)
tabla(tabla_varianza, digits = 2,
      caption = "Tabla 5. Proporción de varianza explicada por cada componente principal",
      col.names = c("Componente", "Autovalor", "Varianza explicada (%)", "Varianza acumulada (%)", "λ > 1 (Kaiser)"))
Tabla 5. Proporción de varianza explicada por cada componente principal
Componente Autovalor Varianza explicada (%) Varianza acumulada (%) λ > 1 (Kaiser)
CP1 6,15 41,00 41,00 Sí
CP2 2,04 13,61 54,61 Sí
CP3 1,34 8,92 63,54 Sí
CP4 1,05 6,97 70,51 Sí
CP5 0,98 6,54 77,04 No
CP6 0,92 6,11 83,15 No
CP7 0,85 5,68 88,84 No
CP8 0,56 3,71 92,55 No
CP9 0,51 3,40 95,95 No
CP10 0,23 1,51 97,46 No
CP11 0,13 0,89 98,35 No
CP12 0,13 0,86 99,21 No
CP13 0,06 0,43 99,64 No
CP14 0,05 0,31 99,95 No
CP15 0,01 0,05 100,00 No

El gráfico de sedimentación (scree plot) muestra cuánta variación captura cada componente. Los componentes se ordenan de mayor a menor: la dimensión 1 captura la mayor variación, la 2 la segunda mayor, y así sucesivamente. El eje horizontal representa los componentes y el vertical el porcentaje de varianza explicada; la línea naranja marca el umbral del criterio de Kaiser (un autovalor de 1 equivale a 100/15 = 6,67 % de la varianza).

n_mostrar <- 10   # cuántos componentes se muestran

df_eig <- data.frame(
  Componente  = factor(paste0("CP", 1:nrow(eig)), levels = paste0("CP", 1:nrow(eig))),
  Varianza    = eig$variance.percent,
  Acumulada   = eig$cumulative.variance.percent,
  ValorPropio = eig$eigenvalue
)[1:n_mostrar, ]

df_eig$Kaiser <- 100 / nrow(eig)      # 6,67 % con 15 variables

coma <- function(x, d = 1) format(round(x, d), nsmall = d, decimal.mark = ",")

df_eig$tooltip <- paste0(
  "<b>", df_eig$Componente, "</b><br>",
  "Varianza explicada: ", coma(df_eig$Varianza), " %<br>",
  "Varianza acumulada: ", coma(df_eig$Acumulada), " %<br>",
  "Valor propio: ", coma(df_eig$ValorPropio, 2)
)

plot_ly(df_eig, x = ~Componente) %>%
  add_bars(y = ~Varianza, name = "Varianza explicada",
           marker = list(color = "#C0392B"),
           text = ~paste0(coma(Varianza), " %"), textposition = "outside",
           hoverinfo = "text", hovertext = ~tooltip) %>%
  add_trace(y = ~Varianza, type = "scatter", mode = "lines+markers",
            name = "Perfil de sedimentación",
            line = list(color = "#7A0016", width = 2),
            marker = list(color = "#7A0016", size = 7),
            hoverinfo = "skip") %>%
  add_trace(y = ~Kaiser, type = "scatter", mode = "lines",
            name = "Criterio de Kaiser (λ = 1)",
            line = list(color = "#D97706", width = 2, dash = "dash"),
            hoverinfo = "skip") %>%
  layout(title  = list(text = "<b>Gráfico de sedimentación</b>", x = 0.5),
         xaxis  = list(title = "Componente principal"),
         yaxis  = list(title = "Varianza explicada (%)", range = c(0, 50)),
         legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.2),
         font   = list(family = "Lato, Arial, sans-serif", color = "#7A0016")) %>%
  config(displaylogo = FALSE)

El gráfico de sedimentación muestra que el primer componente principal explica el 41,0 % de la varianza total, seguido del segundo con 13,6 % y el tercero con 8,9 %. La caída marcada entre los dos primeros componentes y el aplanamiento a partir del cuarto sugieren que la estructura principal de los datos se concentra en pocas dimensiones. Los cuatro primeros componentes tienen valores propios mayores que 1 (criterio de Kaiser) y acumulan el 70,5 % de la varianza, por lo que se evalúa conservar entre tres y cuatro componentes, decisión que se confirma con la interpretabilidad de las cargas.

Aunque el criterio de Kaiser sugiere retener 4 componentes (todos con \(\lambda \ge 1\)), el gráfico de sedimentación muestra el “codo” más pronunciado después del segundo o tercer componente. Sin embargo, retener solo 3 componentes implicaría perder el 36% de la varianza total. Por tanto, se justifica la retención de 4 componentes para asegurar que el modelo capture más del 70% (70.51%) de la estructura latente de los datos.

4.1.3 Interpretación de los componentes principales

4.1.3.1 Tabla de cargas

La tabla de cargas indica cuánto pesa cada variable original en cada componente principal, es decir, cuánto contribuye cada indicador a la dimensión que ese componente representa. Esta información permite identificar qué variables definen cada componente y si el patrón que forman tiene un significado coherente. Por ello complementa los criterios de varianza explicada, Kaiser y el gráfico de sedimentación, y ayuda a decidir si conservar tres o cuatro componentes: no tiene sentido retener muchos si con pocos se cubre gran parte de la variación.

res.var <- get_pca_var(res.pca)

cargas <- as.data.frame(res.var$coord[, 1:4])
names(cargas) <- paste0("CP", 1:4)
cargas <- cargas[order(-abs(cargas$CP1)), , drop = FALSE]    # ordenadas por |carga| en CP1

resaltar <- function(x) ifelse(abs(x) >= 0.5, paste0("<b>", fmt(x, 2), "</b>"), fmt(x, 2))
tab_cargas <- data.frame(
  Indicador = info_vars$Etiqueta[match(rownames(cargas), info_vars$Variable)],
  lapply(cargas, resaltar)
)
tabla(tab_cargas,
      caption = "Tabla 6. Cargas (correlación variable–componente) de los cuatro primeros componentes; en negrita, |carga| ≥ 0,5",
      col.names = c("Indicador", "CP1", "CP2", "CP3", "CP4"))
Tabla 6. Cargas (correlación variable–componente) de los cuatro primeros componentes; en negrita, |carga| ≥ 0,5
Indicador CP1 CP2 CP3 CP4
Esperanza de vida (años) 0,92 0,24 -0,05 -0,06
Uso de internet (% población) 0,91 0,16 -0,00 0,01
Tasa de fertilidad (hijos por mujer) -0,88 -0,25 -0,19 -0,05
Mortalidad infantil (por 1.000 nacidos) -0,84 -0,32 -0,18 0,04
Acceso a electricidad (% población) 0,82 0,37 0,22 0,01
PIB per cápita (USD) 0,76 -0,21 -0,51 -0,01
INB per cápita (USD) 0,75 -0,13 -0,54 -0,03
Telefonía móvil (suscripciones/100 hab.) 0,66 0,22 0,17 -0,09
Exportaciones (% del PIB) 0,59 -0,70 0,18 0,13
Importaciones (% del PIB) 0,46 -0,75 0,30 0,13
Inversión extranjera (% del PIB) 0,28 -0,48 0,08 0,09
Densidad poblacional (personas/km²) 0,27 -0,47 0,03 -0,31
Inflación (% anual) -0,18 0,07 0,02 -0,44
Desempleo (% fuerza laboral) -0,07 0,03 0,71 0,02
Área forestal (% superficie) -0,04 0,17 -0,09 0,83

La tabla muestra la correlación entre cada variable original y los cuatro primeros componentes principales. Para su lectura se consideran relevantes las cargas con valor absoluto igual o superior a 0,5.

El primer componente (41,0 % de la varianza) agrupa la mayor parte de los indicadores. Presenta cargas positivas altas en esperanza de vida (0,92), uso de internet (0,91), acceso a electricidad (0,82), PIB per cápita (0,76), INB per cápita (0,75) y telefonía móvil (0,66), y cargas negativas altas en tasa de fertilidad (-0,88) y mortalidad infantil (-0,84). Esta combinación sugiere que el componente se asocia con el nivel general de desarrollo económico, social y tecnológico: los países con valores altos en este eje tienden a mostrar mayor ingreso, mayor longevidad, mayor conectividad y menor fertilidad y mortalidad infantil.

El segundo componente (13,6 %) está definido principalmente por importaciones (-0,75) y exportaciones (-0,70) como porcentaje del PIB, con aportes menores de la inversión extranjera (-0,48) y la densidad poblacional (-0,47). Se asocia con el grado de apertura comercial y de vinculación con el exterior, una dimensión distinta del nivel de desarrollo.

El tercer componente (8,9 %) se asocia sobre todo con el desempleo (0,71), en sentido opuesto al ingreso per cápita (PIB: -0,51; INB: -0,54). Recoge una dimensión del mercado laboral que no queda representada en los dos primeros componentes.

El cuarto componente (7,0 %) está dominado por el área forestal (0,83), con un aporte menor de la inflación (-0,44), y se asocia con las condiciones ambientales. Es el componente más frágil, porque depende en gran medida de una sola variable y su valor propio (1,05) supera el umbral de Kaiser por un margen estrecho.

En conjunto, se decide conservar cuatro componentes, que acumulan el 70,5 % de la varianza total y cumplen el criterio de Kaiser.

4.1.3.2 Mapa de calor de las cargas

cargas_largas <- cargas %>%
  tibble::rownames_to_column("Variable") %>%
  pivot_longer(CP1:CP4, names_to = "Componente", values_to = "Carga") %>%
  mutate(Indicador = factor(etq_corta[Variable], levels = rev(etq_corta[rownames(cargas)])))

ggplot(cargas_largas, aes(x = Componente, y = Indicador, fill = Carga)) +
  geom_tile(color = "white", linewidth = 0.6) +
  geom_text(aes(label = fmt(Carga, 2), color = abs(Carga) > 0.6), size = 3.3) +
  scale_color_manual(values = c("TRUE" = "white", "FALSE" = "#1F2A37"), guide = "none") +
  scale_fill_gradient2(low = gris, mid = "white", high = rojo_osc, midpoint = 0,
                       limits = c(-1, 1), name = "Carga") +
  labs(title = "Composición de los cuatro primeros componentes", x = NULL, y = NULL) +
  theme(legend.position = "right", axis.text.y = element_text(size = 10))

El mapa de calor resume la tabla anterior: los tonos granate intensos señalan variables que aumentan junto con el componente y los grises, las que disminuyen. Se aprecia que CP1 concentra casi todos los indicadores sociales, tecnológicos y de ingreso, mientras que CP2, CP3 y CP4 quedan definidos por pocas variables cada uno (apertura comercial, desempleo y área forestal, respectivamente).

4.1.3.3 Círculos de correlaciones

Variables en el plano de las dimensiones 1 y 2.

fviz_pca_var(res.pca,
             col.var       = "contrib",                              
             gradient.cols = c("#70A1D7", "#3B82F6", "#D97706"),     
             repel         = TRUE,                                  
             title         = "Variables - dim1 vs dim2-Grafica Original")

Este gráfico circular es un recurso visual para identificar qué variables aportan más información a cada dimensión, según el color, la longitud y la proximidad al eje correspondiente. Las flechas que van hacia la derecha en direcciones muy próximas entre sí y de color naranja son las positivamente correlacionadas: esperanza de vida, uso de internet, acceso a la electricidad, INB per cápita y PIB per cápita. En sentido contrario, tasa de fertilidad y mortalidad infantil apuntan hacia la izquierda, es decir, se asocian de forma inversa con ese grupo de indicadores. Estas flechas son largas y quedan cerca del borde del círculo, por lo que están bien representadas por estas dos dimensiones.

Sobre el eje vertical, exportaciones e importaciones apuntan hacia abajo, con una dirección casi perpendicular al grupo de desarrollo, lo que sugiere que la apertura comercial varía de forma relativamente independiente del nivel de ingreso y de las condiciones sociales. Inversión extranjera y densidad poblacional se orientan en una dirección similar, aunque con menor longitud. Por último, área forestal, inflación y desempleo presentan flechas cortas, por lo que su información se representa mejor en otros componentes y no conviene interpretar su dirección en este plano.

Variables en el plano de las dimensiones 3 y 4.

fviz_pca_var(res.pca,
             axes          = c(3,4),
             col.var       = "contrib",                              
             gradient.cols = c("#70A1D7", "#3B82F6", "#D97706"),     
             repel         = TRUE,                                  
             title         = "Variables - dim3 vs dim4-Grafica Original")

El plano de las dimensiones 3 y 4 resalta variables que quedaban poco representadas en el primero. Sobre el eje horizontal, el desempleo apunta hacia la derecha, mientras que el INB y el PIB per cápita lo hacen hacia la izquierda, en sentido opuesto, lo que indica que, una vez descontado el efecto del primer componente, el desempleo se contrapone al nivel de ingreso. Sobre el eje vertical, el área forestal apunta claramente hacia arriba y la inflación, con menor longitud, hacia abajo, de modo que la dimensión 4 se asocia sobre todo con las condiciones ambientales.

La mayoría de las demás variables presentan flechas muy cortas en este plano, porque su información ya está recogida en las dos primeras dimensiones. Este resultado es esperable y no indica ausencia de relación, sino que estas variables no aportan estructura adicional en las dimensiones 3 y 4.

4.1.4 Factores estimados para el clustering

Las puntuaciones de los países en los cuatro componentes retenidos son los factores estimados que se usan como entrada del método de Ward. Al ser los componentes ortogonales, cada país queda descrito por cuatro coordenadas no correlacionadas en lugar de 15 indicadores redundantes.

m_ret <- 4                                         # componentes retenidos
scores <- as.data.frame(res.pca$x[, 1:m_ret])
colnames(scores) <- paste0("CP", 1:m_ret)
Z <- as.matrix(scores)

ord  <- order(scores$CP1, decreasing = TRUE)
alto <- head(ord, 5)
bajo <- rev(tail(ord, 5))

tab_ext <- data.frame(
  Pos  = 1:5,
  PA   = rownames(scores)[alto], CA = fmt(scores$CP1[alto], 2),
  PB   = rownames(scores)[bajo], CB = fmt(scores$CP1[bajo], 2)
)
tabla(tab_ext,
      caption = "Tabla 7. Países en los extremos del primer componente (nivel general de desarrollo)",
      col.names = c("Posición", "País con CP1 más alto", "CP1", "País con CP1 más bajo", "CP1"))
Tabla 7. Países en los extremos del primer componente (nivel general de desarrollo)
Posición País con CP1 más alto CP1 País con CP1 más bajo CP1
1 Luxembourg 7,11 Central African Republic -8,42
2 Singapore 6,61 Chad -5,96
3 Ireland 4,38 Niger -5,54
4 Switzerland 4,12 Sierra Leone -4,47
5 United Arab Emirates 4,07 Burkina Faso -4,20

Los países con mayor puntaje en CP1 son Luxemburgo (7,11), Singapur (6,61), Irlanda (4,38), Suiza (4,12) y Emiratos Árabes Unidos (4,07); los de menor puntaje son República Centroafricana (−8,42), Chad (−5,96), Níger (−5,54), Sierra Leona (−4,47) y Burkina Faso (−4,20). El recorrido de CP1 es amplio y algo más largo hacia el extremo de menor desarrollo, lo que anticipa una separación clara entre un bloque de alto desarrollo y otro de fuerte rezago.

5 Segmentacion

5.1 Clustering Jerarquico de Ward

5.1.1 Construcción del árbol jerárquico

El agrupamiento se realiza sobre los cuatro factores estimados (Tabla 7), con distancia euclidiana y el criterio de Ward (ward.D2). Primero se construye el árbol completo y se verifica si se conserva bien las distancias originales entre países.

d_euc <- dist(Z, method = "euclidean")
hc    <- hclust(d_euc, method = "ward.D2")
coph  <- cor(cophenetic(hc), d_euc)

tarjetas(
  valores   = c(nrow(Z), m_ret, fmt(sum(pve[1:m_ret]), 1), fmt(coph, 3)),
  etiquetas = c("Países agrupados", "Factores (CP) usados", "% de varianza original que conservan", "Correlación cofenética")
)
150
Países agrupados
4
Factores (CP) usados
70,5
% de varianza original que conservan
0,632
Correlación cofenética

El coeficiente cofenético compara las distancias entre países con las que implica el árbol. Mientras más cerca esté del 1, con menos distorsión se representa la estructura de similitudes en el dendrograma.

5.1.2 Selección del número de clusters

Se evalúan las particiones de 2 a 8 grupos con tres medidas: la altura de fusión del dendrograma, la silueta promedio y la proporción de inercia explicada (\(R^2\)).

k_max <- 8
k_min <- 3      # ver criterio (iv) en la metodología

sct <- sum(scale(Z, scale = FALSE)^2)     # suma de cuadrados total en el espacio de factores

eval_k <- do.call(rbind, lapply(2:k_max, function(k) {
  cl_k <- cutree(hc, k = k)
  sil  <- cluster::silhouette(cl_k, d_euc)
  sce  <- sum(vapply(split(seq_len(nrow(Z)), cl_k),
                     function(i) sum(scale(Z[i, , drop = FALSE], scale = FALSE)^2), numeric(1)))
  data.frame(k = k, Silueta = mean(sil[, "sil_width"]), R2 = 1 - sce / sct,
             n_min = min(table(cl_k)),
             Altura = rev(hc$height)[k - 1])     # costo de pasar de k a k-1 grupos
}))

k_final <- with(eval_k[eval_k$k >= k_min, ], k[which.max(Silueta)])   # modificar aquí para forzar otro k
fila_f  <- eval_k[eval_k$k == k_final, ]

tab_k <- eval_k
tab_k$k <- ifelse(tab_k$k == k_final, paste0("<b>", tab_k$k, " ◄</b>"), tab_k$k)
tabla(tab_k, digits = 3,
      caption = "Tabla 8. Criterios para elegir el número de grupos (◄ = solución elegida)",
      col.names = c("k", "Silueta promedio", "R² (inercia explicada)", "Tamaño del grupo más pequeño", "Altura de fusión (k → k−1)"))
Tabla 8. Criterios para elegir el número de grupos (◄ = solución elegida)
k Silueta promedio R² (inercia explicada) Tamaño del grupo más pequeño Altura de fusión (k → k−1)
2 0,420 0,377 34 34,483
3 ◄ 0,379 0,540 28 22,610
4 0,369 0,655 6 19,099
5 0,245 0,692 6 10,834
6 0,211 0,722 6 9,615
7 0,214 0,747 2 8,843
8 0,226 0,770 2 8,592
ev_larga <- eval_k %>%
  select(k, Silueta, R2, Altura) %>%
  pivot_longer(-k, names_to = "Medida", values_to = "Valor") %>%
  mutate(Medida = recode(Medida, Silueta = "Silueta promedio",
                         R2 = "R² (inercia explicada)",
                         Altura = "Altura de fusión (k → k−1)"),
         Medida = factor(Medida, levels = c("Altura de fusión (k → k−1)", "Silueta promedio", "R² (inercia explicada)")))

p_k <- ggplot(ev_larga, aes(x = k, y = Valor,
                            text = paste0("k = ", k, "<br>", Medida, ": ", fmt(Valor, 3)))) +
  geom_vline(xintercept = k_final, color = naranja, linetype = "dashed", linewidth = 0.7) +
  geom_line(aes(group = Medida), color = rojo_osc, linewidth = 0.9) +
  geom_point(color = rojo_med, size = 2.6) +
  facet_wrap(~ Medida, scales = "free_y", nrow = 1) +
  scale_x_continuous(breaks = 2:k_max) +
  labs(title = "Criterios para elegir el número de grupos", x = "Número de grupos (k)", y = NULL)

mostrar(p_k, alto = 380)
fila_2 <- eval_k[eval_k$k == 2, ]
analisis(
  "La silueta promedio más alta entre las soluciones con al menos ", k_min, " grupos se alcanza con **k = ", k_final,
  "** (", fmt(fila_f$Silueta, 3), "); con esa partición los grupos explican el ", fmt(100 * fila_f$R2, 1),
  " % de la variabilidad total de los factores y el grupo más pequeño tiene ", fila_f$n_min, " países. ",
  "La solución con k = 2 tiene una silueta de ", fmt(fila_2$Silueta, 3), " y un R² de ", fmt(100 * fila_2$R2, 1),
  " %, pero separa a los países en solo dos bloques, una dicotomía demasiado gruesa para describir perfiles. ",
  "En el gráfico, el R² crece de forma cada vez más lenta al añadir grupos, lo que respalda no aumentar k más allá de lo necesario."
)

La silueta promedio más alta entre las soluciones con al menos 3 grupos se alcanza con k = 3 (0,379); con esa partición los grupos explican el 54,0 % de la variabilidad total de los factores y el grupo más pequeño tiene 28 países. La solución con k = 2 tiene una silueta de 0,420 y un R² de 37,7 %, pero separa a los países en solo dos bloques, una dicotomía demasiado gruesa para describir perfiles. En el gráfico, el R² crece de forma cada vez más lenta al añadir grupos, lo que respalda no aumentar k más allá de lo necesario.

Decisión. La silueta promedio es máxima con k = 2 (0,420; R² = 37,7 %), pero esa partición solo aísla un grupo de 34 países de menor desarrollo y deja los 116 restantes en un único bloque. La solución con k = 3 conserva ese grupo intacto y subdivide el bloque restante en dos (88 y 28 países): es una partición anidada, por lo que pasar de 2 a 3 grupos añade detalle sin alterar lo ya identificado. Con k = 3 el R² sube a 54,0 % (16 puntos más que con k = 2) y la silueta es de 0,379. Con k = 4 el R² llega a 65,5 %, pero la silueta baja a 0,369 y aparece un grupo de solo 6 países, es decir, la ganancia se logra fragmentando la muestra; desde k = 5 la silueta cae a 0,245 o menos. Las alturas de fusión no muestran un codo único, por lo que la elección se apoya en el conjunto de criterios y no en uno solo. Se adopta k = 3 por ser la solución con mayor silueta entre las que permiten construir perfiles (k ≥ 3), con grupos de tamaño razonable (mínimo 28 países). La correlación cofenética de 0,63 indica que el árbol conserva de forma moderada las distancias originales, por lo que el dendrograma debe leerse como una aproximación de la estructura de similitudes.

5.1.3 Dendrograma

El dendrograma muestra el orden en que se fusionan los países; la altura de cada unión es el incremento de varianza intra-grupo que produce. Los colores y recuadros indican el corte en 3 grupos.

fviz_dend(hc, k = k_final, k_colors = col_cl[1:k_final],
          color_labels_by_k = TRUE,
          rect = TRUE, rect_fill = TRUE, rect_border = col_cl[1:k_final],
          cex = 0.42, lwd = 0.6,
          main = "Dendrograma de Ward sobre los factores del ACP",
          xlab = "", ylab = "Altura de fusión (Ward)",
          ggtheme = theme_minimal())

5.1.4 Asignación y composición de los grupos

Los grupos se numeran de mayor a menor puntaje medio en CP1: el Grupo 1 es el de mayor nivel general de desarrollo según la interpretación del primer componente y el Grupo 3, el de menor nivel.

cl_raw <- cutree(hc, k = k_final)
orden  <- names(sort(tapply(scores$CP1, cl_raw, mean), decreasing = TRUE))
cl     <- factor(match(cl_raw, as.integer(orden)), levels = 1:k_final,
                 labels = paste("Grupo", 1:k_final))
names(cl) <- rownames(Z)

datos_cl <- data.frame(country = rownames(Z), Grupo = cl, scores, datos_num, row.names = NULL)

# Tamaño y posición media de cada grupo en los factores
tab_tam <- datos_cl %>%
  group_by(Grupo) %>%
  summarise(n = n(), across(CP1:CP4, mean), .groups = "drop") %>%
  mutate(Porcentaje = 100 * n / sum(n)) %>%
  select(Grupo, n, Porcentaje, CP1:CP4)

tarjetas(valores = tab_tam$n, etiquetas = paste(tab_tam$Grupo, "(países)"),
         contenedor = "kpi-fila peq-fila", clase = "kpi peq")
28
Grupo 1 (países)
88
Grupo 2 (países)
34
Grupo 3 (países)
tabla(tab_tam, digits = 2,
      caption = "Tabla 9. Tamaño de cada grupo y puntaje medio en los cuatro factores",
      col.names = c("Grupo", "Países", "% de la muestra", "CP1 medio", "CP2 medio", "CP3 medio", "CP4 medio"))
Tabla 9. Tamaño de cada grupo y puntaje medio en los cuatro factores
Grupo Países % de la muestra CP1 medio CP2 medio CP3 medio CP4 medio
Grupo 1 28 18,67 3,10 -0,82 -1,10 -0,19
Grupo 2 88 58,67 0,39 0,56 0,53 0,10
Grupo 3 34 22,67 -3,56 -0,79 -0,47 -0,10
# Proporción de la variabilidad de cada factor explicada por la partición (eta cuadrado)
eta2 <- vapply(1:m_ret, function(j) {
  1 - sum(tapply(Z[, j], cl, function(v) sum((v - mean(v))^2))) / sum((Z[, j] - mean(Z[, j]))^2)
}, numeric(1))

analisis(
  "La partición explica el ", lista_es(paste0(fmt(100 * eta2, 1), " % de CP", 1:m_ret)),
  " de la variabilidad de cada factor. Los grupos se diferencian sobre todo en **CP", which.max(eta2),
  "**, mientras que el factor donde menos se separan es **CP", which.min(eta2), "**."
)

La partición explica el 77,8 % de CP1, 22,3 % de CP2, 33,4 % de CP3 y 1,5 % de CP4 de la variabilidad de cada factor. Los grupos se diferencian sobre todo en CP1, mientras que el factor donde menos se separan es CP4.

Lectura. El Grupo 1 reúne 28 países (18,7 %), el Grupo 2 reúne 88 (58,7 %) y el Grupo 3 reúne 34 (22,7 %). Sus puntajes medios en CP1 son 3,10, 0,39 y −3,56, es decir, el eje de nivel general de desarrollo ordena los tres grupos con grandes distancias entre ellos. La partición explica el 77,8 % de la variabilidad de CP1, el 33,4 % de CP3 (desempleo frente a ingreso), el 22,3 % de CP2 (apertura comercial) y solo el 1,5 % de CP4 (área forestal): los grupos se definen sobre todo por el nivel de desarrollo y, en mucha menor medida, por el mercado laboral y el comercio; el factor ambiental no los diferencia.

5.1.4.1 Perfil promedio de los indicadores

med_mat <- sapply(levels(cl), function(g) colMeans(datos_num[cl == g, , drop = FALSE]))
tab_med <- data.frame(
  Indicador = info_vars$Etiqueta[match(rownames(med_mat), info_vars$Variable)],
  med_mat,
  Global = colMeans(datos_num),
  check.names = FALSE
)
rownames(tab_med) <- rownames(med_mat)
tab_med <- tab_med[info_vars$Variable, ]   # orden del diccionario

tabla(tab_med, digits = 2,
      caption = "Tabla 10. Promedio de cada indicador por grupo (unidades originales)",
      col.names = c("Indicador", levels(cl), "Promedio global"))
Tabla 10. Promedio de cada indicador por grupo (unidades originales)
Indicador Grupo 1 Grupo 2 Grupo 3 Promedio global
PIB per cápita (USD) 52.167,96 9.912,04 1.561,08 15.906,93
INB per cápita (USD) 50.907,14 9.852,16 1.531,47 15.629,73
Inflación (% anual) 1,23 3,96 12,14 5,30
Inversión extranjera (% del PIB) 32,92 3,92 1,56 8,80
Exportaciones (% del PIB) 68,71 39,45 25,65 41,78
Importaciones (% del PIB) 61,46 44,45 34,03 45,26
Desempleo (% fuerza laboral) 4,85 7,81 6,84 7,04
Esperanza de vida (años) 81,68 74,67 61,63 73,02
Mortalidad infantil (por 1.000 nacidos) 6,14 15,43 71,89 26,49
Tasa de fertilidad (hijos por mujer) 1,62 2,11 4,45 2,55
Densidad poblacional (personas/km²) 566,33 144,74 110,20 215,61
Telefonía móvil (suscripciones/100 hab.) 125,18 119,91 76,03 110,95
Uso de internet (% población) 91,67 66,48 22,82 61,29
Acceso a electricidad (% población) 98,74 97,11 46,04 85,84
Área forestal (% superficie) 25,56 33,69 30,37 31,42

Para comparar indicadores medidos en unidades distintas, el mapa de calor siguiente muestra el promedio estandarizado de cada grupo: los valores positivos (granate) indican que el grupo está por encima del promedio mundial en ese indicador y los negativos (gris), por debajo.

z_mat <- sapply(levels(cl), function(g) colMeans(datos_esc[cl == g, , drop = FALSE]))

z_larga <- as.data.frame(z_mat) %>%
  tibble::rownames_to_column("Variable") %>%
  pivot_longer(-Variable, names_to = "Grupo", values_to = "Z") %>%
  mutate(Indicador = factor(etq_corta[Variable], levels = rev(etq_corta[info_vars$Variable])))

ggplot(z_larga, aes(x = Grupo, y = Indicador, fill = Z)) +
  geom_tile(color = "white", linewidth = 0.6) +
  geom_text(aes(label = fmt(Z, 2), color = abs(Z) > 1), size = 3.3) +
  scale_color_manual(values = c("TRUE" = "white", "FALSE" = "#1F2A37"), guide = "none") +
  scale_fill_gradient2(low = gris, mid = "white", high = rojo_osc, midpoint = 0, name = "Z promedio") +
  labs(title = "Perfil estandarizado de cada grupo", x = NULL, y = NULL) +
  theme(legend.position = "right", axis.text.y = element_text(size = 10))

Lectura de la tabla y del mapa de calor. Los contrastes más fuertes están entre los grupos extremos. El PIB per cápita promedio pasa de unos 52.168 USD (Grupo 1) a 9.912 (Grupo 2) y 1.561 (Grupo 3); la esperanza de vida, de 81,7 a 74,7 y 61,6 años; el uso de internet, de 91,7 % a 66,5 % y 22,8 %; la mortalidad infantil, de 6,1 a 15,4 y 71,9 por 1.000 nacidos; y la tasa de fertilidad, de 1,62 a 2,11 y 4,45 hijos por mujer. La inflación también se ordena de forma inversa (1,2 %, 4,0 % y 12,1 %). El acceso a electricidad separa al Grupo 3 (46,0 %) de los otros dos (98,7 % y 97,1 %), que casi no se diferencian entre sí en ese indicador. Dos precauciones: el promedio de inversión extranjera (32,9 % del PIB) y de densidad poblacional (566 hab./km²) del Grupo 1 está inflado por casos extremos como Luxemburgo y Singapur; y el área forestal y el desempleo no separan de forma clara a los grupos (sus promedios estandarizados quedan entre −0,4 y 0,1).

5.1.4.2 Lectura de cada grupo

Cada recuadro resume, a partir de los promedios estandarizados, los indicadores en los que el grupo se aleja más de 0,5 desviaciones estándar del promedio mundial, junto con los países más cercanos al centro del grupo (los más representativos).

destacados <- function(g, umbral = 0.5, n = 3) {
  z <- sort(z_mat[, g], decreasing = TRUE)
  altos <- names(z)[z > umbral];  altos <- head(altos, n)
  bajos <- rev(names(z)[z < -umbral]); bajos <- head(bajos, n)
  list(altos = unname(etq_corta[altos]), bajos = unname(etq_corta[bajos]))
}

representativos <- function(g, n = 5) {
  idx <- which(cl == g)
  cen <- colMeans(Z[idx, , drop = FALSE])
  dis <- sqrt(rowSums((Z[idx, , drop = FALSE] - matrix(cen, length(idx), ncol(Z), byrow = TRUE))^2))
  names(sort(dis))[seq_len(min(n, length(idx)))]
}

desc_grupo <- character(0)
for (g in levels(cl)) {
  d   <- destacados(g)
  n_g <- sum(cl == g)
  cp1 <- mean(scores$CP1[cl == g])
  txt_alto <- if (length(d$altos)) paste0("por encima del promedio mundial en ", lista_es(tolower(d$altos))) else "sin indicadores claramente por encima del promedio"
  txt_bajo <- if (length(d$bajos)) paste0("por debajo en ", lista_es(tolower(d$bajos))) else "sin indicadores claramente por debajo del promedio"
  desc_grupo[g] <- paste0(txt_alto, "; ", txt_bajo)

  cat('\n::: {.paso}\n\n#### ', g, ' — ', n_g, ' países {-}\n\n',
      'Puntaje medio en CP1: **', fmt(cp1, 2), '**. Se ubica ', desc_grupo[g], '.\n\n',
      '*Países más representativos:* ', lista_es(representativos(g)), '.\n\n:::\n', sep = "")
}

Grupo 1 — 28 países

Puntaje medio en CP1: 3,10. Se ubica por encima del promedio mundial en inb per cápita, pib per cápita y uso de internet; por debajo en tasa de fertilidad y mortalidad infantil.

Países más representativos: Belgium, Netherlands, Denmark, United Arab Emirates y Austria.

Grupo 2 — 88 países

Puntaje medio en CP1: 0,39. Se ubica sin indicadores claramente por encima del promedio; sin indicadores claramente por debajo del promedio.

Países más representativos: El Salvador, Paraguay, Azerbaijan, Albania y Romania.

Grupo 3 — 34 países

Puntaje medio en CP1: -3,56. Se ubica por encima del promedio mundial en tasa de fertilidad y mortalidad infantil; por debajo en acceso a electricidad, uso de internet y esperanza de vida.

Países más representativos: Togo, Guinea, Malawi, Madagascar y Mali.

Interpretación de los tres perfiles.

  • Grupo 1 — Alto ingreso y alta conectividad (28 países). Economías con el mayor ingreso (PIB e INB per cápita muy por encima del promedio), esperanza de vida alta, internet casi universal y economías muy abiertas al comercio. Es el grupo más heterogéneo internamente (silueta media de 0,14), porque mezcla economías diversificadas con casos extremos de comercio e inversión.
  • Grupo 2 — Desarrollo intermedio (88 países). Es el bloque más numeroso y el más diverso: va desde economías europeas como Francia, Italia, España, Portugal o Polonia hasta países de ingreso medio de América Latina (entre ellos Colombia, Brasil, México y Chile), Asia y el norte de África. Sus indicadores están cerca del promedio mundial, con electricidad casi universal (97,1 %), esperanza de vida de 74,7 años e ingreso medio de unos 9.900 USD. Su heterogeneidad indica que, con tres grupos, este bloque agrupa países en distintas etapas de desarrollo.
  • Grupo 3 — Rezago en desarrollo humano y acceso a servicios (34 países). Predominan países de África subsahariana, junto con Haití, Pakistán y las Islas Salomón. Tienen la menor esperanza de vida (61,6 años), la mayor mortalidad infantil (71,9 por 1.000) y fertilidad (4,45), apenas 46,0 % de acceso a electricidad y 22,8 % de uso de internet.

5.1.4.3 Composición completa de los grupos

tab_comp <- datos_cl %>%
  arrange(Grupo, country) %>%
  group_by(Grupo) %>%
  summarise(n = n(),
            Paises = paste0("<div style='text-align:justify;font-size:13px'>", paste(country, collapse = ", "), "</div>"),
            .groups = "drop")
tabla(tab_comp, caption = "Tabla 11. Países que integran cada grupo",
      col.names = c("Grupo", "N.º", "Países"))
Tabla 11. Países que integran cada grupo
Grupo N.º Países
Grupo 1 28
Australia, Austria, Bahrain, Belgium, Canada, Cyprus, Denmark, Djibouti, Finland, Germany, Iceland, Ireland, Israel, Japan, Korea, Rep., Kuwait, Luxembourg, Malta, Netherlands, New Zealand, Norway, Qatar, Singapore, Sweden, Switzerland, United Arab Emirates, United Kingdom, United States
Grupo 2 88
Albania, Algeria, Argentina, Armenia, Azerbaijan, Bahamas, The, Bangladesh, Belarus, Belize, Bhutan, Bolivia, Bosnia and Herzegovina, Botswana, Brazil, Brunei Darussalam, Bulgaria, Cabo Verde, Cambodia, Chile, China, Colombia, Costa Rica, Croatia, Czechia, Dominican Republic, Ecuador, Egypt, Arab Rep., El Salvador, Estonia, Fiji, France, Gabon, Georgia, Ghana, Greece, Guatemala, Honduras, Hungary, India, Indonesia, Iran, Islamic Rep., Iraq, Italy, Kazakhstan, Kyrgyz Republic, Latvia, Lebanon, Lithuania, Malaysia, Maldives, Mauritius, Mexico, Moldova, Mongolia, Montenegro, Morocco, Nepal, Nicaragua, North Macedonia, Oman, Panama, Paraguay, Peru, Philippines, Poland, Portugal, Romania, Russian Federation, Sao Tome and Principe, Saudi Arabia, Senegal, Serbia, Slovak Republic, Slovenia, South Africa, Spain, Sri Lanka, Tajikistan, Thailand, Timor-Leste, Tonga, Tunisia, Turkiye, Ukraine, Uruguay, Uzbekistan, Viet Nam, West Bank and Gaza
Grupo 3 34
Angola, Benin, Burkina Faso, Cameroon, Central African Republic, Chad, Comoros, Congo, Rep., Cote d’Ivoire, Equatorial Guinea, Eswatini, Ethiopia, Gambia, The, Guinea, Guinea-Bissau, Haiti, Kenya, Lesotho, Madagascar, Malawi, Mali, Mauritania, Mozambique, Namibia, Niger, Pakistan, Rwanda, Sierra Leone, Solomon Islands, Tanzania, Togo, Uganda, Zambia, Zimbabwe

5.1.5 Visualización de los segmentos de países

5.1.5.1 Plano de los componentes 1 y 2

df_pl <- data.frame(country = rownames(Z), Grupo = cl, Z)

p12 <- ggplot(df_pl, aes(x = CP1, y = CP2, color = Grupo)) +
  geom_hline(yintercept = 0, color = "gray80") + geom_vline(xintercept = 0, color = "gray80") +
  stat_ellipse(type = "norm", level = 0.9, linetype = "dashed", linewidth = 0.4, show.legend = FALSE) +
  geom_point(aes(text = paste0("<b>", country, "</b><br>", Grupo,
                               "<br>CP1: ", fmt(CP1, 2), "<br>CP2: ", fmt(CP2, 2))),
             size = 2.3, alpha = 0.85) +
  scale_color_manual(values = col_cl[1:k_final]) +
  labs(title = "Países según los dos primeros componentes",
       x = paste0("CP1: nivel general de desarrollo (", fmt(pve[1], 1), " %)"),
       y = paste0("CP2: apertura comercial (", fmt(pve[2], 1), " %)"))

mostrar(p12, alto = 520)

El primer eje ordena a los países por su nivel general de desarrollo (CP1) y el segundo por su apertura comercial (CP2, con signo invertido: valores bajos indican más importaciones y exportaciones respecto al PIB). Los países del mismo color son similares en estos factores; el solapamiento entre elipses señala países frontera entre dos perfiles.

En el plano CP1–CP2 los tres grupos se ordenan de izquierda a derecha en el eje de desarrollo: el Grupo 3 a la izquierda, el Grupo 2 al centro y el Grupo 1 a la derecha, con poco solapamiento entre el Grupo 3 y el resto. La mayor mezcla ocurre entre el Grupo 1 y el 2, donde se ubican los países frontera (Corea del Sur, Nueva Zelanda, Japón y Canadá, en el Grupo 1, y Senegal y Ghana, en el Grupo 2, tienen siluetas cercanas a cero o negativas). Luxemburgo y Singapur quedan muy aislados en el extremo derecho.

5.1.5.2 Plano de los componentes 3 y 4

p34 <- ggplot(df_pl, aes(x = CP3, y = CP4, color = Grupo)) +
  geom_hline(yintercept = 0, color = "gray80") + geom_vline(xintercept = 0, color = "gray80") +
  geom_point(aes(text = paste0("<b>", country, "</b><br>", Grupo,
                               "<br>CP3: ", fmt(CP3, 2), "<br>CP4: ", fmt(CP4, 2))),
             size = 2.3, alpha = 0.85) +
  scale_color_manual(values = col_cl[1:k_final]) +
  labs(title = "Países según los componentes 3 y 4",
       x = paste0("CP3: desempleo frente a ingreso (", fmt(pve[3], 1), " %)"),
       y = paste0("CP4: área forestal (", fmt(pve[4], 1), " %)"))

mostrar(p34, alto = 520)

En el plano CP3–CP4 los grupos se superponen mucho más, en coherencia con que la partición explica solo el 33,4 % de la variabilidad de CP3 y el 1,5 % de CP4: estos dos factores aportan poca información para separar los grupos. La única diferencia apreciable es que el Grupo 1 tiende a valores bajos de CP3 (bajo desempleo y alto ingreso) y el Grupo 2 a valores algo positivos.

5.1.5.3 Distribución geográfica de los grupos

datos_cl_mapa <- data.frame(country = ajustar_nombres_mapa(datos_cl$country), Grupo = datos_cl$Grupo)
mapa_grupos   <- left_join(map_data("world"), datos_cl_mapa, by = c("region" = "country"))

g_mapa <- ggplot(mapa_grupos, aes(x = long, y = lat, group = group, fill = Grupo,
                                  text = paste0("País: ", region, "<br>", Grupo))) +
  geom_polygon(color = "white", linewidth = 0.1) +
  scale_fill_manual(values = col_cl[1:k_final], na.value = "gray85", na.translate = FALSE, name = "Grupo") +
  theme_void() +
  labs(title = "Grupos de desarrollo identificados por el método de Ward (2019)",
       subtitle = "Los países en gris no están en la base final o no coinciden con la cartografía") +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0.5, color = "#7A0016"),
        plot.subtitle = element_text(size = 10, hjust = 0.5),
        legend.position = "right")

ggplotly(g_mapa, tooltip = "text")

El mapa permite examinar si los grupos siguen patrones geográficos (países vecinos o de una misma región que comparten perfil) o si hay países de regiones distantes con niveles de desarrollo similares, que es justamente la ventaja de agrupar por indicadores y no por ubicación.

El mapa muestra un patrón regional marcado: el Grupo 3 se concentra en África subsahariana; el Grupo 1, en América del Norte, Europa occidental y nórdica, Oceanía, Japón, Corea del Sur y el Golfo Pérsico; y el Grupo 2 cubre América Latina, buena parte de Europa del sur y del este, Asia central, el sudeste asiático y el norte de África. Los grupos siguen en buena medida las regiones, pero no de manera estricta: Francia, Italia y España quedan en el Grupo 2 y Yibuti, un país africano, aparece en el Grupo 1.

5.1.6 Calidad de la partición

sil    <- cluster::silhouette(as.integer(cl), d_euc)
sil_df <- data.frame(country = rownames(Z), Grupo = cl, Silueta = sil[, "sil_width"])

tab_sil <- sil_df %>%
  group_by(Grupo) %>%
  summarise(n = n(), Silueta_media = mean(Silueta), Negativas = sum(Silueta < 0), .groups = "drop")

tabla(tab_sil, digits = 3,
      caption = "Tabla 12. Silueta promedio por grupo y países con silueta negativa",
      col.names = c("Grupo", "Países", "Silueta media", "Países con silueta < 0"))
Tabla 12. Silueta promedio por grupo y países con silueta negativa
Grupo Países Silueta media Países con silueta < 0
Grupo 1 28 0,139 3
Grupo 2 88 0,438 2
Grupo 3 34 0,423 1
fviz_silhouette(sil, palette = col_cl[1:k_final], ggtheme = theme_minimal(),
                print.summary = FALSE, main = "Gráfico de siluetas por país")

borde <- sil_df %>% arrange(Silueta) %>% head(8)
tabla(borde, digits = 3,
      caption = "Tabla 13. Países peor asignados a su grupo (menor silueta)",
      col.names = c("País", "Grupo asignado", "Silueta"))
Tabla 13. Países peor asignados a su grupo (menor silueta)
País Grupo asignado Silueta
Djibouti Grupo 1 -0,174
Senegal Grupo 2 -0,136
Eswatini Grupo 3 -0,088
Korea, Rep.  Grupo 1 -0,053
Ghana Grupo 2 -0,041
New Zealand Grupo 1 -0,023
Japan Grupo 1 0,005
Canada Grupo 1 0,006
analisis(
  "La silueta promedio global es de **", fmt(mean(sil_df$Silueta), 3), "**. ",
  "Los países de la Tabla 13 son los menos nítidamente ubicados: están a una distancia similar de su grupo y del grupo vecino, ",
  "por lo que se comportan como **países frontera** y su asignación es la más sensible a cambios de método o de k. ",
  ifelse(sum(sil_df$Silueta < 0) == 0,
         "Ningún país tiene silueta negativa, es decir, todos están más cerca de su propio grupo que del vecino.",
         paste0("Hay ", sum(sil_df$Silueta < 0), " países con silueta negativa, es decir, más cercanos al grupo vecino que al propio."))
)

La silueta promedio global es de 0,379. Los países de la Tabla 13 son los menos nítidamente ubicados: están a una distancia similar de su grupo y del grupo vecino, por lo que se comportan como países frontera y su asignación es la más sensible a cambios de método o de k. Hay 6 países con silueta negativa, es decir, más cercanos al grupo vecino que al propio.

Lectura. Lectura. La silueta promedio global es 0,379, un valor intermedio-bajo (en la escala de Kaufman y Rousseeuw, 0,26–0,50 corresponde a una estructura débil). Esto indica que los países no forman bloques completamente separados, sino un continuo de desarrollo que la partición recorta en tres tramos. Aun así, la partición es informativa por varias razones: (i) el grupo de menor desarrollo (silueta 0,423) y el grupo intermedio (0,438) están bien definidos, y el primero se mantiene idéntico al pasar de 2 a 3 grupos; (ii) la debilidad se concentra en el Grupo 1 (0,139), que mezcla economías diversificadas con casos extremos de comercio e inversión, y en seis países frontera con silueta negativa, algo esperable cuando la variable de fondo es continua; y (iii) las diferencias entre los perfiles son grandes en las variables sustantivas (por ejemplo, PIB per cápita promedio de 52.168, 9.912 y 1.561 USD). Los grupos deben leerse, por tanto, como perfiles descriptivos de un gradiente y no como categorías naturales. el Grupo 1 es el más débil (0,139). Seis países tienen silueta negativa: Yibuti (−0,174), Corea del Sur (−0,053) y Nueva Zelanda (−0,023) en el Grupo 1; Senegal (−0,136) y Ghana (−0,041) en el Grupo 2; y Esuatini (−0,088) en el Grupo 3. Son países frontera cuya asignación depende del método y de k. La presencia de Yibuti en el Grupo 1 es la asignación menos intuitiva y se explica por sus valores extremos de comercio (exportaciones e importaciones superiores al 150 % del PIB, unas cuatro desviaciones estándar sobre el promedio), que lo acercan a economías muy abiertas como Singapur, aunque su ingreso (unos 2.800 USD per cápita) y sus indicadores sociales son muy distintos a los del grupo.

5.2 Respuestas a las preguntas del taller

¿Qué componentes principales explican mayor variabilidad y qué representan? CP1 (41,0 %) representa el nivel general de desarrollo (ingreso, salud, conectividad, fertilidad); CP2 (13,6 %), la apertura comercial; CP3 (8,9 %), el mercado laboral frente al ingreso; y CP4 (7,0 %), las condiciones ambientales. Juntos acumulan el 70,5 % de la varianza.

¿Cuántos clusters se formaron y qué características definen cada grupo? Tres: un grupo de alto ingreso y alta conectividad (28 países), un bloque intermedio muy numeroso y diverso (88) y un grupo con fuerte rezago en salud, acceso a electricidad y conectividad (34).

¿Se observan patrones interesantes? Sí. La diferencia entre grupos es sobre todo de nivel de desarrollo (CP1, 77,8 % de su variabilidad entre grupos). Hay un patrón geográfico claro, con África subsahariana concentrada en el grupo de menor desarrollo y países de alto ingreso de Norteamérica, Europa, Oceanía y Asia oriental en el de mayor desarrollo, pero también excepciones (Francia, Italia y España en el grupo intermedio; Yibuti en el de mayor ingreso). Además, ni el desempleo ni el área forestal separan a los grupos de manera clara.


6 Conclusiones

Sobre los componentes principales. El ACP resumió los 15 indicadores de 150 países en 4 componentes que acumulan el 70,5 % de la varianza total (según el criterio de Kaiser, 4 componentes tienen autovalor mayor que 1). El primero, con el 41,0 %, representa el nivel general de desarrollo: opone a los países con mayor esperanza de vida, conectividad, acceso a electricidad e ingreso a los de mayor fertilidad y mortalidad infantil. El segundo (13,6 %) recoge la apertura comercial, el tercero (8,9 %) el contraste entre mercado laboral e ingreso y el cuarto (7,0 %) las condiciones ambientales (área forestal). Que un solo componente concentre buena parte de la variabilidad indica que muchos indicadores de desarrollo se mueven juntos.

Sobre los grupos. El método de Ward aplicado a los factores del ACP formó 3 grupos de países, con una silueta promedio de 0,379 y una inercia explicada del 54,0 %. Los perfiles son los siguientes:

Dado que la silueta promedio indica una estructura de intensidad intermedia-baja, los grupos se interpretan como perfiles dentro de un continuo de desarrollo; el grupo de menor desarrollo es el más nítido y los Grupos 1 y 2 presentan una frontera más difusa.

for (g in levels(cl)) {
  cat("- **", g, "** (", sum(cl == g), " países): ", desc_grupo[g], ".\n", sep = "")
}
  • Grupo 1 (28 países): por encima del promedio mundial en inb per cápita, pib per cápita y uso de internet; por debajo en tasa de fertilidad y mortalidad infantil.
  • Grupo 2 (88 países): sin indicadores claramente por encima del promedio; sin indicadores claramente por debajo del promedio.
  • Grupo 3 (34 países): por encima del promedio mundial en tasa de fertilidad y mortalidad infantil; por debajo en acceso a electricidad, uso de internet y esperanza de vida.

Sobre los patrones observados. La partición separa con más claridad a los países en el factor CP1, donde los grupos explican el 77,8 % de su variabilidad, es decir, la diferencia entre grupos es sobre todo de nivel de desarrollo (ingreso, salud y conectividad) y mucho menos de apertura comercial o de entorno. Los grupos siguen un gradiente que va de los países con mayor ingreso, esperanza de vida y conectividad a los de mayor rezago en salud, electricidad y acceso a internet, y al visualizarlos en el mapa se aprecia una agrupación geográfica de países con condiciones similares. En suma, el análisis sí permitió identificar patrones de desarrollo entre países sin partir de una clasificación predefinida como la de nivel de ingreso o región.

6.1 Usos reales en economía y políticas públicas

Este tipo de análisis tiene aplicaciones concretas, entre ellas:

  • Focalización de políticas y de recursos. Agrupar países (o regiones, departamentos o municipios) con perfiles parecidos permite diseñar intervenciones distintas para cada grupo, en lugar de aplicar una misma política a todos. Por ejemplo, priorizar infraestructura básica y salud en los grupos más rezagados y conectividad o innovación en los intermedios.
  • Cooperación internacional y asignación de ayuda. Organismos multilaterales y agencias de cooperación pueden usar segmentaciones multivariadas para decidir a qué países dirigir programas de financiamiento o asistencia técnica, con base en varias dimensiones y no solo en el PIB per cápita.
  • Comparación y aprendizaje entre pares. Los países de un mismo grupo comparten condiciones de partida, así que son referentes realistas unos de otros para evaluar políticas exitosas. Los más cercanos al centro del grupo sirven de punto de comparación (benchmarking).
  • Seguimiento de metas de desarrollo. Repetir el ejercicio en distintos años permite ver si los países cambian de grupo y si las brechas se cierran o se amplían, por ejemplo en acceso a electricidad o a internet.
  • Análisis de riesgo e inversión. Gobiernos, bancos y empresas pueden usar los grupos para identificar mercados con características similares y definir estrategias de inversión o de expansión.
  • Reducción de dimensionalidad en la gestión pública. El ACP permite construir indicadores sintéticos (como el primer componente) que resumen muchas variables en un índice fácil de comunicar y de monitorear.

Bibliografía

  • Banco Mundial. (2019). World Development Indicators [Base de datos]. The World Bank Group. https://databank.worldbank.org/source/world-development-indicators
  • James, G., Witten, D., Hastie, T., y Tibshirani, R. (2021). An Introduction to Statistical Learning with Applications in R (2.ª ed.). Springer.
  • Johnson, R. A., y Wichern, D. W. (2007). Applied Multivariate Statistical Analysis (6.ª ed.). Pearson Prentice Hall.
  • Jolliffe, I. T. (2002). Principal Component Analysis (2.ª ed.). Springer.
  • Kaiser, H. F. (1960). The application of electronic computers to factor analysis. Educational and Psychological Measurement, 20(1), 141–151.
  • Kassambara, A., y Mundt, F. (2020). factoextra: Extract and Visualize the Results of Multivariate Data Analyses (R package version 1.0.7). https://CRAN.R-project.org/package=factoextra
  • Murtagh, F., y Legendre, P. (2014). Ward’s hierarchical agglomerative clustering method: Which algorithms implement Ward’s criterion? Journal of Classification, 31(3), 274–295.
  • Rousseeuw, P. J. (1987). Silhouettes: A graphical aid to the interpretation and validation of cluster analysis. Journal of Computational and Applied Mathematics, 20, 53–65.
  • Ward, J. H. (1963). Hierarchical grouping to optimize an objective function. Journal of the American Statistical Association, 58(301), 236–244.
Universidad del Valle · Gestión de Datos · Taller 3: ACP y Clustering jerárquico de Ward