164 países
15 indicadores WDI
4 componentes principales
3 perfiles de países
164 países 15 indicadores del Banco Mundial Año 2021 ODS 7 · energía asequible y no contaminante 4 componentes principales 74,7% de la varianza 3 perfiles de transición Método de Ward 164 países 15 indicadores del Banco Mundial Año 2021 ODS 7 · energía asequible y no contaminante 4 componentes principales 74,7% de la varianza 3 perfiles de transición Método de Ward

Introducción

En 2015, los países de las Naciones Unidas se comprometieron a que, para 2030, todas las personas tengan acceso a energía asequible, segura, sostenible y moderna lo cual hace parte del Objetivo de Desarrollo Sostenible 7, parece una sola meta, pero son tres: que todos tengan electricidad y puedan cocinar sin humo (meta 7.1), que las energías renovables ganen peso (meta 7.2) y que la energía se use con más eficiencia (meta 7.3). A esto se suma el compromiso del Acuerdo de París de reducir las emisiones. El Consejo Mundial de la Energía (World Energy Council, 2021) lo resume como un trilema y es que cada país tiene que equilibrar la equidad, es decir, que la energía llegue a todos, la sostenibilidad ambiental que contamine poco y el desarrollo económico que impulse la producción.

El problema es que estas metas no siempre avanzan juntas. Nuestros propios datos lo muestran:

La lección es que mirar un solo indicador engaña. Un ranking de energía renovable pondría a países sin electricidad por delante de Alemania y uno de ingreso pondría a los grandes exportadores de petróleo como modelo de desarrollo. Parte de la explicación es la escalera energética (Hosier & Dowd, 1987; Leach, 1992) que nos dice que los hogares pobres cocinan con leña y carbón vegetal que cuentan como energía renovable y al subir el ingreso los cambian por electricidad y combustibles fósiles, y solo más adelante, y no en todos los países, llegan las renovables modernas.

Por eso en este trabajo miramos varios indicadores a la vez: 15 del Banco Mundial (World Development Indicators) para 164 países en 2021. Cubren el acceso, las renovables y la eficiencia, las consecuencias ambientales (emisiones, aire y bosques) y el contexto económico y demográfico. Usamos aprendizaje no supervisado, es decir, no predecimos nada dejamos que los datos muestren qué países se parecen. Primero resumimos los 15 indicadores en unas pocas dimensiones (Análisis de Componentes Principales, ACP) y luego agrupamos los países parecidos (método de Ward).

Pregunta de investigación ¿Qué grupos de países se pueden identificar a partir de sus indicadores energéticos, ambientales, económicos y demográficos en 2021, y cuáles son las principales diferencias entre ellos en relación con la transición energética?

El objetivo es identificar y describir perfiles de países según su situación energética, ambiental y socioeconómica en 2021, así mismo, buscamos describir cómo se comportan los 15 indicadores y cómo se relacionan con el ingreso y la región, resumir esos indicadores en pocas dimensiones e interpretar qué representa cada una, agrupar los países con esas dimensiones y caracterizar cada grupo y proponer implicaciones de política pública diferenciadas para cada grupo.

Alcance del estudio. El análisis es transversal (un solo año) y descriptivo. Permite identificar asociaciones entre indicadores y perfiles de países en 2021, pero no explicar qué factores causan la transición energética ni reconstruir la evolución de cada país en el tiempo. Los grupos obtenidos son una segmentación exploratoria, relativa a los 15 indicadores seleccionados, y no una clasificación universal o permanente de los países.

Metodología

La investigación adopta un enfoque cuantitativo, descriptivo y transversal, orientado a caracterizar las diferencias entre países en materia de transición energética y sostenibilidad ambiental. La unidad de análisis es cada país y el período de referencia es el año 2021. Al tratarse de aprendizaje no supervisado, no se define una variable dependiente ni se busca predecir. El propósito es explorar la estructura de los datos, identificar las principales dimensiones de variabilidad y reconocer grupos de países con características similares.

¿Qué países se analizan?

La muestra incluye 164 países de todos los continentes. El mapa permite ver la cobertura geográfica y cambiar entre cinco indicadores clave con el control de la esquina superior derecha. Los 20 estados insulares o de territorio muy pequeño que no se distinguen a esta escala se representan con círculos.

Figura 1Cobertura de la muestra y distribución geográfica de los indicadores clave
capas_mapa <- c(
  "Países incluidos"        = "incluido",
  "Energía renovable (%)"   = "Energia_renovable",
  "Acceso a electricidad (%)" = "Acceso_electricidad",
  "CO2 per cápita (t)"      = "Emisiones_CO2",
  "PM2.5 (µg/m³)"           = "Contaminacion_PM25"
)
paletas <- c(Energia_renovable = "YlGn", Acceso_electricidad = "Greens",
             Emisiones_CO2 = "YlOrBr", Contaminacion_PM25 = "OrRd")

mundo$incluido <- ifelse(is.na(mundo$country), NA, 1)
pequenos$incluido <- 1

# Mapa base sin teselas externas (no dependen de claves de API): el oceano lo da el fondo del contenedor
mapa <- leaflet(mundo, options = leafletOptions(minZoom = 1, maxZoom = 6, zoomSnap = .25,
                                                attributionControl = FALSE)) %>%
  setView(lng = 12, lat = 20, zoom = 1.6)

for (nombre in names(capas_mapa)) {
  v <- capas_mapa[[nombre]]
  valores <- mundo[[v]]
  todos <- c(valores, pequenos[[v]])

  if (v == "incluido") {
    fpal <- colorNumeric(pal[["natural"]], c(1, 1), na.color = "#E6E6E6")
  } else if (v == "Emisiones_CO2") {
    fpal <- colorQuantile(paletas[[v]], todos, n = 5, na.color = "#E6E6E6")
  } else {
    fpal <- colorNumeric(paletas[[v]], todos, na.color = "#E6E6E6")
  }

  clase_leyenda <- paste0("info legend leyenda-capa capa-", match(nombre, names(capas_mapa)) - 1)

  etiqueta_valor <- function(datos) {
    if (v == "incluido") return(ifelse(is.na(datos$country), "No incluido (información incompleta)", paste0(datos$pais, " · incluido")))
    ifelse(is.na(datos[[v]]), "Sin datos", paste0(datos$pais, ": ", num(datos[[v]], 1)))
  }

  mapa <- mapa %>%
    addPolygons(
      fillColor = fpal(valores), fillOpacity = .85, weight = .6, color = "#FFFFFF",
      group = nombre, label = etiqueta_valor(mundo),
      highlightOptions = highlightOptions(weight = 2, color = pal[["profundo"]], bringToFront = TRUE)
    ) %>%
    addCircleMarkers(
      data = pequenos, radius = 4, stroke = TRUE, color = "#FFFFFF", weight = 1,
      fillColor = fpal(pequenos[[v]]), fillOpacity = .95,
      group = nombre, label = etiqueta_valor(pequenos)
    )

  if (v == "incluido") {
    mapa <- mapa %>% addLegend("bottomleft", colors = c(pal[["natural"]], "#E6E6E6"),
                               labels = c("Incluido", "Sin información completa"),
                               title = "Muestra", opacity = .9, className = clase_leyenda)
  } else if (v == "Emisiones_CO2") {
    mapa <- mapa %>% addLegend("bottomleft", pal = fpal, values = todos[!is.na(todos)],
                               title = "CO2 per cápita<br>(quintiles)", opacity = .9, className = clase_leyenda,
                               labFormat = function(type, cuts, p) paste0(num(head(cuts, -1), 1), " – ", num(cuts[-1], 1)))
  } else {
    mapa <- mapa %>% addLegend("bottomleft", pal = fpal, values = todos[!is.na(todos)],
                               title = nombre, opacity = .9, className = clase_leyenda)
  }
}

# Solo se muestra la leyenda de la capa activa
mapa %>%
  addLayersControl(baseGroups = names(capas_mapa), position = "topright",
                   options = layersControlOptions(collapsed = FALSE)) %>%
  htmlwidgets::onRender(sprintf("
    function(el, x) {
      var capas = %s;
      var map = this;
      function mostrar(nombre) {
        var i = capas.indexOf(nombre);
        el.querySelectorAll('.leyenda-capa').forEach(function(l) {
          l.style.display = l.classList.contains('capa-' + i) ? '' : 'none';
        });
      }
      map.on('baselayerchange', function(e) { mostrar(e.name); });
      mostrar(capas[0]);
    }", jsonlite::toJSON(names(capas_mapa))))

Fuente: elaboración propia con datos WDI, Banco Mundial (2021). Los países en gris no tienen información completa para los 15 indicadores.

La muestra cubre casi toda América, Europa y Asia, y buena parte de África y Oceanía. Las principales ausencias son países con estadísticas incompletas para 2021, entre ellos algunos con más de 20 millones de habitantes, como Etiopía, Venezuela, Angola, Yemen, Nepal, Burkina Faso y Corea del Norte. Esto debe tenerse en cuenta al interpretar los resultados, en particular para África oriental y para países afectados por conflictos. Las capas temáticas anticipan el patrón central del estudio: el mapa de energía renovable es casi el negativo del mapa de acceso a electricidad.

Variables de estudio

Para caracterizar a los países se seleccionaron 15 variables cuantitativas de la base World Development Indicators del Banco Mundial, distribuidas en cuatro dimensiones: energía, medio ambiente, economía y demografía. La selección aborda la transición energética desde diferentes perspectivas, incorporando tanto indicadores directamente relacionados con el uso y el acceso a la energía como variables que contextualizan las condiciones ambientales, productivas y poblacionales de cada país. La tabla relaciona cada indicador con la meta del ODS 7 o con el aspecto del trilema energético que representa.

Tabla 1Indicadores seleccionados del Banco Mundial
# TABLA DESCRIPCION DE LAS VARIABLES

tabla_variables <- data.frame(
  Dimension = c(
    rep("Energia", 7),
    rep("Medio ambiente", 4),
    rep("Economia", 2),
    rep("Demografia", 2)
  ),

  Variable = c(
    "Consumo de energia renovable",
    "Electricidad generada de fuentes renovables",
    "Intensidad energetica",
    "Acceso a electricidad",
    "Acceso rural a electricidad",
    "Acceso a tecnologias limpias para cocinar",
    "Acceso rural a tecnologias limpias para cocinar",
    "Emisiones de CO2 per capita",
    "Emisiones totales de GEI per capita",
    "Contaminacion por PM2.5",
    "Superficie forestal",
    "PIB per capita PPA",
    "Valor agregado industrial",
    "Poblacion urbana",
    "Crecimiento poblacional"
  ),

  Codigo = c(
    "EG.FEC.RNEW.ZS",
    "EG.ELC.RNEW.ZS",
    "EG.EGY.PRIM.PP.KD",
    "EG.ELC.ACCS.ZS",
    "EG.ELC.ACCS.RU.ZS",
    "EG.CFT.ACCS.ZS",
    "EG.CFT.ACCS.RU.ZS",
    "EN.GHG.CO2.PC.CE.AR5",
    "EN.GHG.ALL.PC.CE.AR5",
    "EN.ATM.PM25.MC.M3",
    "AG.LND.FRST.ZS",
    "NY.GDP.PCAP.PP.KD",
    "NV.IND.TOTL.ZS",
    "SP.URB.TOTL.IN.ZS",
    "SP.POP.GROW"
  ),

  Unidad = c(
    "% del consumo final",
    "% de la generacion electrica",
    "MJ por dolar PPA del PIB de 2021",
    "% de la poblacion",
    "% de la poblacion rural",
    "% de la poblacion",
    "% de la poblacion rural",
    "t CO2e por persona",
    "t CO2e por persona",
    "Microgramos por metro cubico",
    "% de la superficie terrestre",
    "Dolares internacionales constantes de 2021",
    "% del PIB",
    "% de la poblacion",
    "% anual"
  ),

  Relacion = c(
    "ODS 7.2 · Sostenibilidad",
    "ODS 7.2 · Sostenibilidad",
    "ODS 7.3 · Eficiencia",
    "ODS 7.1 · Equidad",
    "ODS 7.1 · Equidad",
    "ODS 7.1 · Equidad",
    "ODS 7.1 · Equidad",
    "Acuerdo de París · Sostenibilidad",
    "Acuerdo de París · Sostenibilidad",
    "Salud ambiental",
    "Capital natural",
    "Desarrollo económico",
    "Estructura productiva",
    "Demanda energética",
    "Presión demográfica"
  )
)

reactable(
  tabla_variables,
  groupBy = "Dimension",
  defaultExpanded = TRUE,
  pagination = FALSE,
  striped = TRUE,
  compact = TRUE,
  columns = list(
    Dimension = colDef(name = "Dimensión", minWidth = 120),
    Variable = colDef(minWidth = 230),
    Codigo = colDef(name = "Código WDI", minWidth = 150,
                    style = list(fontFamily = "IBM Plex Mono, monospace", fontSize = "12px")),
    Unidad = colDef(minWidth = 180),
    Relacion = colDef(name = "ODS 7 / trilema", minWidth = 190,
                      cell = function(value) span(class = "etiqueta-ods", value))
  ),
  theme = reactableTheme(headerStyle = list(background = pal[["bosque"]], color = "white"))
)

Fuente: elaboración propia a partir de World Development Indicators (WDI), Banco Mundial. Los nombres y códigos de los países se usan solo como identificadores y no son variables activas del ACP.

Criterio de selección del año y de las variables

Año. La elección de 2021 responde a tres criterios:

  • Disponibilidad simultánea de los datos: el ACP y la clusterización exigen que cada país tenga información en todas las variables y los indicadores del ODS 7 como consumo final de energía renovable, intensidad energética y acceso a cocina limpia se construyen a partir de balances energéticos nacionales que se publican con varios años de rezago. Por eso, 2021 es el año más reciente en el que estos indicadores coinciden con las series de emisiones, contaminación y PIB para un número amplio de países: con él se conservan 164 de los 217 registros de países y economías (75,6%).
  • Comparabilidad: todas las variables están medidas con criterios homogéneos entre países, con el PIB y la intensidad energética en dólares PPA constantes de 2021 y las emisiones en toneladas de CO2 equivalente con los potenciales de calentamiento del IPCC (AR5), lo que evita mezclar años o unidades.
  • Contexto económico: 2021 es el primer año de reactivación después del choque de la pandemia de COVID-19. Usar 2020 habría reflejado una caída atípica de la actividad, del consumo de energía y de las emisiones, mientras que 2021 refleja mejor la estructura energética habitual de los países, aunque todavía con efectos de la recuperación.

Variables. Las 15 variables responden a tres preguntas: ¿De dónde proviene la energía y qué tan eficiente es su uso? (renovables e intensidad energética), ¿Quién tiene acceso a servicios energéticos modernos? (acceso total y rural a electricidad y a cocina limpia) y ¿Qué consecuencias ambientales y qué contexto socioeconómico acompañan esas decisiones? (emisiones, PM2.5, bosques, ingreso, industria, urbanización y crecimiento poblacional). La inclusión del acceso rural permite medir la brecha territorial, y la distinción entre consumo renovable total y electricidad renovable permite separar la biomasa tradicional como la leña de las renovables modernas.

Construcción, limpieza e integración de la base de datos

La información proviene de World Development Indicators (WDI), una base de datos administrada por el Banco Mundial que reúne indicadores internacionales sobre desarrollo económico, social y ambiental. Se obtuvo con el paquete WDI de R, que permite consultar directamente los indicadores disponibles en la plataforma oficial.

Fuente de información: https://databank.worldbank.org/source/world-development-indicators

Primero se descargaron los indicadores y se organizó la información usando el país y el año como criterios de correspondencia. Después se excluyeron los agregados regionales y económicos, con el fin de conservar solo observaciones individuales. Este procedimiento dejó 217 registros iniciales de países y economías.

A continuación se evaluó la disponibilidad de información de cada indicador y se conservaron únicamente las observaciones con valores completos en las 15 variables. Se excluyeron 53 registros incompletos y la base quedó conformada por 164 países, aproximadamente el 75,6% de las observaciones iniciales. No se aplicaron procedimientos de imputación, interpolación ni sustitución de datos faltantes.

La información se organizó en formato tabular: cada fila es un país y cada columna uno de los indicadores. Además se conservaron tres columnas de identificación (nombre del país, código ISO de tres letras y año de referencia). La base depurada se almacenó en el archivo Banco_Mundial_Energia_2021.csv.

Tabla 2Base de datos definitiva - Banco Mundial, 2021
DT::datatable(
  base_final %>% select(País = pais, ISO = iso3c, all_of(variables)),
  rownames = FALSE,
  filter = "top",
  extensions = "Buttons",
  options = list(
    pageLength = 8,
    lengthMenu = c(8, 25, 50, 100, 164),
    scrollX = TRUE,
    dom = "Bfltip",
    buttons = c("copy", "csv", "excel"),
    language = list(
      search = "Buscar:",
      lengthMenu = "Mostrar _MENU_ registros",
      info = "Mostrando _START_ a _END_ de _TOTAL_ países",
      paginate = list(previous = "Anterior", "next" = "Siguiente")
    )
  )
) %>%
  formatRound(columns = variables, digits = 2, mark = ".", dec.mark = ",")

Descripción del modelo

El análisis se desarrolla en cinco etapas encadenadas. Cada una usa como insumo el resultado de la anterior:

1EstandarizaciónPuntajes z para que ninguna unidad de medida domine.
2ACP15 variables correlacionadas → pocos componentes independientes.
3DistanciasDistancia euclidiana entre países en el espacio de componentes.
4WardAgrupamiento jerárquico que minimiza la varianza interna.
5CaracterizaciónValores test para describir y nombrar cada grupo.

Resultados descriptivos

El análisis descriptivo se organiza en torno a cuatro preguntas que se desprenden del trilema energético. Primero se presenta un panorama general de los indicadores y luego cada pregunta se responde con una figura y un hallazgo principal. El objetivo no es solo describir promedios, sino identificar las relaciones que justifican el análisis multivariado posterior.

Panorama general

74
países aún sin cobertura eléctrica universal
46
países donde menos de la mitad de la población cocina con combustibles limpios
22,2%
mediana de energía renovable en el consumo final
98%
de los países supera la guía de la OMS para PM2.5 (5 µg/m³)
Tabla 3Estadísticas descriptivas de los 15 indicadores (2021)
# ============================================================
# ESTADISTICAS DESCRIPTIVAS
# ============================================================

asimetria <- function(x) mean((x - mean(x))^3) / sd(x)^3

descriptivas <- map_dfr(variables, function(v) {
  x <- base_final[[v]]
  tibble(
    Dimension = dimension_var[[v]],
    Indicador = etiquetas[[v]],
    Media = mean(x),
    Mediana = median(x),
    DE = sd(x),
    CV = 100 * sd(x) / mean(x),
    Asimetria = asimetria(x),
    Minimo = paste0(num(min(x), 1), " · ", base_final$pais[which.min(x)]),
    Maximo = paste0(num(max(x), 1), " · ", base_final$pais[which.max(x)])
  )
})

cv_co2 <- descriptivas$CV[descriptivas$Indicador == etiquetas[["Emisiones_CO2"]]]
formato <- function(d = 2) function(value) num(value, d)

reactable(
  descriptivas,
  groupBy = "Dimension",
  defaultExpanded = TRUE,
  pagination = FALSE,
  compact = TRUE,
  columns = list(
    Dimension = colDef(name = "Dimensión", minWidth = 110),
    Indicador = colDef(minWidth = 220),
    Media = colDef(cell = formato(), align = "right"),
    Mediana = colDef(cell = formato(), align = "right"),
    DE = colDef(name = "Desv. est.", cell = formato(), align = "right"),
    CV = colDef(name = "CV (%)", minWidth = 130, align = "left",
                cell = function(value) {
                  ancho <- paste0(min(100, value / 2), "%")
                  div(class = "barra-cv",
                      div(class = "barra-relleno", style = list(width = ancho)),
                      span(num(value, 0)))
                }),
    Asimetria = colDef(name = "Asimetría", align = "right",
                       cell = formato(),
                       style = function(value) if (abs(value) > 1) list(color = pal[["terracota"]], fontWeight = 700)),
    Minimo = colDef(name = "Mínimo · país", minWidth = 190),
    Maximo = colDef(name = "Máximo · país", minWidth = 190)
  ),
  theme = reactableTheme(headerStyle = list(background = pal[["bosque"]], color = "white"))
)

El coeficiente de variación (CV) mide la dispersión relativa. Las asimetrías mayores a 1 en valor absoluto se resaltan en color terracota.

En la tabla se muestran tres comportamientos distintos. El primer comportamiento corresponde a las brechas de acceso que se concentran en una minoría de países. Tenemos que el acceso a electricidad tiene media de 86,9% y mediana de 100%, donde presenta una asimetría negativa: la mayoría de los países ya está en el techo y la dispersión proviene de un grupo de países con coberturas muy pero muy bajas. La cocina limpia tiene una dispersión mucho mayor con una desviación de 36,1 puntos, lo que indica que es la meta del ODS 7 más rezagada.

El segundo comportamiento es el de las desigualdades extremas. Las emisiones de CO2 (CV de 162%), las de GEI y el PIB per cápita tienen la media muy por encima de lo que es la mediana ya que unos pocos países concentran valores extremos: Palaos y los Petro estados del Golfo en emisiones, y Luxemburgo, Singapur e Irlanda en ingreso. Vemos que en estas variables la media resulta engañosa. La media de CO2 es de 5,04 t per cápita, pero la mediana es de 2,70 t, y la media del PIB per cápita (US$ 25.120) supera en más de 50% a la mediana (US$ 16.061). Por eso, en el resto del análisis descriptivo se usan medianas, que no se ven arrastradas por los valores extremos que se presentan, Estas colas largas también nos ayudan a justificar estandarizar antes del ACP y tener precaución con los casos atípicos en la clusterización.

El tercero es el de una variable que esconde dos realidades: la energía renovable va de 0,0% a 96,3%, y su máximo está en la República Democrática del Congo que es uno de los países con menor acceso a electricidad del mundo. Con este contraste podemos anticipar la pregunta central del análisis descriptivo.

Pregunta 1. ¿Qué cambia cuando un país se enriquece?

La escalera energéticaVemos que si la hipótesis de la escalera energética es correcta, significa que los indicadores deberían cambiar de forma sistemática a medida que aumenta el ingreso. Para comprobarlo se hizo que los países se dividieron en cinco quintiles de PIB per cápita y se calculó la mediana de cada indicador en cada quintil.
Figura 2La escalera energética: indicadores clave por quintil de PIB per cápita
indicadores_escalera <- c("Energia_renovable", "Electricidad_renovable", "Cocina_limpia",
                          "Emisiones_CO2", "Contaminacion_PM25", "Intensidad_energetica")

escalera <- base_final %>%
  select(quintil, all_of(indicadores_escalera)) %>%
  pivot_longer(-quintil, names_to = "variable", values_to = "valor") %>%
  group_by(variable, quintil) %>%
  summarise(mediana = median(valor), q1 = quantile(valor, .25), q3 = quantile(valor, .75),
            .groups = "drop") %>%
  mutate(variable = factor(cortas[variable], levels = cortas[indicadores_escalera]))

g_escalera <- escalera %>%
  ggplot(aes(quintil, mediana, group = variable,
             text = paste0("<b>", variable, "</b><br>", gsub("\n", " ", quintil),
                           "<br>Mediana: ", num(mediana, 2),
                           "<br>Rango intercuartil: ", num(q1, 2), " – ", num(q3, 2)))) +
  geom_ribbon(aes(ymin = q1, ymax = q3), fill = pal[["menta"]], alpha = .7) +
  geom_line(colour = pal[["bosque"]], linewidth = 1.1) +
  geom_point(colour = pal[["bosque"]], fill = pal[["dorado"]], shape = 21, size = 3, stroke = 1.1) +
  facet_wrap(~variable, scales = "free_y", ncol = 3) +
  labs(x = NULL, y = NULL) +
  theme(panel.spacing = unit(1.4, "lines"), axis.text.x = element_text(size = 8))

# Animacion: los paises de cada quintil en el plano cocina limpia - energia renovable
animacion <- base_final %>%
  mutate(q = gsub("\n", " ", quintil)) %>%
  plot_ly(x = ~Cocina_limpia, y = ~Energia_renovable, frame = ~q,
          type = "scatter", mode = "markers",
          size = ~sqrt(Emisiones_CO2), sizes = c(10, 55),
          color = ~log10(Emisiones_CO2), colors = c(pal[["menta"]], "#E0A230", pal[["terracota"]], pal[["profundo"]]),
          marker = list(opacity = .85, line = list(color = "white", width = 1), sizemode = "diameter"),
          text = ~paste0("<b>", pais, "</b><br>", q, "<br>Cocina limpia: ", num(Cocina_limpia, 0), "%",
                         "<br>Renovable: ", num(Energia_renovable), "%<br>CO2: ", num(Emisiones_CO2, 2), " t pc"),
          hoverinfo = "text") %>%
  colorbar(title = "CO2 pc<br>(log10 t)") %>%
  layout(xaxis = list(title = "Población con cocina limpia (%)", range = c(-5, 108), zeroline = FALSE),
         yaxis = list(title = "Energía renovable (% del consumo)", range = c(-5, 105), zeroline = FALSE),
         annotations = list(
           list(x = 4, y = 100, text = "Biomasa tradicional", showarrow = FALSE, xanchor = "left",
                font = list(color = pal[["terracota"]], size = 13)),
           list(x = 104, y = 4, text = "Modernos de base fósil", showarrow = FALSE, xanchor = "right",
                font = list(color = pal[["profundo"]], size = 13)))) %>%
  animation_opts(frame = 1500, transition = 800, easing = "cubic-in-out", redraw = FALSE) %>%
  animation_slider(currentvalue = list(prefix = "Quintil de ingreso: ", font = list(color = pal[["bosque"]], size = 15))) %>%
  animation_button(label = "▶ Subir la escalera", x = 0, xanchor = "left", y = -0.18,
                   bgcolor = pal[["dorado"]], font = list(color = pal[["profundo"]])) %>%
  estilo_plotly()

selector_vistas(list(
  "Medianas por quintil" = interactivo(g_escalera, tooltip = "text"),
  "▶ La escalera en movimiento" = animacion
), "escalera", alto = 660)

Primera vista: la línea une las medianas y la franja verde muestra el rango intercuartil de cada quintil. Segunda vista: pulse «Subir la escalera» para ver cómo se desplazan los países al pasar de un quintil de ingreso al siguiente; el tamaño y el color de cada burbuja indican sus emisiones de CO2.

Hallazgo

Los datos son coherentes con la escalera energética, pero la energía renovable sigue una curva en U. Al pasar del quintil más pobre al más rico, la mediana de cocina limpia sube de 8,0% a 100,0% y la mediana de PM2.5 baja de 32,3 a 10,4 µg/m³. Es decir, los países de mayor ingreso tienen, en mediana, más acceso a servicios energéticos modernos y un aire local menos contaminado. Pero esto no equivale a un mejor desempeño ambiental en todos los indicadores: la mediana de emisiones de CO2 se multiplica por más de 25 (de 0,3 a 8,3 t per cápita).

La energía renovable, en cambio, no aumenta con el ingreso, esta cae de 71,1% en el quintil más pobre a 9,7% en el quintil medio, vemos que cuando los países abandonan la leña y adoptan combustibles fósiles, y solo se recupera levemente en los quintiles altos (12,5%). La electricidad renovable dibuja exactamente la misma U. Con este patrón respaldaría la expectativa E1 y sugiere que la adopción de renovables modernas no acompaña automáticamente a un mayor ingreso. Tenemos que recordar que esto se trata de una comparación entre países distintos en un mismo año, no de la evolución de un país a lo largo del tiempo.

Pregunta 2. ¿Renovable significa limpio?

La paradoja renovableTenemos que para separar las renovables tradicionales de las modernas se cruzó la participación renovable con el acceso a cocina limpia, un indicador directo del abandono de la leña. Los umbrales del 50% dividen a los países en cuatro cuadrantes.
Figura 3Energía renovable frente a acceso a cocina limpia: cuatro perfiles de países
cuadrantes <- base_final %>%
  mutate(cuadrante = case_when(
    Energia_renovable >= 50 & Cocina_limpia < 50  ~ "Renovable tradicional",
    Energia_renovable >= 50 & Cocina_limpia >= 50 ~ "Renovable moderna",
    Energia_renovable < 50 & Cocina_limpia >= 50  ~ "Moderno de base fósil",
    TRUE                                          ~ "Doble rezago"
  ))
conteo_cuad <- count(cuadrantes, cuadrante)
n_cuad <- function(x) conteo_cuad$n[conteo_cuad$cuadrante == x]

g_cuad <- ggplot(highlight_key(cuadrantes, ~region), aes(Cocina_limpia, Energia_renovable)) +
  annotate("rect", xmin = -2, xmax = 50, ymin = 50, ymax = 100, fill = "#F6E3DB", alpha = .8) +
  annotate("rect", xmin = 50, xmax = 102, ymin = 50, ymax = 100, fill = "#DDF1E8", alpha = .9) +
  annotate("rect", xmin = 50, xmax = 102, ymin = -2, ymax = 50, fill = "#ECEFF1", alpha = .9) +
  annotate("rect", xmin = -2, xmax = 50, ymin = -2, ymax = 50, fill = "#FBF1D9", alpha = .9) +
  annotate("text", x = 2, y = 98, hjust = 0, size = 3.6, colour = pal[["terracota"]],
           label = paste0("Renovable tradicional (", n_cuad("Renovable tradicional"), ")")) +
  annotate("text", x = 100, y = 98, hjust = 1, size = 3.6, colour = pal[["bosque"]],
           label = paste0("Renovable moderna (", n_cuad("Renovable moderna"), ")")) +
  annotate("text", x = 100, y = 46, hjust = 1, size = 3.6, colour = "#4D5B63",
           label = paste0("Moderno de base fósil (", n_cuad("Moderno de base fósil"), ")")) +
  annotate("text", x = 2, y = 46, hjust = 0, size = 3.6, colour = "#9A7316",
           label = paste0("Doble rezago (", n_cuad("Doble rezago"), ")")) +
  geom_point(aes(colour = region,
                 text = paste0("<b>", pais, "</b><br>", cuadrante,
                               "<br>Renovable: ", num(Energia_renovable), "%",
                               "<br>Cocina limpia: ", num(Cocina_limpia, 0), "%",
                               "<br>Electricidad renovable: ", num(Electricidad_renovable), "%")),
             size = 2.6, alpha = .85) +
  scale_colour_manual(values = col_region) +
  coord_cartesian(xlim = c(0, 100), ylim = c(0, 100), expand = FALSE) +
  labs(x = "Población con acceso a cocina limpia (%)", y = "Energía renovable (% del consumo final)", colour = NULL)

interactivo(g_cuad, tooltip = "text") %>%
  layout(legend = list(orientation = "h", y = -0.22)) %>%
  highlight(on = "plotly_hover", off = "plotly_doubleclick", opacityDim = .18, selected = attrs_selected(showlegend = FALSE))

Pase el cursor sobre un país para resaltar a los demás países de su región; doble clic para restablecer.

Hallazgo

La mayoría de los países muy renovables lo son por pobreza energética. De los 39 países con más del 50% de energía renovable, 30 están en el cuadrante renovable tradicional, notamos que su población cocina mayoritariamente con la leña o el carbón vegetal y su renovable proviene de biomasa, una fuente asociada a deforestación y a contaminación del aire dentro de los hogares. Solo 9 países combinan alta participación renovable con acceso masivo a cocina limpia.

El cuadrante más poblado es el moderno de base fósil (109 países): ya superaron la pobreza energética, pero lo hicieron con petróleo, gas y carbón. Con un criterio algo más flexible (renovable ≥ 30% y cocina limpia ≥ 90%) aparecen 15 países los cuales combinan ambas condiciones en 2021: Gabón, Bután, Noruega, Suecia, Uruguay, Finlandia, Brasil, Letonia, Dinamarca, Estonia, Austria, Costa Rica, Croacia, Lituania, Portugal. Como podemos notar su mayoría son países europeos y latinoamericanos con abundante hidroenergía.

Pregunta 3. ¿Emiten más CO₂ los países más ricos?

Ingreso y emisionesSe analiza la relación entre el PIB per cápita y las emisiones de CO2 per cápita de 164 países en 2021. El gráfico utiliza escalas logarítmicas para facilitar la comparación de países con ingresos y emisiones muy diferentes. Se destacan en dorado los países con PIB per cápita de al menos US$ 30.000 y emisiones inferiores a 5 toneladas por habitante. Los umbrales son referencias descriptivas: 5 toneladas equivalen al promedio de emisiones de los 164 países y US$ 30.000 casi duplican la mediana del PIB per cápita.
Figura 4Emisiones de CO2 frente a PIB per cápita (escala logarítmica)
tipos_ingreso <- base_final %>%
  mutate(tipo = case_when(
    PIB_per_capita >= 30000 & Emisiones_CO2 < 5 ~ "Ingreso alto con bajas emisiones",
    PIB_per_capita >= 30000 ~ "Ingreso alto con altas emisiones",
    TRUE ~ "Resto de países"
  ))

ricos <- filter(tipos_ingreso, PIB_per_capita >= 30000)
ingreso_alto_baja_emision <- filter(tipos_ingreso, tipo == "Ingreso alto con bajas emisiones")

# Correlación descriptiva entre los logaritmos del ingreso y las emisiones
cor_log_ingreso_emisiones <- cor(
  log(base_final$PIB_per_capita),
  log(base_final$Emisiones_CO2)
)

# Gráfico de dispersión
g_emi <- ggplot(highlight_key(tipos_ingreso, ~tipo), aes(PIB_per_capita, Emisiones_CO2)) +
  geom_point(aes(colour = tipo,
                 text = paste0("<b>", pais, "</b><br>PIB pc: US$ ", num(PIB_per_capita, 0),
                               "<br>CO2: ", num(Emisiones_CO2, 2), " t per cápita",
                               "<br>Electricidad renovable: ", num(Electricidad_renovable), "%")),
             size = 2.7, alpha = .85) +
  scale_x_log10(labels = scales::dollar) +
  scale_y_log10(labels = function(x) num(x, 1)) +
  scale_colour_manual(values = c("Ingreso alto con bajas emisiones" = "#E0A230",
                                 "Ingreso alto con altas emisiones" = pal[["profundo"]],
                                 "Resto de países" = "#9DB8AE")) +
  labs(x = "PIB per cápita PPA (escala logarítmica)",
       y = "CO2 per cápita (t, escala logarítmica)",
       colour = NULL)

interactivo(g_emi, tooltip = "text") %>%
  layout(legend = list(orientation = "h", y = -0.2)) %>%
  highlight(on = "plotly_hover",
            off = "plotly_doubleclick",
            opacityDim = .18,
            selected = attrs_selected(showlegend = FALSE))

Pase el cursor sobre un país para resaltar a los demás de su mismo grupo; doble clic para restablecer.

Hallazgo

En el gráfico observamos una relación positiva entre el ingreso y las emisiones de CO₂ per cápita. La correlación entre los logaritmos de ambas variables es de 0,83, lo que indica una asociación positiva fuerte. Sin embargo, los países con mayores ingresos no presentan necesariamente los mismos niveles de emisiones.

De los 50 países con un PIB per cápita de al menos US$ 30.000, 10 registran emisiones inferiores a 5 toneladas de CO₂ por habitante. Por ejemplo, Malta (US$ 56.824; 3,1 t), Suecia (US$ 62.191; 3,9 t) y Suiza (US$ 83.525; 4,3 t) presentan ingresos elevados y emisiones relativamente bajas. En contraste, Catar registra un PIB per cápita de US$ 116.833 y emisiones de 47,3 toneladas por habitante.

Estos resultados muestran que el ingreso no es suficiente para describir las diferencias en las emisiones de CO₂ entre países. Por esta razón, es importante considerar también los demás indicadores energéticos, ambientales, económicos y demográficos para identificar patrones más completos mediante el ACP.

Pregunta 4. ¿Dónde están las mayores brechas?

Brechas regionales y territorialesVemos que la figura resume cada región con la mediana de sus países en cada indicador expresada en las desviaciones estándar con respecto al promedio mundial, los tonos verdes nos indican valores por encima del promedio y los terracota por debajo, el valor real aparece al pasar el cursor.
Figura 5Perfil de las regiones: mediana estandarizada de cada indicador
z <- base_final %>% mutate(across(all_of(variables), ~ as.numeric(scale(.x))))

perfil_region <- z %>%
  group_by(region) %>%
  summarise(across(all_of(variables), median), n = n(), .groups = "drop") %>%
  pivot_longer(all_of(variables), names_to = "variable", values_to = "z") %>%
  left_join(
    base_final %>% group_by(region) %>%
      summarise(across(all_of(variables), median), .groups = "drop") %>%
      pivot_longer(-region, names_to = "variable", values_to = "real"),
    by = c("region", "variable")
  ) %>%
  mutate(variable = factor(cortas[variable], levels = rev(cortas)),
         region = paste0(region, " (", n, ")"))

g_region <- perfil_region %>%
  ggplot(aes(region, variable, fill = z,
             text = paste0("<b>", region, "</b><br>", variable,
                           "<br>Mediana: ", num(real, 2), "<br>Puntaje z: ", num(z, 2)))) +
  geom_tile(colour = "white", linewidth = .7) +
  geom_text(aes(label = num(z, 1)), size = 3, colour = ifelse(abs(perfil_region$z) > 1, "white", pal[["profundo"]])) +
  scale_fill_gradient2(low = pal[["terracota"]], mid = "#FFFFFF", high = pal[["bosque"]], midpoint = 0,
                       limits = c(-2.2, 2.2), oob = scales::squish, name = "z") +
  scale_x_discrete(position = "top", labels = function(x) str_wrap(x, 16)) +
  labs(x = NULL, y = NULL) +
  theme(panel.grid = element_blank(), axis.text.x = element_text(size = 8.5))

interactivo(g_region, tooltip = "text")
Figura 6Brecha entre el acceso eléctrico nacional y el rural: los 12 países con mayor diferencia
brecha <- base_final %>%
  mutate(brecha = Acceso_electricidad - Electricidad_rural) %>%
  slice_max(brecha, n = 12) %>%
  mutate(pais = fct_reorder(pais, brecha))

g_brecha <- brecha %>%
  ggplot(aes(y = pais)) +
  geom_segment(aes(x = Electricidad_rural, xend = Acceso_electricidad, yend = pais),
               colour = "#C9D8D1", linewidth = 2.4, lineend = "round") +
  geom_point(aes(x = Electricidad_rural, text = paste0(pais, "<br>Rural: ", num(Electricidad_rural), "%")),
             colour = pal[["terracota"]], size = 3.6) +
  geom_point(aes(x = Acceso_electricidad, text = paste0(pais, "<br>Nacional: ", num(Acceso_electricidad), "%",
                                                       "<br>Brecha: ", num(brecha), " puntos")),
             colour = pal[["bosque"]], size = 3.6) +
  labs(x = "Población con acceso a electricidad (%) · terracota = rural, verde = nacional", y = NULL)

interactivo(g_brecha, tooltip = "text")

Hallazgo

La pobreza energética es africana y rural; la contaminación del aire se concentra en Medio Oriente y Asia del Sur. Vemos que Africa Subsahariana es la región con mayor participación renovable con una mediana del 71,1% y al mismo tiempo la de menor acceso a electricidad con 53,4% y a cocina limpia del 10,0%. En el extremo opuesto, la región de Medio Oriente, Norte de África, Afganistán y Pakistán (agrupación vigente del Banco Mundial) tiene la menor participación renovable 6,1%, la peor calidad del aire (PM2.5 de 41,1 µg/m³), apenas 1,7% de cobertura forestal y emisiones de 4,1 t per cápita, por encima de la mediana mundial, en este caso, se puede evidenciar que Asia del Sur combina un acceso eléctrico casi universal con la segunda peor calidad del aire (32,5 µg/m³). Europa y América Latina tienen la misma mediana de electricidad renovable (38,2%) y acceso universal, pero Europa emite más del doble (5,3 frente a 2,3 t per cápita) y América Latina conserva más bosque.

Dentro de los países, la brecha es territorial. En Guinea Ecuatorial, Gabón y Botsuana la diferencia entre el acceso nacional y el rural supera los 45 puntos porcentuales: la electricidad llega a las ciudades, pero no al campo. En promedio, el acceso rural a cocina limpia está 8,3 puntos por debajo del nacional.

Síntesis del análisis descriptivo

Como una breve conclusión tenemos que los cuatro hallazgos muestran que las variables están fuertemente interrelacionadas pero no se mueven en una sola dirección. Por ejemplo, el ingreso mejora el acceso y la calidad del aire pero aumenta las emisiones. La energía renovable alcanza su máximo en los países más pobres y su mínimo en los de ingreso medio y las regiones muestran combinaciones distintas de acceso, emisiones y renovables. Notamos que ningún indicador por sí solo permite clasificar a los países, lo que justifica usar el ACP para encontrar las dimensiones que resumen esta complejidad y la clusterización para identificar perfiles.

Resultados del modelo

Análisis de Componentes Principales (ACP)

Correlaciones y adecuación de los datos

Figura 7Matriz de correlaciones de Pearson, con variables ordenadas por similitud
R <- cor(X)
orden <- hclust(as.dist(1 - R))$order

cor_df <- as.data.frame(as.table(R)) %>%
  setNames(c("v1", "v2", "r")) %>%
  mutate(v1 = factor(cortas[as.character(v1)], levels = cortas[orden]),
         v2 = factor(cortas[as.character(v2)], levels = rev(cortas[orden])))

g_cor <- ggplot(cor_df, aes(v1, v2, fill = r, text = paste0(v1, " vs ", v2, "<br>r = ", num(r, 2)))) +
  geom_tile(colour = "white", linewidth = .4) +
  geom_text(aes(label = sub("^(-?)0", "\\1", formatC(r, format = "f", digits = 2))),
            size = 2.6, colour = ifelse(abs(cor_df$r) > .6, "white", pal[["profundo"]])) +
  scale_fill_gradient2(low = pal[["terracota"]], mid = "#FFFFFF", high = pal[["bosque"]], limits = c(-1, 1), name = "r") +
  labs(x = NULL, y = NULL) +
  theme(axis.text.x = element_text(angle = 40, hjust = 1, size = 9), axis.text.y = element_text(size = 9),
        panel.grid = element_blank())

interactivo(g_cor, tooltip = "text")
# Prueba de esfericidad de Bartlett
n <- nrow(X); p <- ncol(X)
chi_bartlett <- -(n - 1 - (2 * p + 5) / 6) * log(det(R))
gl_bartlett <- p * (p - 1) / 2
p_bartlett <- pchisq(chi_bartlett, gl_bartlett, lower.tail = FALSE)

# Observaciones por variable (tamano de muestra para el ACP)
razon_np <- n / p
2.455
χ² de Bartlett con 105 gl (p < 0,001)
10,9
países por variable: por encima del mínimo recomendado de 10
0,98
correlación entre CO2 y GEI: información redundante
−0,75
correlación entre renovables y acceso a electricidad

Al ordenar las variables por similitud aparecen tres bloques importantes: - Acceso y modernización: las variables electricidad y cocina limpia, total y rural aparecen con correlaciones entre 0,77 y 0,96 asociadas positivamente con el PIB per cápita y la urbanización. - Emisiones: CO2 y GEI prácticamente miden lo mismo r = 0,98. - Energía renovable en oposición: se correlaciona negativamente con el acceso (r = -0,75) y positivamente con el crecimiento poblacional r = 0,48, lo que expresa numéricamente la paradoja renovable. La superficie forestal y la contaminación por PM2.5 casi no se relacionan con el resto, lo que anticipa que formarán componentes propios.

La prueba de Bartlett rechaza con amplitud la hipótesis de que la matriz de correlaciones sea una identidad (χ² = 2.455, p < 0,001), es decir, las variables comparten suficiente información como para resumirlas en componentes. Además, la muestra tiene 10,9 países por variable, por encima de la proporción de 10 a 1 que Hair et al. (2019) consideran deseable. Por tanto, los datos son adecuados para el ACP.

Varianza explicada

# Valores propios de los 15 componentes (la matriz de correlaciones equivale a trabajar con datos estandarizados)
valores_propios <- eigen(cor(X), only.values = TRUE)$values
eig <- tibble(
  componente = factor(paste0("CP", seq_along(valores_propios)), levels = paste0("CP", seq_along(valores_propios))),
  valor_propio = valores_propios,
  varianza = 100 * valores_propios / sum(valores_propios),
  acumulada = cumsum(varianza)
)

# Criterio de Kaiser: se retienen los componentes con valor propio mayor que 1
k_cp <- sum(eig$valor_propio > 1)
acp <- PCA(X, scale.unit = TRUE, ncp = k_cp, graph = FALSE)
Figura 8Gráfico de sedimentación: varianza por componente y varianza acumulada
g_scree <- eig %>%
  ggplot(aes(componente)) +
  geom_col(aes(y = varianza, fill = valor_propio > 1,
               text = paste0(componente, "<br>Valor propio: ", num(valor_propio, 3),
                             "<br>Varianza: ", num(varianza, 2), "%",
                             "<br>Acumulada: ", num(acumulada, 2), "%")), width = .7) +
  geom_line(aes(y = acumulada, group = 1), colour = "#E0A230", linewidth = 1.1) +
  geom_point(aes(y = acumulada), colour = "#E0A230", size = 2.6) +
  geom_hline(yintercept = 100 / length(variables), linetype = "dashed", colour = pal[["terracota"]]) +
  annotate("text", x = 12.5, y = 100 / length(variables) + 3, hjust = .5, size = 3.3, colour = pal[["terracota"]],
           label = "Criterio de Kaiser (valor propio = 1)") +
  geom_vline(xintercept = k_cp + .5, linetype = "dotted", colour = pal[["profundo"]]) +
  annotate("text", x = k_cp + 2.4, y = 96, hjust = .5, size = 3.3, colour = pal[["profundo"]],
           label = paste0("Se retienen ", k_cp, " componentes (", num(eig$acumulada[k_cp]), "%)")) +
  scale_fill_manual(values = c(`TRUE` = pal[["bosque"]], `FALSE` = pal[["menta"]]), guide = "none") +
  scale_y_continuous(breaks = seq(0, 100, 20), limits = c(0, 102)) +
  labs(x = NULL, y = "% de varianza (barras) y acumulada (línea)")

interactivo(g_scree, tooltip = "text") %>% layout(margin = list(b = 60))

Los 4 primeros componentes tienen valor propio mayor que 1 como podemos observar en las barras verde oscuro y en conjunto explican el 74,7% de la varianza total. El gráfico tiene un codo pronunciado después del CP1 y otro quiebre después del CP4. A partir del CP5, cada componente aporta menos que el promedio de una variable (línea punteada en 6,67%). Por los tres criterios se retienen 4 componentes. El CP1 por sí solo explica el 42,0%, lo que indica que existe un eje dominante que ordena a los países.

Algo importante que resaltar es que el signo de cada componente es arbitrario, es decir, si se invirtiera la lectura sería la misma con los polos intercambiados. Lo que importa es qué variables cargan juntas y en direcciones opuestas y dónde se ubican los países respecto a esas variables. Por eso los nombres que siguen se basan en las variables con cargas mayores a 0,5 en valor absoluto y con contribuciones superiores al promedio (100/15 = 6,67%).

¿Qué representa cada componente?

CP1

Modernización y acceso energético

42,0% de la varianza

Eje dominante y sintético: no mide solo el acceso a electricidad, sino un conjunto de rasgos que aparecen juntos (acceso a electricidad y cocina limpia, ingreso, urbanización y menor crecimiento poblacional), frente a la dependencia de la biomasa tradicional.

Polo positivo Cocina limpia (0,92), acceso a electricidad (0,86), PIB per cápita (0,71), urbanización (0,70) Países: Catar, Palaos, Singapur, Kuwait
Polo negativo Energía renovable (−0,82), crecimiento poblacional (−0,70) Países: República Democrática del Congo, Burundi, República Centroafricana, Malaui
CP2

Emisiones e intensidad energética

15,9% de la varianza

Independiente del CP1. Agrupa tres fenómenos relacionados pero distintos: emisiones de gases de efecto invernadero (efecto climático global), intensidad energética (eficiencia) y PM2.5 (contaminación local del aire). Distingue a las economías intensivas en hidrocarburos e industria.

Polo positivo GEI (0,68), intensidad energética (0,66), CO2 (0,65), PM2.5 (0,64), industria (0,57) Países: Catar, Palaos, Kuwait, Baréin
Polo negativo Sin cargas negativas fuertes: economías pequeñas, de servicios y poco intensivas en energía Países: San Vicente y las Granadinas, Dominica, Maldivas, Costa Rica
CP3

Cobertura forestal y contaminación del aire

9,5% de la varianza

Eje territorial-ambiental: opone territorios boscosos a países áridos con aire más contaminado. La cobertura forestal es un indicador de capital natural, no una medida completa de sostenibilidad.

Polo positivo Superficie forestal (0,72), electricidad renovable (0,45) Países: Palaos, Liberia, Finlandia, Suecia
Polo negativo Contaminación PM2.5 (−0,56) Países: Bangladés, Irak, Egipto, Pakistán
CP4

Electricidad renovable e ingreso

7,4% de la varianza

Recoge la combinación de electricidad renovable e ingreso alto. Una matriz eléctrica renovable no implica bajas emisiones en toda la economía (transporte e industria pueden seguir usando fósiles). Catar aparece en el polo positivo por su ingreso, no por su matriz.

Polo positivo Electricidad renovable (0,62), PIB per cápita (0,42) Países: Luxemburgo, Noruega, Catar, Dinamarca
Polo negativo Superficie forestal (−0,41), intensidad energética (−0,26) Países: Palaos, Micronesia, Fed. Sts., Trinidad y Tobago, Islas Salomón

La siguiente figura muestra la evidencia en que se basa esta interpretación. Con los botones se cambia entre las cargas factoriales y los círculos de correlaciones de tres planos factoriales.

Figura 9Evidencia para la interpretación de los componentes
# --- Cargas factoriales
cargas <- as.data.frame(acp$var$cor) %>%
  rownames_to_column("variable") %>%
  pivot_longer(-variable, names_to = "cp", values_to = "carga") %>%
  mutate(cp = sub("Dim.", "CP", cp), variable = factor(cortas[variable], levels = rev(cortas)),
         contrib = as.vector(t(acp$var$contrib)))

g_cargas <- ggplot(cargas, aes(cp, variable, fill = carga,
                               text = paste0(variable, "<br>", cp, "<br>Carga: ", num(carga, 3),
                                             "<br>Contribución: ", num(contrib, 1), "%"))) +
  geom_tile(colour = "white", linewidth = .6) +
  geom_text(aes(label = num(carga, 2)), size = 3.1, colour = ifelse(abs(cargas$carga) > .5, "white", pal[["profundo"]])) +
  scale_fill_gradient2(low = pal[["terracota"]], mid = "white", high = pal[["bosque"]], limits = c(-1, 1), name = "Carga") +
  scale_x_discrete(position = "top") +
  labs(x = NULL, y = NULL) +
  theme(panel.grid = element_blank())

# --- Circulo de correlaciones: flechas coloreadas por dimension, grosor y opacidad segun la calidad (cos2)
col_dim <- c("Energía" = pal[["bosque"]], "Medio ambiente" = "#E0A230", "Economía" = pal[["terracota"]], "Demografía" = "#4F9DA6")
nombre_cp <- c("Modernización", "Emisiones y contaminación", "Bosque frente a PM2.5", "Electricidad renovable")

circulo <- function(a, b) {
  v <- tibble(variable = variables, nombre = cortas[variables], dimension = dimension_var[variables],
              x = acp$var$coord[, a], y = acp$var$coord[, b],
              cos2 = acp$var$cos2[, a] + acp$var$cos2[, b],
              contrib = (acp$var$contrib[, a] * eig$valor_propio[a] + acp$var$contrib[, b] * eig$valor_propio[b]) /
                        (eig$valor_propio[a] + eig$valor_propio[b]))
  t <- seq(0, 2 * pi, length.out = 240)

  flechas <- lapply(seq_len(nrow(v)), function(i) list(
    x = v$x[i], y = v$y[i], ax = 0, ay = 0, xref = "x", yref = "y", axref = "x", ayref = "y",
    text = "", showarrow = TRUE, arrowhead = 2, arrowsize = 1.1, arrowwidth = 1.2 + 2.6 * v$cos2[i],
    arrowcolor = col_dim[[v$dimension[i]]], opacity = .35 + .65 * v$cos2[i]))
  sentidos <- list(
    list(x = 1, y = 0, xref = "paper", yref = "paper", xanchor = "right", yanchor = "bottom", showarrow = FALSE,
         text = paste0("CP", a, ": ", nombre_cp[a], " →"), font = list(size = 11, color = "#5C7469")),
    list(x = 0, y = 1, xref = "paper", yref = "paper", xanchor = "left", yanchor = "top", showarrow = FALSE,
         text = paste0("↑ CP", b, ": ", nombre_cp[b]), font = list(size = 11, color = "#5C7469")))

  # Las variables con flechas casi superpuestas comparten una sola etiqueta para que el texto no se encime
  grupo_txt <- cutree(hclust(dist(cbind(v$x, v$y)), method = "single"), h = .13)
  etiquetas_txt <- v %>%
    mutate(g = grupo_txt) %>%
    group_by(g) %>%
    summarise(x = mean(x), y = mean(y), texto = paste(nombre, collapse = "<br>"),
              color = if (n_distinct(dimension) == 1) col_dim[[first(dimension)]] else pal[["profundo"]],
              .groups = "drop")

  fig <- plot_ly() %>%
    add_trace(x = cos(t), y = sin(t), type = "scatter", mode = "lines", fill = "toself",
              fillcolor = "rgba(197,235,221,.18)", line = list(color = pal[["natural"]], width = 1.6),
              hoverinfo = "skip", showlegend = FALSE) %>%
    add_trace(x = .5 * cos(t), y = .5 * sin(t), type = "scatter", mode = "lines",
              line = list(color = "#B9CEC3", width = 1, dash = "dot"), hoverinfo = "skip", showlegend = FALSE)

  for (d in names(col_dim)) {
    vd <- filter(v, dimension == d)
    fig <- fig %>% add_trace(
      x = vd$x, y = vd$y, type = "scatter", mode = "markers", name = d, cliponaxis = FALSE,
      marker = list(size = 6 + 8 * vd$cos2, color = col_dim[[d]], line = list(color = "white", width = 1.5)),
      hovertext = paste0("<b>", vd$nombre, "</b> · ", d,
                         "<br>Correlación con CP", a, ": ", num(vd$x, 2),
                         "<br>Correlación con CP", b, ": ", num(vd$y, 2),
                         "<br>Calidad de representación (cos²): ", num(vd$cos2, 2),
                         "<br>Contribución al plano: ", num(vd$contrib, 1), "%"),
      hoverinfo = "text")
  }

  fig <- fig %>% add_trace(
    x = etiquetas_txt$x, y = etiquetas_txt$y, type = "scatter", mode = "text", showlegend = FALSE,
    cliponaxis = FALSE, hoverinfo = "skip", text = etiquetas_txt$texto,
    textposition = ifelse(etiquetas_txt$x >= 0, "middle right", "middle left"),
    textfont = list(size = 11.5, color = etiquetas_txt$color))

  fig %>%
    layout(
      annotations = c(flechas, sentidos),
      xaxis = list(title = paste0("CP", a, " · ", nombre_cp[a], " (", num(eig$varianza[a]), "%)"),
                   range = c(-1.6, 1.6), zeroline = TRUE, zerolinecolor = "#B9CEC3", scaleanchor = "y"),
      yaxis = list(title = paste0("CP", b, " · ", nombre_cp[b], " (", num(eig$varianza[b]), "%)"),
                   range = c(-1.22, 1.22), zeroline = TRUE, zerolinecolor = "#B9CEC3"),
      legend = list(orientation = "h", y = -0.14, title = list(text = "Dimensión: "))
    ) %>%
    estilo_plotly()
}

# --- Paises en el espacio de los tres primeros componentes
# (se conservan estas definiciones porque la figura de los clusters usa grafico_3d)
coord_ind <- as.data.frame(acp$ind$coord) %>%
  setNames(paste0("CP", 1:4)) %>%
  mutate(pais = base_final$pais, region = base_final$region)

# Aporte de cada pais a la inercia del espacio CP1-CP3 (suma de sus contribuciones ponderadas por los valores propios)
contrib_3d <- 100 * rowSums(acp$ind$coord[, 1:3]^2) / (nrow(X) * sum(eig$valor_propio[1:3]))
destacados <- union(names(sort(contrib_3d, decreasing = TRUE))[1:10],
                    unlist(lapply(1:3, function(j) names(sort(acp$ind$contrib[, j], decreasing = TRUE))[1:2])))

# Giro automatico de la camara; se detiene cuando el usuario interactua con el grafico
js_giro <- "
function(el) {
  var ang = -0.75, r = 1.75, z = 0.62, girando = true, ocupado = false;
  el.style.position = 'relative';
  var btn = document.createElement('button');
  btn.type = 'button'; btn.className = 'btn-giro'; btn.textContent = '⏸ Pausar giro';
  el.appendChild(btn);
  function fijar(estado) { girando = estado; btn.textContent = estado ? '⏸ Pausar giro' : '⟳ Girar'; }
  if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) { fijar(false); }
  btn.addEventListener('click', function(e) { e.stopPropagation(); fijar(!girando); });
  ['mousedown', 'wheel', 'touchstart'].forEach(function(ev) {
    el.addEventListener(ev, function(e) { if (e.target !== btn) fijar(false); }, { passive: true });
  });
  setInterval(function() {
    if (!girando || el.offsetParent === null) return;
    if (ocupado && Date.now() - ocupado < 500) return;
    var caja = el.getBoundingClientRect();
    if (caja.bottom < 0 || caja.top > window.innerHeight) return;
    ang += 0.01; ocupado = Date.now();
    Plotly.relayout(el, { 'scene.camera.eye': { x: r * Math.cos(ang), y: r * Math.sin(ang), z: z } })
      .then(function() { ocupado = false; }, function() { ocupado = false; });
  }, 60);
}"

eje_3d <- function(titulo) list(title = titulo, backgroundcolor = "#F3F8F5", showbackground = TRUE,
                                gridcolor = "#D9E7DF", zerolinecolor = "#8FB3A3", tickfont = list(size = 10))

grafico_3d <- function(grupo, colores, centroides = FALSE) {
  d <- coord_ind %>%
    mutate(grupo = as.character(.data[[grupo]]), aporte = contrib_3d,
           info = paste0("<b>", pais, "</b><br>", grupo,
                         "<br>CP1: ", num(CP1, 2), " · CP2: ", num(CP2, 2), " · CP3: ", num(CP3, 2),
                         "<br>Aporte a la inercia (CP1–CP3): ", num(aporte, 2), "%"))
  fig <- plot_ly()
  for (g in names(colores)) {
    dg <- filter(d, grupo == g)
    if (nrow(dg) == 0) next
    fig <- fig %>% add_trace(
      x = dg$CP1, y = dg$CP2, z = dg$CP3, type = "scatter3d", mode = "markers", name = g,
      marker = list(size = 3.5 + 10 * sqrt(dg$aporte / max(d$aporte)), color = colores[[g]], opacity = .88,
                    line = list(color = "white", width = .6)),
      hovertext = dg$info, hoverinfo = "text")
  }
  cortos <- c("República Democrática del Congo" = "RD Congo", "República Centroafricana" = "Rep. Centroafricana")
  top <- filter(d, pais %in% destacados) %>%
    mutate(etiqueta = ifelse(pais %in% names(cortos), cortos[pais], pais))
  fig <- fig %>%
    add_trace(x = top$CP1, y = top$CP2, z = top$CP3, type = "scatter3d", mode = "text",
              name = "Países que más aportan", text = top$etiqueta, textposition = "top center",
              textfont = list(size = 11, color = pal[["profundo"]]), hoverinfo = "skip")
  if (centroides) {
    cen <- d %>% group_by(grupo) %>% summarise(across(c(CP1, CP2, CP3), mean), .groups = "drop")
    fig <- fig %>% add_trace(
      x = cen$CP1, y = cen$CP2, z = cen$CP3, type = "scatter3d", mode = "markers", name = "Centroides",
      marker = list(size = 13, symbol = "diamond", color = unname(colores[cen$grupo]),
                    line = list(color = "white", width = 3)),
      hovertext = paste0("<b>Centroide</b><br>", cen$grupo), hoverinfo = "text")
  }
  fig %>%
    layout(scene = list(xaxis = eje_3d("CP1 · Modernización"), yaxis = eje_3d("CP2 · Emisiones y contaminación"),
                        zaxis = eje_3d("CP3 · Bosque vs. PM2.5"), aspectmode = "cube",
                        domain = list(x = c(0, 1), y = c(.1, 1)),
                        camera = list(eye = list(x = 1.28, y = -1.19, z = .62))),
           legend = list(orientation = "h", y = 0, font = list(size = 11.5)),
           margin = list(l = 0, r = 0, t = 10, b = 0)) %>%
    estilo_plotly(rejilla = FALSE) %>%
    htmlwidgets::onRender(js_giro)
}

vistas <- list(
  "Cargas" = interactivo(g_cargas, tooltip = "text"),
  "Círculo CP1–CP2" = circulo(1, 2),
  "Círculo CP1–CP3" = circulo(1, 3),
  "Círculo CP3–CP4" = circulo(3, 4)
)

selector_vistas(vistas, "evid", alto = 660)

Círculos: cada flecha es una variable; su color indica la dimensión, y cuanto más larga, gruesa y opaca, mejor representada está en el plano (cos² alto). La circunferencia punteada representa una distancia de 0,5 respecto al centro del plano de correlaciones. Vista 3D: el tamaño de cada punto es proporcional a su aporte a la inercia de los tres primeros componentes; se etiquetan los países que más aportan y Colombia (rombo dorado). Arrastre para girar; el giro automático se detiene al interactuar.

Los círculos de correlaciones nos ayudan a ver qué indicadores se mueven juntos y cuáles lo hacen en sentido contrario. En el plano CP1–CP2 podemos observar que las flechas de acceso a electricidad y a cocina limpia, tanto total como rural, apuntan hacia la derecha y llegan casi al borde del círculo; el PIB per cápita y la urbanización van en la misma dirección, aunque son más cortas. En contraste, la energía renovable y el crecimiento poblacional apuntan hacia la izquierda, lo que nos dice que los países con menos acceso son los que tienen más energía renovable. Esta es la paradoja renovable que veníamos viendo, ahora representada gráficamente.

Notemos que las flechas de intensidad energética, PM2.5 e industria suben casi en vertical, perpendiculares a las de acceso. Esto nos da a entender que la contaminación y la intensidad energética son una dimensión distinta del nivel de acceso: un país puede tener electricidad para toda su población y aun así contaminar mucho. Las emisiones de CO₂ y de gases de efecto invernadero quedan en diagonal porque se relacionan con los dos ejes: están ligadas tanto al ingreso y la urbanización como a la industria y la contaminación.

En el plano CP1–CP3, la superficie forestal y el PM2.5 se separan en direcciones opuestas sobre el eje vertical, es decir, los países con más bosque tienden a tener menos contaminación del aire. Por último, en el plano CP3–CP4 la electricidad renovable se alinea con el CP4 junto con el PIB per cápita.

Clusterización con el método de Ward

# Ward sobre los componentes retenidos
factores <- acp$ind$coord[, 1:k_cp]
distancias <- dist(factores, method = "euclidean")
hc <- hclust(distancias, method = "ward.D2")
# Suma de cuadrados dentro de los grupos (inercia intra) y silueta media para k = 1, ..., 10
inercia_intra <- function(g) {
  sum(sapply(split(as.data.frame(factores), g), function(d) sum(scale(d, scale = FALSE)^2)))
}

criterios <- tibble(k = 1:10) %>%
  mutate(
    wss = map_dbl(k, ~ inercia_intra(cutree(hc, .x))),
    r2 = 100 * (1 - wss / wss[1]),            # % de la inercia total explicada por la particion
    ganancia = r2 - lag(r2),                   # puntos de inercia que agrega cada grupo adicional
    silueta = map_dbl(k, ~ if (.x == 1) NA_real_ else mean(silhouette(cutree(hc, .x), distancias)[, 3])),
    tamanos = map_chr(k, ~ paste(sort(table(cutree(hc, .x)), decreasing = TRUE), collapse = " · "))
  )

k_final <- 3
crit <- function(k, col) criterios[[col]][criterios$k == k]
ganancia_despues <- max(criterios$ganancia[criterios$k > k_final])

Elección del número de clusters

Elegir el número de grupos es una de las decisiones más delicadas del análisis de conglomerados, porque en la literatura no existe un criterio único ni universalmente óptimo. Everitt et al. (2011) señalan que las reglas para detener la agrupación sirven como guías y no como pruebas formales, y Hennig (2015) plantea que cuáles son los «verdaderos» grupos depende del propósito del análisis. Por esta razón, y siguiendo a Hair et al. (2019), la decisión combina criterios estadísticos con la utilidad práctica de la solución.

Evaluamos soluciones de 1 a 10 grupos con dos criterios estadísticos que se complementan: el método del codo, que nos dice cuánta información gana cada grupo adicional, y el coeficiente de silueta, que mide qué tan bien quedó ubicado cada país dentro de su grupo. A esto sumamos un criterio más sencillo: que los grupos se puedan interpretar a la luz del trilema energético.

56,9%
de la inercia total queda explicada al dividir a los países en tres grupos
0,434
silueta media con k = 3, la más alta entre 2 y 10 grupos
15,3 pts
de inercia agrega el tercer grupo; el cuarto solo agrega 7,0 pts
6
países con silueta negativa, todos en la frontera entre dos grupos
Figura 10Criterios para elegir el número de clusters: método del codo y coeficiente de silueta
# --- Metodo del codo: suma de cuadrados intra (arriba) y ganancia de inercia explicada (abajo)
destaca <- function(k, si, no) ifelse(k == k_final, si, no)

codo_sup <- plot_ly(criterios, x = ~k) %>%
  add_trace(y = ~wss, type = "scatter", mode = "lines", fill = "tozeroy", fillcolor = "rgba(54,153,120,.12)",
            line = list(color = pal[["natural"]], width = 3, shape = "spline"), hoverinfo = "skip", showlegend = FALSE) %>%
  add_trace(y = ~wss, type = "scatter", mode = "markers", showlegend = FALSE,
            marker = list(size = destaca(criterios$k, 20, 11), color = destaca(criterios$k, pal[["dorado"]], "#FFFFFF"),
                          line = list(color = destaca(criterios$k, pal[["profundo"]], pal[["natural"]]), width = 2.5)),
            hovertext = ~paste0("<b>k = ", k, "</b><br>Suma de cuadrados intra: ", num(wss, 1),
                                "<br>Inercia explicada: ", num(r2, 1), "%<br>Tamaños: ", tamanos),
            hoverinfo = "text")

ganancias <- filter(criterios, k > 1)
codo_inf <- plot_ly(ganancias, x = ~k, y = ~ganancia, type = "bar", showlegend = FALSE,
                    marker = list(color = destaca(ganancias$k, pal[["dorado"]], pal[["menta"]]),
                                  line = list(color = destaca(ganancias$k, pal[["profundo"]], pal[["natural"]]), width = 1.5)),
                    text = ~paste0("+", num(ganancia, 1)), textposition = "outside", cliponaxis = FALSE,
                    hovertext = ~paste0("Pasar de ", k - 1, " a ", k, " grupos agrega<br>", num(ganancia, 1),
                                        " puntos de inercia explicada"),
                    hoverinfo = "text")

codo <- subplot(codo_sup, codo_inf, nrows = 2, heights = c(.6, .4), shareX = TRUE, titleY = TRUE, margin = .07) %>%
  layout(
    xaxis = list(title = "Número de clusters (k)", dtick = 1, range = c(.5, 10.5)),
    yaxis = list(title = "Suma de cuadrados intra"),
    yaxis2 = list(title = "Ganancia (pts)", range = c(0, max(ganancias$ganancia) * 1.3)),
    shapes = list(list(type = "rect", xref = "x", yref = "paper", x0 = k_final + .5, x1 = 10.5, y0 = 0, y1 = 1,
                       fillcolor = "rgba(242,205,115,.14)", line = list(width = 0), layer = "below")),
    annotations = list(
      list(x = k_final, y = crit(k_final, "wss"), xref = "x", yref = "y", showarrow = TRUE, arrowhead = 2,
           arrowcolor = pal[["profundo"]], ax = 90, ay = -55, bgcolor = "#FFFFFF", bordercolor = pal[["dorado"]],
           borderwidth = 1.5, borderpad = 6, font = list(size = 12.5),
           text = paste0("<b>Codo en k = ", k_final, "</b><br>", num(crit(k_final, "r2")), "% de la inercia explicada")),
      list(x = 7.5, y = 1, xref = "x", yref = "paper", yanchor = "top", showarrow = FALSE,
           font = list(size = 12, color = "#9A7316"),
           text = paste0("Rendimientos decrecientes: desde k = ", k_final + 1, "<br>cada grupo adicional aporta ",
                         num(ganancia_despues), " pts o menos")))
  ) %>%
  estilo_plotly()

# --- Silueta media segun k, con las franjas de interpretacion de Kaufman y Rousseeuw (1990)
sil_k <- filter(criterios, k > 1)
franja <- function(y0, y1, color) list(type = "rect", xref = "paper", x0 = 0, x1 = 1, y0 = y0, y1 = y1,
                                       fillcolor = color, line = list(width = 0), layer = "below")
rotulo <- function(y, texto, color) list(x = 12.55, y = y, xanchor = "right", showarrow = FALSE, align = "right",
                                         text = texto, font = list(size = 11.5, color = color))

g_silk <- plot_ly(sil_k, x = ~k, y = ~silueta, type = "bar", showlegend = FALSE,
                  marker = list(color = destaca(sil_k$k, pal[["dorado"]], pal[["natural"]]),
                                line = list(color = destaca(sil_k$k, pal[["profundo"]], "#FFFFFF"), width = 2)),
                  text = ~num(silueta, 3), textposition = "outside", cliponaxis = FALSE,
                  hovertext = ~paste0("<b>k = ", k, "</b><br>Silueta media: ", num(silueta, 3), "<br>Tamaños: ", tamanos),
                  hoverinfo = "text") %>%
  layout(
    xaxis = list(title = "Número de clusters (k)", tickvals = 2:10, range = c(1.4, 12.6)),
    yaxis = list(title = "Silueta media", range = c(0, .72)),
    shapes = list(franja(0, .25, "rgba(181,83,47,.07)"), franja(.25, .50, "rgba(242,205,115,.18)"),
                  franja(.50, .70, "rgba(54,153,120,.12)")),
    annotations = list(rotulo(.125, "<b>Sin estructura</b><br>sustancial (≤ 0,25)", pal[["terracota"]]),
                       rotulo(.375, "<b>Estructura débil</b><br>a moderada (0,26–0,50)", "#9A7316"),
                       rotulo(.60, "<b>Estructura</b><br>razonable (0,51–0,70)", pal[["bosque"]]),
                       list(x = k_final, y = crit(k_final, "silueta"), yshift = 26, showarrow = FALSE,
                            text = "▼ máximo", font = list(size = 12, color = pal[["profundo"]])))
  ) %>%
  estilo_plotly()

# --- Silueta de cada pais con k = 3 (perfil clasico de Rousseeuw)
df_sil <- tibble(pais = base_final$pais, cluster = base_final$cluster, s = silueta_pais, vecino = vecino_pais) %>%
  arrange(cluster, desc(s)) %>%
  mutate(orden = row_number())
neg <- filter(df_sil, s < 0)
marcas_neg <- lapply(seq_len(nrow(neg)), function(i) list(
  x = neg$orden[i], y = neg$s[i], text = neg$pais[i], showarrow = TRUE, arrowhead = 0, arrowcolor = "#9DB8AE",
  ax = ifelse(i %% 2 == 1, -48, 48), ay = 20 + 18 * ((i - 1) %% 4),
  font = list(size = 10.5, color = pal[["terracota"]])))

g_silp <- plot_ly(df_sil, x = ~orden, y = ~s, color = ~cluster, colors = col_cluster, type = "bar",
                  hovertext = ~paste0("<b>", pais, "</b><br>", cluster, "<br>Silueta: ", num(s, 3),
                                      "<br>Cluster vecino más cercano: ", vecino),
                  hoverinfo = "text") %>%
  layout(
    bargap = .08,
    xaxis = list(title = "Países ordenados por cluster y por silueta", showticklabels = FALSE, zeroline = FALSE),
    yaxis = list(title = "Ancho de silueta", zerolinecolor = pal[["profundo"]], range = c(-.62, .78)),
    shapes = list(list(type = "line", xref = "paper", x0 = 0, x1 = 1,
                       y0 = crit(k_final, "silueta"), y1 = crit(k_final, "silueta"),
                       line = list(color = pal[["terracota"]], dash = "dash", width = 1.5))),
    annotations = c(list(list(x = 1, xref = "paper", xanchor = "right", y = crit(k_final, "silueta"), yanchor = "bottom",
                              showarrow = FALSE, text = paste0("Silueta media = ", num(crit(k_final, "silueta"), 3)),
                              font = list(color = pal[["terracota"]], size = 12))), marcas_neg),
    legend = list(orientation = "h", y = -0.12)
  ) %>%
  estilo_plotly()

selector_vistas(list(
  "Método del codo" = codo,
  "Silueta media según k" = g_silk,
  "Silueta de cada país (k = 3)" = g_silp
), "k", alto = 580)

Método del codo: la curva superior muestra la suma de cuadrados dentro de los grupos y las barras inferiores la ganancia de inercia explicada al agregar cada grupo; la zona sombreada marca los rendimientos decrecientes. Silueta: las franjas siguen la escala de interpretación de Kaufman y Rousseeuw (1990). Pase el cursor para ver el tamaño de los grupos en cada solución.

  • Método del codo: busca el punto a partir del cual agregar un grupo deja de reducir de forma importante la suma de cuadrados dentro de los grupos, que es justamente lo que el método de Ward minimiza en cada fusión. Como podemos observar en la figura, la curva cae con fuerza al pasar de uno a dos grupos +41,6 puntos de inercia explicada y de dos a tres +15,3 puntos y a partir de ahí se aplana, el cuarto grupo agrega solo 7,0 puntos, menos de la mitad que el tercero. Por eso el codo está en k = 3 donde la clasificación ya explica el 56,9% de la inercia total de los cuatro componentes.

  • Coeficiente de silueta: para cada país compara qué tan lejos está de los países de su propio grupo con qué tan lejos está del grupo vecino más cercano. Va de −1 a 1 y su promedio resume qué tan bien quedó toda la clasificación. La silueta media es máxima en k = 3 (0,434), un poco por encima de k = 2 (0,411) y baja con fuerza con cuatro grupos 0,342. Según la escala de Kaufman y Rousseeuw (1990), un valor entre 0,26 y 0,50 indica una estructura débil: los grupos existen, pero con fronteras difusas. Esto es esperable en un fenómeno gradual como la transición energética, en el que los países se distribuyen a lo largo de un continuo y no en bloques separados. Notemos que solo 6 de los 164 países 3,7% tienen silueta negativa, es decir, están algo más cerca del grupo vecino que del suyo: Bangladés, Belice, Botsuana, Fiyi, Pakistán y Samoa. Todos son casos de frontera entre la pobreza energética y el acceso universal.

  • La decisión: ambos criterios coinciden en k = 3. Además, Hair et al. (2019) recomiendan preferir la solución más simple cuando las alternativas solo agregan mejoras pequeñas, y aquí un cuarto grupo baja la calidad de la clasificación sin ganar mucha inercia. Y, como proponen Husson et al. (2017), los tres grupos se pueden leer directamente porque son tres posiciones distintas frente al trilema energético: déficit de acceso, acceso resuelto con distinta participación de energías renovables, y alta emisión con alto ingreso.

Figura 11Dendrograma del método de Ward cortado en tres clusters
Pobreza energética con biomasa (55) Acceso universal con matriz mixta (100) Países de alto ingreso y alta emisión (9)
orden_dend <- as.character(unique(grupos[hc$order]))          # clusters en el orden del dendrograma
colores_dend <- unname(col_cluster[nombres_cl[orden_dend]])

corte <- mean(rev(hc$height)[c(k_final - 1, k_final)])          # punto medio entre la fusion 3->2 y la 4->3

dend <- as.dendrogram(hc) %>%
  dendextend::color_branches(k = k_final, col = colores_dend) %>%
  dendextend::color_labels(k = k_final, col = colores_dend) %>%
  dendextend::set("labels_cex", .85) %>%
  dendextend::set("branches_lwd", 1.8)

par(mar = c(4, 1, 1, 10), family = "sans", col.axis = pal[["profundo"]], col.lab = pal[["bosque"]])
plot(dend, horiz = TRUE, xlab = "Distancia de agregación (criterio de Ward)", axes = TRUE)
abline(v = corte, lty = 2, lwd = 1.6, col = pal[["terracota"]])
text(corte, 1, "corte en k = 3", pos = 4, cex = .9, col = pal[["terracota"]])

Desplace el panel para recorrer los 164 países. Cada color corresponde a un cluster y la línea discontinua marca el corte en tres grupos.

El dendrograma nos muestra cómo se fueron uniendo los países paso a paso. Como podemos observar, la primera gran división separa a los 55 países con déficit de acceso del resto. Los 9 países de alto ingreso y alta emisión forman una rama propia que solo se une con los de acceso universal casi al final, lo que nos da a entender que se diferencian claramente de los demás.

Ubicación de los clusters

Figura 12Los tres clusters en el espacio factorial y en el mapa
# Plano factorial con elipses de concentracion (90%) y centroides de cada cluster
datos_plano <- coord_ind
centroides <- datos_plano %>% group_by(cluster) %>% summarise(CP1 = mean(CP1), CP2 = mean(CP2), .groups = "drop")

g_plano_cl <- ggplot(datos_plano, aes(CP1, CP2, colour = cluster, fill = cluster)) +
  stat_ellipse(geom = "polygon", alpha = .08, level = .9, linewidth = .4) +
  geom_point(aes(text = paste0("<b>", pais, "</b><br>", cluster, "<br>", region)), size = 2.6, alpha = .9) +
  geom_point(data = centroides, aes(text = paste0("Centroide<br>", cluster)),
             shape = 23, size = 5.5, colour = "white", stroke = 1.2) +
  scale_colour_manual(values = col_cluster) +
  scale_fill_manual(values = col_cluster) +
  labs(x = paste0("CP1 · Modernización (", num(eig$varianza[1]), "%)"),
       y = paste0("CP2 · Intensidad fósil (", num(eig$varianza[2]), "%)"), colour = NULL, fill = NULL)

mundo_cl <- mundo %>% select(adm0_a3, geometry) %>%
  left_join(base_final %>% select(iso3c, pais, cluster, subperfil, Energia_renovable, Emisiones_CO2, Acceso_electricidad),
            by = c("adm0_a3" = "iso3c"))
pequenos_cl <- pequenos %>% select(adm0_a3, geometry) %>%
  left_join(base_final %>% select(iso3c, pais, cluster), by = c("adm0_a3" = "iso3c"))
pal_cl <- colorFactor(unname(col_cluster), levels = orden_cl, na.color = "#E6E6E6")

mapa_cl <- leaflet(mundo_cl, options = leafletOptions(minZoom = 1, maxZoom = 6, zoomSnap = .25,
                                                      attributionControl = FALSE), height = 460) %>%
  setView(lng = 12, lat = 20, zoom = 1.6) %>%
  addPolygons(
    fillColor = ~pal_cl(cluster), fillOpacity = .88, weight = .6, color = "white",
    label = ~ifelse(is.na(cluster), "Sin datos", paste0(pais, " · ", cluster)),
    popup = ~ifelse(is.na(cluster), "Sin datos",
                    paste0("<b>", pais, "</b><br><i>", cluster, "</i><br>Subperfil: ", subperfil,
                           "<br>Renovable: ", num(Energia_renovable), "%<br>Acceso electricidad: ",
                           num(Acceso_electricidad), "%<br>CO2: ", num(Emisiones_CO2, 2), " t pc")),
    highlightOptions = highlightOptions(weight = 2, color = pal[["profundo"]], bringToFront = TRUE)
  ) %>%
  addCircleMarkers(data = pequenos_cl, radius = 4, color = "white", weight = 1, fillOpacity = .95,
                   fillColor = ~pal_cl(cluster), label = ~paste0(pais, " · ", cluster)) %>%
  addLegend("bottomleft", pal = pal_cl, values = orden_cl, title = "Cluster", opacity = .9)

selector_vistas(list(
  "Espacio 3D" = grafico_3d("cluster", col_cluster, centroides = TRUE),
  "Plano CP1–CP2" = interactivo(g_plano_cl, tooltip = "text") %>% layout(legend = list(orientation = "h", y = -0.2)),
  "Mapa mundial" = mapa_cl
), "segm", alto = 620)

Espacio 3D: los rombos grandes son los centroides de cada cluster y se etiquetan los países que más aportan a la inercia. El giro automático se detiene al arrastrar el gráfico.

En el espacio factorial los tres grupos se ordenan, ante todo, a lo largo del CP1. El centroide de Pobreza energética con biomasa queda en el extremo negativo de la modernización (CP1 = −3,02), el de Acceso universal con matriz mixta en la zona positiva (CP1 = 1,30) y el de Alto ingreso y alta emisión todavía más a la derecha (CP1 = 3,98). Lo que separa a este último grupo del resto es el CP2: su centroide vale 4,58 en ese eje, muy por encima de los otros dos (0,33 y −0,59), por lo que en la vista 3D se ve como una nube aislada en la parte alta del eje de emisiones y contaminación. Los otros dos grupos se tocan en la zona central del CP1, lo que explica que sus fronteras sean difusas.

El mapa nos muestra que los grupos tienen una geografía reconocible, pero que no coinciden con los continentes. De los 41 países de África subsahariana 37 pertenecen al grupo de pobreza energética y los otros 4 que son Cabo Verde, Mauricio, Seychelles y Sudáfrica quedan con el acceso universal. En América Latina y el Caribe 22 de los 27 países tienen acceso universal, mientras que Belice, Guatemala, Honduras y Nicaragua comparten el perfil de pobreza energética y Trinidad y Tobago se ubica en el grupo de alto ingreso y alta emisión. Asia Oriental y Pacífico es la región más repartida con 10, 14 y 2 países en cada grupo; los dos del grupo de alto ingreso y alta emisión son Brunéi y Palaos. Por último, en Medio Oriente, Norte de África, Afganistán y Pakistán conviven los 6 países del Golfo de alto ingreso y alta emisión con 10 países de acceso universal y 2 en pobreza energética (Afganistán y Yibuti).

Caracterización y justificación de los nombres

El nombre de cada grupo no es una etiqueta arbitraria, ya que sale de los valores test que nos dicen en qué variables el grupo se aparta significativamente del promedio mundial. Un valor test positivo significa que el grupo tiene en promedio valores más altos que el conjunto de países y uno negativo, valores más bajos. La franja gris de la figura marca la zona donde la diferencia no es significativa (|v| < 1,96). Para nombrar cada grupo tomamos la combinación de rasgos con los valores test más altos en valor absoluto y la comprobamos con los países más cercanos a su centro.

Figura 13Valores test: en qué se distingue cada cluster del promedio mundial
vt_graf <- vt %>%
  mutate(nombre = factor(cortas[variable], levels = rev(cortas)), cluster = factor(cluster, levels = orden_cl),
         fila = as.numeric(nombre))

g_vt <- ggplot(vt_graf, aes(v, fila)) +
  annotate("rect", xmin = -1.96, xmax = 1.96, ymin = .4, ymax = 15.6, fill = "#E9EFEB", alpha = .9) +
  annotate("text", x = 0, y = 16.1, label = "No significativo (|v| < 1,96)", size = 3.2, colour = "#5C7469") +
  geom_vline(xintercept = 0, colour = "#B9CEC3") +
  geom_line(aes(group = nombre), colour = "#D3E0D8", linewidth = 1.3) +
  geom_point(aes(colour = cluster,
                 text = paste0("<b>", cluster, "</b><br>", nombre, "<br>Valor test: ", num(v, 2),
                               "<br>Media del cluster: ", num(media, 2), "<br>Media mundial: ", num(global, 2))),
             size = 4, alpha = .95) +
  scale_colour_manual(values = col_cluster) +
  scale_x_continuous(breaks = seq(-12, 12, 3)) +
  scale_y_continuous(breaks = seq_along(levels(vt_graf$nombre)), labels = levels(vt_graf$nombre),
                     expand = expansion(add = .4)) +
  labs(x = "Valor test (v)", y = NULL, colour = NULL)

interactivo(g_vt, tooltip = "text") %>% layout(legend = list(orientation = "h", y = -0.12))

Cada fila es una variable y cada punto un cluster. Los puntos fuera de la franja gris son diferencias significativas al 5 % respecto al promedio de los 164 países.

Las tarjetas siguientes detallan cada grupo, el por qué se llama así, su perfil completo, los países más representativos y su composición por regiones. En las barras se compara el promedio del grupo (barra de color) con el promedio mundial (marca oscura).

Cluster 1

Pobreza energética con biomasa

55 países 33,5% de la muestra Silueta media 0,36
Justificación del nombre

Las variables que más lo distinguen del promedio mundial son la cocina limpia (v = −11,2), la cocina limpia rural (v = −11,2), el acceso rural a electricidad (v = −10,2) y el acceso total (v = −9,6). Es el único grupo con un déficit masivo de servicios energéticos modernos, lo que define la pobreza energética. Su rasgo positivo más fuerte es la energía renovable (v = +9,4; 58,1% frente a 30,4% en el mundo), pero con solo 26,7% de la población cocinando con combustibles limpios, esa energía renovable proviene sobre todo de leña y carbón vegetal, es decir, de biomasa tradicional. El nombre une ambos rasgos porque son dos caras del mismo fenómeno.

Perfil del grupo

En promedio, solo 61,9% de la población tiene electricidad (44,7% en zonas rurales) y apenas 13,7% de los hogares rurales cocina con combustibles limpios. Tiene el menor PIB per cápita (US$ 5.649, menos de una cuarta parte del promedio), la menor urbanización (41,6%) y el mayor crecimiento poblacional (2,06% anual; v = +7,0), lo que significa que la demanda de energía crecerá rápido. Sus emisiones son mínimas (0,73 t de CO2 per cápita), pero su intensidad energética es alta (5,77 MJ/US$; v = +3,3) por la baja eficiencia de la biomasa, y su contaminación por PM2.5 (26,6 µg/m³) supera el promedio. Conserva más bosque que el promedio (40,2%), un capital natural presionado por el uso de leña.

Promedio del cluster frente a los 164 países analizados
Acceso a electricidad 61,9%
Cocina limpia 26,7%
Energía renovable 58,1%
Electricidad renovable 49,1%
CO2 per cápita 0,73 t
PM2.5 26,6 µg/m³
PIB per cápita 5.649 US$
Países más representativos
Myanmar (Birmania) Laos Togo Kenia Camboya
Composición regional

África subsahariana (37) · Asia Oriental y Pacífico (10) · América Latina y el Caribe (4) · Asia del Sur (2) · Medio Oriente, Norte de África, Afganistán y Pakistán (2)

Prioridad de política: acceso básico con soluciones descentralizadas (minirredes y sistemas solares) y programas masivos de cocinas limpias, evitando que la modernización sustituya la biomasa por combustibles fósiles.
Cluster 2

Acceso universal con matriz mixta

100 países 61,0% de la muestra Silueta media 0,49
Justificación del nombre

Sus valores test positivos más altos corresponden a la cocina limpia (v = +9,8), la cocina limpia rural (v = +9,5), la electricidad rural (v = +9,0) y el acceso total (v = +8,5): prácticamente todos sus países tienen acceso universal (99,5% en promedio). Su rasgo negativo más fuerte es la energía renovable (v = −7,5; 17,9% frente a 30,4%), pero la electricidad renovable apenas se separa del promedio (v = −2,0) y va de 0,0 a 99,4% según el país, y las emisiones de CO2 no difieren significativamente del promedio mundial (v = +0,2). Lo que estos países tienen en común es el acceso, no la fuente de energía: en el grupo conviven matrices dominadas por el carbón y el gas con otras casi totalmente renovables. Por eso se describe como acceso universal con matriz mixta.

Perfil del grupo

Es el grupo más numeroso y el más cohesionado (silueta media de 0,49). Tiene ingreso medio-alto (US$ 32.915 en promedio, con una mediana de US$ 24.915), alta urbanización (67,0%), crecimiento poblacional bajo (0,34%) y la menor intensidad energética de los tres grupos (3,85 MJ/US$; v = −5,4). Su contaminación por PM2.5 (18,7 µg/m³) es inferior al promedio, aunque sigue por encima de la guía de la OMS. Sus emisiones promedio (5,14 t per cápita) esconden una gran dispersión: van de 0,0 a 15,0 t, con Australia, Canadá y Estados Unidos en el extremo alto. Reúne a las principales economías del mundo, como China, Estados Unidos, India, Japón y los países de la Unión Europea, por lo que de su evolución depende buena parte de las emisiones globales.

Promedio del cluster frente a los 164 países analizados
Acceso a electricidad 99,5%
Cocina limpia 93,2%
Energía renovable 17,9%
Electricidad renovable 32,6%
CO2 per cápita 5,14 t
PM2.5 18,7 µg/m³
PIB per cápita 32.915 US$
Países más representativos
México Macedonia del Norte Rumanía Hungría Bulgaria
Composición regional

Europa y Asia Central (44) · América Latina y el Caribe (22) · Asia Oriental y Pacífico (14) · Medio Oriente, Norte de África, Afganistán y Pakistán (11) · África subsahariana (4) · Asia del Sur (3) · Norteamérica (2)

Prioridad de política: descarbonizar la generación eléctrica en los emergentes de matriz fósil y, en los de ingreso alto, electrificar el transporte, la industria y la calefacción, además de financiar la transición de los demás grupos.
Cluster 3

Países de alto ingreso y alta emisión

9 países 5,5% de la muestra Silueta media 0,27
Justificación del nombre

Es el grupo con los valores test más extremos de toda la clasificación: emisiones de GEI (v = +10,0) y de CO2 (v = +9,6), con 30,3 t de CO2 per cápita, 6 veces el promedio de los países analizados. Le siguen la industria (v = +5,4; 46,6% del PIB), la contaminación por PM2.5 (v = +4,8) y la intensidad energética (v = +4,7). En el lado negativo, su participación renovable es prácticamente nula (0,3%; v = −3,5). Por sus elevados niveles de ingreso y emisiones, este grupo se describe como países de alto ingreso y alta emisión.

Perfil del grupo

Tiene el mayor PIB per cápita (US$ 57.497), la mayor urbanización (84,1%) y acceso universal, pero el peor desempeño ambiental: la intensidad energética más alta (9,00 MJ/US$), PM2.5 de 47,8 µg/m³, en parte por el polvo del desierto, y solo 3,1% de bosques en mediana. Su crecimiento poblacional promedio es negativo (−1,09%), un valor arrastrado por Catar (−10,9%), una caída probablemente asociada a la salida de trabajadores extranjeros durante la pandemia. La excepción del grupo es Palaos, que no produce hidrocarburos pero registra las mayores emisiones per cápita de la muestra (74,7 t) por su población muy pequeña y su total dependencia de combustibles importados.

Promedio del cluster frente a los 164 países analizados
Acceso a electricidad 100,0%
Cocina limpia 99,4%
Energía renovable 0,3%
Electricidad renovable 1,3%
CO2 per cápita 30,26 t
PM2.5 47,8 µg/m³
PIB per cápita 57.497 US$
Países más representativos
Baréin Kuwait Omán Emiratos Árabes Unidos Arabia Saudí
Composición regional

Medio Oriente, Norte de África, Afganistán y Pakistán (6) · Asia Oriental y Pacífico (2) · América Latina y el Caribe (1)

Prioridad de política: diversificar la economía, eliminar gradualmente los subsidios a los combustibles fósiles y aprovechar su alto potencial solar.

Cohesión y heterogeneidad interna

Pertenecer al mismo cluster no significa tener indicadores idénticos. La tabla siguiente muestra para cada grupo la silueta media (cohesión), la proporción de países con silueta negativa, las medianas de cuatro indicadores clave y el rango de las emisiones per cápita.

Tabla 4Cohesión y heterogeneidad interna de los clusters
heterogeneidad <- base_final %>%
  mutate(silueta = silueta_pais) %>%
  group_by(Cluster = as.character(cluster)) %>%
  summarise(
    Países = n(),
    `Silueta media` = mean(silueta),
    `% con silueta negativa` = 100 * mean(silueta < 0),
    `Renovable (mediana %)` = median(Energia_renovable),
    `Acceso elec. (mediana %)` = median(Acceso_electricidad),
    `CO2 pc (mediana t)` = median(Emisiones_CO2),
    `Rango CO2 pc (t)` = paste0(num(min(Emisiones_CO2), 1), " – ", num(max(Emisiones_CO2), 1)),
    .groups = "drop"
  ) %>%
  arrange(factor(Cluster, levels = orden_cl))

reactable(
  heterogeneidad, pagination = FALSE, compact = TRUE,
  columns = list(
    Cluster = colDef(minWidth = 210, cell = function(value) {
      span(class = "chip-cluster", style = paste0("background:", col_cluster[[value]]), value)
    }),
    `Silueta media` = colDef(cell = function(value) {
      div(class = "barra-cv",
          div(class = "barra-relleno", style = list(width = paste0(100 * value / max(heterogeneidad$`Silueta media`), "%"),
                                                     background = "#E0A230")),
          span(num(value, 3)))
    }),
    `% con silueta negativa` = colDef(cell = function(v) num(v, 1)),
    `Renovable (mediana %)` = colDef(cell = function(v) num(v, 1)),
    `Acceso elec. (mediana %)` = colDef(cell = function(v) num(v, 1)),
    `CO2 pc (mediana t)` = colDef(cell = function(v) num(v, 2))
  ),
  theme = reactableTheme(headerStyle = list(background = pal[["bosque"]], color = "white"))
)

Como podemos observar en la Tabla 4, el grupo de Acceso universal con matriz mixta es el que presenta la silueta media más alta, con un valor de 0,491, y está conformado por 100 países. Esto significa que es el grupo que presenta una mejor separación respecto a los demás. Además, solo 2 países tienen una silueta negativa, lo que nos indica que la mayoría se encuentra mejor agrupada dentro de este cluster. Sin embargo, esto no quiere decir que todos tengan las mismas características, ya que sus emisiones de CO₂ por habitante varían entre 0,0 y 15,0 toneladas.

Por otro lado, tenemos el grupo de Pobreza energética con biomasa, conformado por 55 países, con una silueta media de 0,357. En este caso, 4 países presentan valores negativos, lo que muestra que algunos tienen características más cercanas a otro grupo. También podemos observar que su mediana de energía renovable es del 62,1 %, mientras que la mediana de acceso a electricidad es del 65,4 %. Esta diferencia es importante porque nos muestra que tener una participación elevada de energía renovable no significa necesariamente que exista un alto acceso a servicios energéticos.

Finalmente, el grupo de Países de alto ingreso y alta emisión está formado por 9 países y presenta la silueta media más baja, con un valor de 0,267. Aunque ninguno de sus países tiene una silueta negativa, existen diferencias importantes dentro del grupo. Por ejemplo, las emisiones de CO₂ per cápita van de 19,2 a 74,7 toneladas. Esto nos permite entender que los países pueden pertenecer a un mismo cluster y aun así presentar valores muy diferentes en algunos indicadores.

En general, los resultados de la tabla nos muestran que los tres clusters permiten identificar grupos de países con ciertas características similares, pero esto no significa que todos los integrantes de un mismo grupo sean iguales. Por esta razón, la clasificación es útil para reconocer patrones generales, teniendo en cuenta que también existen diferencias entre los países que conforman cada grupo.

Conclusiones

Después de realizar el análisis de los 164 países con los 15 indicadores del Banco Mundial correspondientes al año 2021 podemos concluir que sí fue posible identificar diferentes patrones de desarrollo energético, ambiental y económico. Los resultados nos muestran que los países no presentan las mismas condiciones y que tener un mayor ingreso o una participación elevada de energía renovable no significa necesariamente contar con mejores condiciones de acceso energético o menores niveles de contaminación.

En primer lugar, mediante el Análisis de Componentes Principales (ACP) logramos resumir las 15 variables en cuatro componentes que explican conjuntamente el 74,7 % de la variabilidad total. El componente más importante fue el CP1, modernización y acceso energético con un 42,0 %, seguido del CP2, emisiones e intensidad energética con un 15,9 %. Por otro lado, el CP3 permitió identificar diferencias relacionadas con la cobertura forestal y la contaminación del aire mientras que el CP4 estuvo relacionado principalmente con la electricidad renovable y el ingreso. De acuerdo con estos resultados, podemos observar que las mayores diferencias entre los países están relacionadas principalmente con el acceso a servicios energéticos modernos, aunque los indicadores ambientales también tienen una participación importante.

Posteriormente, al aplicar el método de Ward utilizando los cuatro componentes principales, obtuvimos tres clusters. El primero, denominado Pobreza energética con biomasa que reúne a 55 países que presentan menores niveles de ingreso y acceso a electricidad y cocina limpia, pero una participación elevada de energía renovable. El segundo el Acceso universal con matriz mixta que está conformado por 100 países y se caracteriza por mejores condiciones de acceso energético, aunque existen diferencias importantes en sus emisiones y en la participación de electricidad renovable. Finalmente, el tercer grupo Países de alto ingreso y alta emisión que contiene 9 países que se destacan por sus elevados niveles de ingreso y emisiones de CO₂. Esto nos permitió identificar tres perfiles generales con características distintas, sin que todos los países de un mismo grupo sean necesariamente iguales.

Uno de los resultados que más llama la atención es que una participación alta de energía renovable no siempre representa mejores condiciones energéticas. Como pudimos observar, algunos de los países con mayor consumo de energía renovable también presentan dificultades para acceder a electricidad y tecnologías limpias para cocinar. Esto puede estar relacionado con el uso de biomasa tradicional, como la leña. En contraste, encontramos países con mayores ingresos y acceso a electricidad que presentan emisiones elevadas. Por lo tanto, consideramos que no es suficiente analizar únicamente el ingreso o las energías renovables, sino que es necesario tener en cuenta varios indicadores para comprender mejor la situación de cada país.

También identificamos diferencias entre regiones, una parte importante de los países con mayores dificultades de acceso energético se encuentra en África subsahariana, mientras que en otras regiones encontramos países con mejores condiciones de acceso pero con resultados ambientales diferentes. En el caso de América Latina podemos observar que varios países presentan una participación importante de electricidad renovable, aunque todavía existen desafíos relacionados con otros servicios energéticos. Colombia es un ejemplo, ya que cuenta con una elevada participación de electricidad renovable, pero mantiene diferencias entre las zonas urbanas y rurales en el acceso a tecnologías limpias para cocinar. Esto demuestra que las condiciones energéticas de un país no pueden evaluarse únicamente mediante un promedio nacional.

En cuanto a las posibles aplicaciones, consideramos que este tipo de análisis puede ser útil en economía y políticas públicas, porque permite identificar países con necesidades similares y establecer prioridades según las características de cada grupo. Por ejemplo, en los países con menor acceso energético sería importante fortalecer la electrificación y el acceso a tecnologías limpias para cocinar. Por otro lado, en los países con mejores condiciones de acceso, las prioridades podrían estar relacionadas con aumentar la participación de electricidad renovable, mejorar la eficiencia energética y reducir las emisiones. Para los países con ingresos y emisiones elevados, los resultados pueden servir como punto de partida para estudiar alternativas que permitan reducir su impacto ambiental.

Finalmente, debemos tener en cuenta que el análisis presenta algunas limitaciones. Trabajamos únicamente con información del año 2021 y con los 164 países que tenían datos completos, por lo que no podemos afirmar que estos resultados representen a todos los países del mundo ni cómo ha evolucionado cada uno a través del tiempo. Además, los clusters dependen de las variables seleccionadas y del método utilizado. A pesar de estas limitaciones, consideramos que el ACP y el método de Ward fueron herramientas útiles para resumir la información, identificar semejanzas entre países y comprender mejor las diferencias que existen en sus condiciones de desarrollo energético y ambiental.

Bibliografía

Bartlett, M. S. (1950). Tests of significance in factor analysis. British Journal of Psychology, Statistical Section, 3(2), 77–85. https://doi.org/10.1111/j.2044-8317.1950.tb00285.x

Everitt, B. S., Landau, S., Leese, M., & Stahl, D. (2011). Cluster analysis (5.ª ed.). Wiley. https://doi.org/10.1002/9780470977811

Hair, J. F., Black, W. C., Babin, B. J., & Anderson, R. E. (2019). Multivariate data analysis (8.ª ed.). Cengage Learning.

Hennig, C. (2015). What are the true clusters? Pattern Recognition Letters, 64, 53–62. https://doi.org/10.1016/j.patrec.2015.04.009

Hosier, R. H., & Dowd, J. (1987). Household fuel choice in Zimbabwe: An empirical test of the energy ladder hypothesis. Resources and Energy, 9(4), 347–361. https://doi.org/10.1016/0165-0572(87)90003-X

Husson, F., Lê, S., & Pagès, J. (2017). Exploratory multivariate analysis by example using R (2.ª ed.). CRC Press. https://doi.org/10.1201/b21874

Jolliffe, I. T., & Cadima, J. (2016). Principal component analysis: A review and recent developments. Philosophical Transactions of the Royal Society A, 374(2065), 20150202. https://doi.org/10.1098/rsta.2015.0202

Kaiser, H. F. (1960). The application of electronic computers to factor analysis. Educational and Psychological Measurement, 20(1), 141–151. https://doi.org/10.1177/001316446002000116

Kaufman, L., & Rousseeuw, P. J. (1990). Finding groups in data: An introduction to cluster analysis. Wiley. https://doi.org/10.1002/9780470316801

Lê, S., Josse, J., & Husson, F. (2008). FactoMineR: An R package for multivariate analysis. Journal of Statistical Software, 25(1), 1–18. https://doi.org/10.18637/jss.v025.i01

Leach, G. (1992). The energy transition. Energy Policy, 20(2), 116–123. https://doi.org/10.1016/0301-4215(92)90105-B

Murtagh, F., & Legendre, P. (2014). Ward’s hierarchical agglomerative clustering method: Which algorithms implement Ward’s criterion? Journal of Classification, 31(3), 274–295. https://doi.org/10.1007/s00357-014-9161-z

Naciones Unidas. (2015). Transformar nuestro mundo: la Agenda 2030 para el Desarrollo Sostenible (A/RES/70/1). Asamblea General de las Naciones Unidas.

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. https://doi.org/10.1016/0377-0427(87)90125-7

Stern, D. I. (2004). The rise and fall of the environmental Kuznets curve. World Development, 32(8), 1419–1439. https://doi.org/10.1016/j.worlddev.2004.03.004

Thorndike, R. L. (1953). Who belongs in the family? Psychometrika, 18(4), 267–276. https://doi.org/10.1007/BF02289263

Ward, J. H. (1963). Hierarchical grouping to optimize an objective function. Journal of the American Statistical Association, 58(301), 236–244. https://doi.org/10.1080/01621459.1963.10500845

World Bank. (2024). World Development Indicators [Base de datos]. https://databank.worldbank.org/source/world-development-indicators

World Energy Council. (2021). World energy trilemma index 2021. World Energy Council.

World Health Organization. (2021). WHO global air quality guidelines: Particulate matter (PM2.5 and PM10), ozone, nitrogen dioxide, sulfur dioxide and carbon monoxide. World Health Organization.