1 Introducción

La energía es un recurso fundamental para el desarrollo y funcionamiento de los países, ya que está presente en las actividades económicas, industriales y sociales que se realizan diariamente. Sin embargo, la cantidad de energía que genera cada país no es la misma y puede estar relacionada con diferentes características de su población y de su economía. Factores como el número de habitantes, el Producto Interno Bruto (PIB), el porcentaje de población que vive en zonas urbanas y el acceso a la electricidad pueden tener relación con la cantidad de energía generada.

A partir de esto, surge la siguiente pregunta de investigación: ¿qué relación existe entre la generación total de energía y factores como la población, el PIB, la población urbana y el acceso a la electricidad en los diferentes países durante el año 2022?

Para responder esta pregunta, se analizarán los datos correspondientes a diferentes países durante el año 2022, tomando como variable principal la generación total de energía y relacionándola con variables demográficas, económicas y sociales. De esta manera, se busca conocer si las diferencias en estas características están relacionadas con las diferencias en la cantidad de energía generada por cada país.

El objetivo de este estudio es analizar la relación entre la generación total de energía de los países en 2022 y variables como la población total, el PIB, el porcentaje de población urbana y el acceso a la electricidad, con el fin de identificar cuáles de estos factores presentan una mayor relación con la generación de energía.

Así, el estudio permitirá tener una visión más clara de cómo las características de los países pueden estar relacionadas con su capacidad de generación de energía y de qué manera los aspectos económicos, demográficos y sociales se relacionan entre sí.

2 Fuente y construcción de la base.

Para el desarrollo del estudio se construyó una base de datos a partir de información pública proveniente de Our World in Data (OWID) y el Banco Mundial, seleccionando los registros correspondientes al año 2022. La unidad de análisis es el país, por lo que cada fila de la base representa un país con información disponible para las variables consideradas en el estudio.

La generación total de electricidad, medida en teravatios-hora (TWh), se obtuvo de Electricity Mix de Our World in Data. La población total se obtuvo del Population & Demography Data Explorer de la misma plataforma, mientras que la clasificación por continente se tomó de World regions according to Our World in Data. Esta última fuente corresponde a las regiones definidas por OWID y utilizadas en sus gráficos y mapas.

Por otra parte, el PIB total, expresado en dólares estadounidenses a precios actuales, y el consumo de energía eléctrica per cápita, expresado en kWh por habitante, fueron obtenidos del Banco Mundial. Finalmente, el acceso a electricidad, medido como el porcentaje de la población con acceso al servicio eléctrico, se obtuvo de la sección Access to Energy de Our World in Data.

Debido a que las variables se encontraban distribuidas en diferentes conjuntos de datos, fue necesario realizar un proceso de integración. Para ello, las bases fueron organizadas utilizando el código de país como identificador común, lo que permitió relacionar correctamente la información de generación, población, PIB, consumo de electricidad per cápita, acceso a electricidad y continente para cada país.

Posteriormente, se realizó la depuración de los datos. Se revisaron posibles registros duplicados, valores faltantes y la correcta codificación de las variables. En el caso del consumo de electricidad per cápita se identificaron 49 observaciones sin información disponible, las cuales fueron reconocidas como valores faltantes. Para garantizar que todas las observaciones utilizadas en el análisis contaran con información completa en las variables seleccionadas, se trabajó únicamente con casos completos.

Después del proceso de integración, revisión y depuración, la base final quedó conformada por 140 países, con información completa para las variables incluidas en el estudio. Esta base fue utilizada posteriormente para realizar el análisis descriptivo y estimar el modelo de regresión lineal múltiple.

3 Metodología

El estudio se desarrolló mediante un enfoque cuantitativo de corte transversal, utilizando información correspondiente a 140 países durante el año 2022. Para analizar la relación entre la generación total de electricidad y diferentes características socioeconómicas y energéticas, se empleó un modelo de regresión lineal múltiple estimado mediante Mínimos Cuadrados Ordinarios (MCO). La variable dependiente fue la generación total de electricidad, expresada en teravatios-hora (TWh), mientras que como variables explicativas se incluyeron la población total, el PIB total, el consumo de electricidad per cápita, el acceso a electricidad y el continente. Estas variables fueron seleccionadas por su relación conceptual con el fenómeno estudiado: la población representa la dimensión demográfica de cada país, el PIB refleja el tamaño de su economía, el consumo per cápita representa la intensidad del uso de electricidad, el acceso a electricidad refleja la cobertura del servicio y el continente permite considerar diferencias geográficas entre los países.

El modelo planteado se expresa como:

\[Gen Elect = \beta_0 + \beta_1(Pob) + \beta_2(PIB) + \beta_3(Cons EelectPerCapital) + \beta_4(Continente) + \beta_5(Acceso Elect) + \epsilon \]

En esta expresión, \(\beta_0\) corresponde al intercepto; \(\beta_1,\beta_2,\beta_3\) y \(\beta_4\) representan los coeficientes asociados a las variables cuantitativas; \(D_{ji}\) corresponde a las variables indicadoras utilizadas para representar el continente; \(\gamma_j\) representa sus respectivos coeficientes; y \(\varepsilon_i\) corresponde al término de error, que recoge aquellos factores relacionados con la generación eléctrica que no fueron incluidos en el modelo. Debido a que el continente es una variable categórica nominal con seis categorías, se incorporó mediante cinco variables indicadoras, utilizando África como categoría de referencia. Por esta razón, los coeficientes de Asia, Europa, América del Norte, Oceanía y América del Sur representan diferencias con respecto a África, manteniendo constantes las demás variables.

Los coeficientes fueron estimados mediante MCO, método que busca minimizar la suma de los cuadrados de las diferencias entre los valores observados y los estimados por el modelo. Cada coeficiente cuantitativo representa el cambio esperado en la generación total de electricidad asociado con un aumento de una unidad en la variable correspondiente, manteniendo constantes las demás variables. Para evaluar los resultados se analizaron los coeficientes estimados, errores estándar, estadísticos t y valores p, además del R² ajustado y la prueba F para evaluar el comportamiento global del modelo. Finalmente, se realizaron diagnósticos de linealidad, normalidad de los residuos, homocedasticidad y multicolinealidad mediante VIF/GVIF, con el propósito de verificar el cumplimiento de los principales supuestos de la regresión lineal y considerar sus posibles limitaciones al momento de interpretar los resultados.

3.1 Descricpión del modelo

El modelo será estimado mediante Mínimos Cuadrados Ordinarios (MCO), utilizando una muestra de 140 países con información correspondiente al año 2022, obtenida de Our World in Data. La generación total de electricidad será la variable dependiente y se analizará su relación con factores socioeconómicos y energéticos como la población, el PIB, el consumo de electricidad per cápita, el acceso a electricidad y el continente.

Tabla_modelo <- data.frame(
  Variable = c(
    "Generacion", "β₀", "Poblacion", "PIB",
    "Consumo", "Acceso", "Continente", "ε"
  ),
  
  Descripcion = c(
    "Generación total de electricidad del país",
    "Intercepto del modelo",
    "Población total del país",
    "Producto Interno Bruto total del país",
    "Consumo de electricidad per cápita",
    "Población con acceso a electricidad",
    "Continente al que pertenece el país",
    "Término de error aleatorio"
  ),
  
  Tipo = c(
    "Dependiente - cuantitativa continua",
    "Parámetro",
    "Cuantitativa",
    "Cuantitativa continua",
    "Cuantitativa continua",
    "Cuantitativa continua",
    "Categórica nominal",
    "Error"
  ),
  
  Unidad_Notas = c(
    "TWh",
    "Intercepto",
    "Habitantes",
    "USD",
    "kWh per cápita",
    "%",
    "Categoría de referencia",
    "Factores no observados"
  )
)

knitr::kable(
  Tabla_modelo,
  format = "html",
  col.names = c(
    "Variable",
    "Descripción",
    "Tipo de variable",
    "Unidad / Notas"
  ),
  caption = "Tabla de Variables del Modelo de Regresión",
  escape = FALSE
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = TRUE,
    position = "center"
  ) %>%
  kableExtra::row_spec(
    0,
    bold = TRUE,
    color = "#FBF3DD",
    background = "#3E2416"
  ) %>%
  kableExtra::row_spec(
    seq(2, nrow(Tabla_modelo), by = 2),
    background = "#F5E6C8"
  )
Tabla de Variables del Modelo de Regresión
Variable Descripción Tipo de variable Unidad / Notas
Generacion Generación total de electricidad del país Dependiente - cuantitativa continua TWh
β₀ Intercepto del modelo Parámetro Intercepto
Poblacion Población total del país Cuantitativa Habitantes
PIB Producto Interno Bruto total del país Cuantitativa continua USD
Consumo Consumo de electricidad per cápita Cuantitativa continua kWh per cápita
Acceso Población con acceso a electricidad Cuantitativa continua %
Continente Continente al que pertenece el país Categórica nominal Categoría de referencia
ε Término de error aleatorio Error Factores no observados

3.2 Base de datos del estudio

Para este estudio se utiliza una base de datos construida a partir de información de Our World in Data para el año 2022. La base final está conformada por 140 países y reúne las variables seleccionadas para el modelo: generación total de electricidad, población, PIB total, consumo de electricidad per cápita, acceso a electricidad y continente. La información fue integrada mediante el código de cada país y posteriormente depurada para trabajar únicamente con observaciones completas y consistentes.

library(readxl)
library(tidyverse)


gen <- read.csv("Generacion de electricidad.csv", sep = ",") %>% 
  rename(
    Codigo = 2,
    Generacion = 4
  ) %>% 
  select(Codigo, Generacion)


pob <- read.csv("Poblacion cada pais.csv", sep = ",") %>% 
  rename(
    Codigo = 2,
    Poblacion = 4
  ) %>% 
  select(Codigo, Poblacion)


cont <- read.csv("Continente de cada pais.csv", sep = ",") %>% 
  rename(
    Codigo = 2,
    Continente = 4
  ) %>% 
  select(Codigo, Continente)


cons <- read.csv("Cons energ per capita.xlsx - Data.csv") %>% 
  select(Country.Code, X2022) %>% 
  rename(
    Codigo = Country.Code,
    Consumo = X2022
  )


pib <- read.csv("PIB total de cada pais.csv", sep = ",") %>% 
  rename(
    Codigo = 2,
    PIB = 4
  ) %>% 
  select(Codigo, PIB)


acc <- read.csv("Acceso a electricidad de cada pais.csv", sep = ",") %>% 
  rename(
    Codigo = 2,
    Acceso = 4
  ) %>% 
  select(Codigo, Acceso)


Base_datos <- gen %>% 
  inner_join(pob, by = "Codigo") %>% 
  inner_join(cont, by = "Codigo") %>% 
  inner_join(cons, by = "Codigo") %>% 
  inner_join(pib, by = "Codigo") %>% 
  inner_join(acc, by = "Codigo") %>% filter(Codigo != "ISL") 


Base_datos$Consumo[Base_datos$Consumo == ""] <- NA

Base_datos$Consumo <- as.numeric(
  gsub(",", ".", Base_datos$Consumo)
)


Base_datos <- Base_datos %>% 
  drop_na()


library(gt)

Base_datos %>%
  gt() %>%
  
  
  tab_header(
    title    = "Base de Datos – Indicadores Energéticos 2022",
    subtitle = "140 países  |  Fuente: Our World in Data y Banco Mundial"
  ) %>%
  
 
  cols_label(
    Codigo     = "Código",
    Generacion = "Generación (TWh)",
    Poblacion  = "Población",
    Continente = "Continente",
    Consumo    = "Consumo (kWh per cápita)",
    PIB        = "PIB total (USD)",
    Acceso     = "Acceso a electricidad"
  ) %>%
  
  
  fmt_number(
    columns  = c(Generacion, Consumo),
    decimals = 2,
    sep_mark = ",",
    dec_mark = "."
  ) %>%
  fmt_integer(
    columns  = Poblacion,
    sep_mark = ","
  ) %>%
  fmt_currency(
    columns  = PIB,
    currency = "USD",
    decimals = 0,
    sep_mark = ","
  ) %>%
  fmt_number(
    columns  = Acceso,
    decimals = 2,
    pattern  = "{x} %"
  ) %>%
  
 
  cols_align(
    align   = "center",
    columns = c(Codigo, Continente)
  ) %>%
  cols_align(
    align   = "right",
    columns = c(Generacion, Poblacion, Consumo, PIB, Acceso)
  ) %>%
  
  
  cols_width(
    Codigo     ~ px(80),
    Generacion ~ px(130),
    Poblacion  ~ px(120),
    Continente ~ px(130),
    Consumo    ~ px(170),
    PIB        ~ px(140),
    Acceso     ~ px(150)
  ) %>%
  
  
  tab_style(
    style = list(
      cell_fill(color = "#2E1A0F"),
      cell_text(
        color    = "#F0DFA8",
        weight   = "bold",
        size     = px(20),
        align    = "center",
        font     = "Cinzel"
      )
    ),
    locations = cells_title(groups = "title")
  ) %>%
  tab_style(
    style = list(
      cell_fill(color = "#2E1A0F"),
      cell_text(
        color    = "#E8C766",
        style    = "italic",
        size     = px(14),
        align    = "center"
      )
    ),
    locations = cells_title(groups = "subtitle")
  ) %>%
  
  
  tab_style(
    style = list(
      cell_fill(color = "#3E2416"),
      cell_text(
        color    = "#F0DFA8",
        weight   = "bold",
        size     = px(12),
        font     = "Cinzel",
        align    = "center"
      )
    ),
    locations = cells_column_labels()
  ) %>%
  
  
  tab_style(
    style = list(
      cell_text(color = "#A85834", weight = "bold")
    ),
    locations = cells_body(columns = Continente)
  ) %>%
  
  
  tab_style(
    style = cell_fill(color = "#FBF3DD"),
    locations = cells_body(rows = seq(1, nrow(Base_datos), by = 2))
  ) %>%
  tab_style(
    style = cell_fill(color = "#F5E6C8"),
    locations = cells_body(rows = seq(2, nrow(Base_datos), by = 2))
  ) %>%
  
  
  tab_source_note(
    source_note = "Elaboración propia con base en Our World in Data (2022) y el Banco Mundial."
  ) %>%
  tab_style(
    style = list(
      cell_text(color = "#8B5E34", style = "italic", size = px(11), align = "left")
    ),
    locations = cells_source_notes()
  ) %>%
  
  
  tab_options(
    table.background.color            = "#F5E6C8",
    table.font.names                  = "EB Garamond",
    table.font.color                  = "#2B1810",
    table.font.size                   = px(13.5),
    
    table.border.top.color            = "#D4A017",
    table.border.top.width            = px(3),
    table.border.bottom.color         = "#D4A017",
    table.border.bottom.width         = px(3),
    
    heading.border.bottom.color       = "#D4A017",
    heading.border.bottom.width       = px(2),
    
    column_labels.border.bottom.color = "#D4A017",
    column_labels.border.bottom.width = px(2),
    
    row.striping.include_table_body   = FALSE
  ) %>%
  
 
  opt_interactive(
    use_search           = TRUE,
    use_pagination       = TRUE,
    use_page_size_select = TRUE,
    use_highlight        = TRUE,
    use_compact_mode     = TRUE,
    page_size_default    = 15,
    page_size_values     = c(10, 15, 25, 50, 100)
  )
Base de Datos – Indicadores Energéticos 2022
140 países | Fuente: Our World in Data y Banco Mundial
Elaboración propia con base en Our World in Data (2022) y el Banco Mundial.

4 4 Resultados descriptivos

4.1 Análisis Univariado de las variables del Modelo

4.1.1 Generación de electricidad

En la Tabla 1 se presentan las estadísticas descriptivas de la generación de electricidad de los países incluidos en el estudio, agrupadas por continente. Los resultados muestran diferencias importantes tanto en el nivel promedio de generación como en su dispersión, lo que permite observar que la producción de electricidad no se distribuye de manera uniforme entre los países analizados.

Tabla_generacion <- Base_datos %>%
  group_by(Continente) %>%
  summarise(
    N = n(),
    Promedio = mean(Generacion),
    Desv_Estandar = sd(Generacion),
    Minimo = min(Generacion),
    Maximo = max(Generacion)
  )

kable(
  Tabla_generacion,
  format = "html",
  digits = 2,
  col.names = c(
    "Continente",
    "N",
    "Generación promedio (TWh)",
    "Desv. Estándar",
    "Mínimo",
    "Máximo"
  ),
  caption = "Tabla 1: Estadísticas descriptivas de la generación de electricidad por continente"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = TRUE,
    position = "center"
  ) %>%
  kableExtra::row_spec(
    0,
    bold = TRUE,
    color = "#FBF3DD",
    background = "#3E2416"
  ) %>%
  kableExtra::row_spec(
    seq(2, nrow(Tabla_generacion), by = 2),
    background = "#F5E6C8"
  )
Tabla 1: Estadísticas descriptivas de la generación de electricidad por continente
Continente N Generación promedio (TWh) Desv. Estándar Mínimo Máximo
Africa 35 25.81 53.47 0.39 239.17
Asia 41 388.42 1393.20 4.37 8848.71
Europe 39 120.45 215.22 1.21 1166.94
North America 13 414.52 1179.75 1.01 4286.89
Oceania 2 158.08 162.40 43.25 272.92
South America 10 116.24 201.87 2.11 677.16

Los resultados muestran diferencias importantes en la generación de electricidad entre los países analizados. North America presenta el promedio más alto con 414,52 TWh, seguido de Asia con 388,42 TWh, mientras que África registra el promedio más bajo con 25,81 TWh. Además, se observa una alta dispersión entre países, especialmente en Asia y North America, donde algunos presentan niveles de generación considerablemente superiores al resto. Esto muestra que, incluso dentro de un mismo continente, la generación de electricidad puede variar ampliamente. En el caso de Oceania, los resultados deben interpretarse con cautela debido a que solo se incluyen dos países.

El mapa permite observar la distribución geográfica de la generación de electricidad en 2022, evidenciando una marcada heterogeneidad entre países. Se destacan algunos países con niveles de generación considerablemente superiores al resto, mientras que gran parte presenta valores más bajos. Esta distribución refleja que las diferencias en generación no solo se presentan entre continentes, sino también entre países de una misma región.

library(sf)
library(rnaturalearth)
library(rnaturalearthdata)
library(leaflet)
library(dplyr)
library(htmltools)
library(htmlwidgets)


paleta_generacion <- c(
  "#FAF0DC",   # casi blanco pergamino
  "#F0DFA8",   # dorado pálido
  "#E8C766",   # dorado claro
  "#D4A017",   # dorado
  "#C9821B",   # ámbar
  "#A85834",   # terracota
  "#5C3A21",   # café
  "#2E1A0F"    # café oscuro
)


world <- ne_countries(scale = "medium", returnclass = "sf")


world_data <- world %>%
  left_join(
    Base_datos %>% select(Codigo, Generacion, Continente),
    by = c("iso_a3" = "Codigo")
  )


formato_num <- function(x, decimales = 2) {
  ifelse(
    is.na(x),
    "Sin datos",
    format(round(x, decimales), big.mark = ",", scientific = FALSE, trim = TRUE)
  )
}


pal_gen <- colorNumeric(
  palette  = colorRampPalette(paleta_generacion)(100),
  domain   = world_data$Generacion,
  na.color = "#E7D3A8"
)


labels <- sprintf(
  "<div style='font-family: EB Garamond, Georgia, serif; color: #2B1810;'>
     <strong style='color: #3E2416; font-family: Cinzel, serif; font-size: 15px; letter-spacing: 0.5px;'>%s</strong><br/>
     <span style='color: #8B5E34; font-size: 12px; font-style: italic;'>Generación de electricidad:</span><br/>
     <strong style='color: #A85834; font-size: 14px;'>%s</strong>
   </div>",
  world_data$name,
  paste0(formato_num(world_data$Generacion), " TWh")
) %>% lapply(HTML)


mapa <- leaflet(
  world_data,
  width  = "100%",
  height = "600px",
  options = leafletOptions(
    minZoom       = 2,
    maxZoom       = 6,
    worldCopyJump = TRUE
  )
) %>%
  setView(lng = 10, lat = 18, zoom = 2) %>%
  addProviderTiles("CartoDB.Positron") %>%
  addPolygons(
    fillColor   = ~pal_gen(world_data$Generacion),
    weight      = 1,
    opacity     = 0.85,
    color       = "#5C3A21",
    fillOpacity = 0.88,
    highlight = highlightOptions(
      weight       = 2.5,
      color        = "#D4A017",
      fillOpacity  = 0.95,
      bringToFront = TRUE
    ),
    label        = labels,
    labelOptions = labelOptions(
      style = list(
        "background"    = "#FBF3DD",
        "border"        = "2px solid #D4A017",
        "border-radius" = "6px",
        "padding"       = "10px 12px",
        "box-shadow"    = "0 4px 18px rgba(140, 106, 31, 0.45)"
      ),
      textsize = "13px"
    )
  ) %>%
  addLegend(
    position  = "bottomright",
    pal       = pal_gen,
    values    = ~Generacion,
    title     = paste0(
      "<div style='font-family: Cinzel, Georgia, serif; color: #3E2416; ",
      "font-weight: 700; font-size: 12px; letter-spacing: 1.2px; ",
      "text-transform: uppercase; text-align: center; margin-bottom: 4px;'>",
      "GENERACIÓN DE ELECTRICIDAD</div>",
      "<div style='font-family: EB Garamond, serif; color: #8B5E34; ",
      "font-style: italic; font-size: 11px; text-align: center; ",
      "margin-bottom: 8px;'>Teravatios-hora (TWh)</div>"
    ),
    labFormat = labelFormat(
      suffix   = " TWh",
      digits   = 1,
      big.mark = ","
    ),
    opacity  = 1,
    na.label = "Sin datos"
  )


mapa <- mapa %>%
  htmlwidgets::onRender("
    function(el, x) {

      var container = el.querySelector('.leaflet-container');
      if (container) {
        container.style.background   = '#FBF3DD';
        container.style.border       = '3px solid #D4A017';
        container.style.borderRadius = '8px';
        container.style.boxShadow    = '0 8px 28px rgba(46,26,15,0.35)';
      }

      setTimeout(function() {
        var legend = document.querySelector('.leaflet-control.legend.leaflet-control');
        if (legend) {
          legend.style.background   = 'linear-gradient(135deg, #FBF3DD, #F5E6C8)';
          legend.style.border       = '2px solid #D4A017';
          legend.style.borderRadius = '8px';
          legend.style.padding      = '14px 16px';
          legend.style.boxShadow    = '0 6px 24px rgba(46,26,15,0.35)';
          legend.style.fontFamily   = 'EB Garamond, Georgia, serif';
          legend.style.color        = '#2B1810';

          var items = legend.querySelectorAll('.legend i');
          items.forEach(function(item) {
            item.style.borderRadius = '3px';
            item.style.border       = '1px solid #8C6A1F';
            item.style.boxShadow    = 'inset 0 0 4px rgba(46,26,15,0.25)';
            item.style.width        = '22px';
            item.style.height       = '14px';
            item.style.marginRight  = '8px';
          });

          var divs = legend.querySelectorAll('div');
          divs.forEach(function(d) {
            if (!d.style.color || d.style.color === '') {
              d.style.color      = '#2B1810';
              d.style.fontFamily = 'EB Garamond, Georgia, serif';
              d.style.fontSize   = '11px';
            }
          });
        }

        var attr = document.querySelector('.leaflet-control-attribution');
        if (attr) {
          attr.style.background = 'rgba(251, 243, 221, 0.85)';
          attr.style.color      = '#5C3A21';
          attr.style.fontFamily = 'EB Garamond, serif';
          attr.style.fontSize   = '10px';
        }

        var zoomIn  = document.querySelector('.leaflet-control-zoom-in');
        var zoomOut = document.querySelector('.leaflet-control-zoom-out');
        [zoomIn, zoomOut].forEach(function(btn) {
          if (btn) {
            btn.style.background = '#FBF3DD';
            btn.style.color      = '#5C3A21';
            btn.style.border     = '2px solid #D4A017';
            btn.style.fontWeight = 'bold';
          }
        });
      }, 150);
    }
  ")


htmltools::tagList(
  htmltools::HTML(
    '<div style="
       text-align: center;
       color: #3E2416;
       font-family: Cinzel, Georgia, serif;
       font-size: 20px;
       font-weight: 700;
       letter-spacing: 2px;
       text-transform: uppercase;
       margin: 1.5rem 0 1rem 0;
       padding-bottom: 0.6rem;
       border-bottom: 3px double #D4A017;
     ">
       ❖ Distribución Geoespacial de la Generación de Electricidad 2022 ❖
       <div style=\"font-family: EB Garamond, serif; font-style: italic;
                   font-size: 13px; color: #8B5E34;
                   letter-spacing: normal; text-transform: none;
                   margin-top: 0.4rem;\">
         Teravatios-hora (TWh) por país | Fuente: Our World in Data, 2022
       </div>
     </div>'
  ),
  mapa
)
❖ Distribución Geoespacial de la Generación de Electricidad 2022 ❖
Teravatios-hora (TWh) por país | Fuente: Our World in Data, 2022

4.2 Variables Explicativas Cuantitativas

4.2.1 Consumo de energía per capitá

El consumo de electricidad per cápita representa la cantidad de electricidad consumida por habitante, expresada en kWh per cápita. En la tabla se presentan sus principales estadísticas descriptivas para los 140 países de la muestra, agrupados según el continente al que pertenecen.

Tabla_consumo <- Base_datos %>%
  group_by(Continente) %>%
  summarise(
    N = n(),
    Promedio = mean(Consumo),
    Desv_Estandar = sd(Consumo),
    Minimo = min(Consumo),
    Maximo = max(Consumo)
  )

kable(
  Tabla_consumo,
  format = "html",
  digits = 2,
  col.names = c(
    "Continente",
    "N",
    "Consumo promedio",
    "Desv. Estándar",
    "Mínimo",
    "Máximo"
  ),
  caption = "Tabla 2: Estadísticas descriptivas del consumo de electricidad per cápita por continente"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = TRUE,
    position = "center"
  ) %>%
  kableExtra::row_spec(
    0,
    bold = TRUE,
    color = "#FBF3DD",
    background = "#3E2416"
  ) %>%
  kableExtra::row_spec(
    seq(2, nrow(Tabla_consumo), by = 2),
    background = "#F5E6C8"
  )
Tabla 2: Estadísticas descriptivas del consumo de electricidad per cápita por continente
Continente N Consumo promedio Desv. Estándar Mínimo Máximo
Africa 35 767.41 941.45 15.55 3979.07
Asia 41 5099.65 5596.50 321.38 23151.55
Europe 39 6154.70 3825.14 2255.35 23373.47
North America 13 3682.75 4847.97 76.24 14901.64
Oceania 2 9034.07 1257.74 8144.72 9923.43
South America 10 2433.11 1084.83 859.64 4405.86

En la tabla se observan diferencias importantes en el consumo de electricidad per cápita entre los continentes. Oceania presenta el promedio más alto, con 9.034,07 kWh per cápita, aunque este resultado debe interpretarse con cautela porque solo incluye dos países. Le siguen Europe con 6.154,70 kWh y Asia con 5.099,65 kWh, mientras que Africa registra el promedio más bajo, con 767,41 kWh per cápita. También se evidencia una alta dispersión dentro de algunos continentes, especialmente en Asia y North America, lo que muestra que existen diferencias considerables entre los países de una misma región. Por su parte, el diagrama de dispersión muestra una tendencia positiva entre el consumo per cápita y la generación total de electricidad, aunque los puntos se encuentran bastante dispersos y existen algunos valores extremos. Por esta razón, la relación deberá evaluarse posteriormente junto con las demás variables del modelo de regresión.

Para facilitar la visualización de esta relación, se presentan dos versiones del diagrama de dispersión: una con los 140 países de la muestra y otra excluyendo únicamente de la visualización los 20 países con mayor generación de electricidad. Esta segunda gráfica permite observar con mayor claridad la distribución y la tendencia del resto de los países, evitando que los valores extremos compriman visualmente la mayoría de las observaciones. Esta exclusión se realizó solo con fines gráficos y descriptivos, por lo que los países continúan incluidos en la base y en el modelo de regresión.

library(plotly)
library(dplyr)


colores <- c(
  "Africa"        = "#A85834",
  "Asia"          = "#3E2416",
  "Europe"        = "#C9821B",
  "North America" = "#D4A017",
  "Oceania"       = "#6D4C2F",
  "South America" = "#E8C766"
)


datos_plot <- Base_datos %>%
  filter(
    !is.na(Consumo), Consumo > 0,
    !is.na(Generacion), Generacion > 0,
    !is.na(Continente)
  ) %>%
  mutate(
    Continente = factor(
      Continente,
      levels = c("Africa", "Asia", "Europe",
                 "North America", "Oceania", "South America")
    )
  )


N_TOP <- 20

top_n <- datos_plot %>%
  arrange(desc(Generacion)) %>%
  slice(1:N_TOP) %>%
  pull(Codigo)

datos_sin_top <- datos_plot %>% filter(!Codigo %in% top_n)


etiquetas_full <- datos_plot %>%
  arrange(desc(Generacion)) %>%
  slice(1:10)

etiquetas_filt <- datos_sin_top %>%
  arrange(desc(Generacion)) %>%
  slice(1:10)


modelo_full <- lm(Generacion ~ Consumo, data = datos_plot)
modelo_filt <- lm(Generacion ~ Consumo, data = datos_sin_top)

x_seq <- seq(min(datos_plot$Consumo),
             max(datos_plot$Consumo),
             length.out = 200)

pred_full <- predict(modelo_full, newdata = data.frame(Consumo = x_seq),
                     interval = "confidence", level = 0.95)
pred_filt <- predict(modelo_filt, newdata = data.frame(Consumo = x_seq),
                     interval = "confidence", level = 0.95)

continentes <- levels(datos_plot$Continente)
n_cont      <- length(continentes)


fmt_num <- function(x, dec = 2) {
  format(round(x, dec),
         big.mark = ".", decimal.mark = ",",
         scientific = FALSE, trim = TRUE)
}


ann_full <- lapply(seq_len(nrow(etiquetas_full)), function(i) {
  list(
    x           = etiquetas_full$Consumo[i],
    y           = etiquetas_full$Generacion[i],
    xref        = "x",
    yref        = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#2E1A0F;'>",
      etiquetas_full$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 22,
    yshift      = 10,
    font        = list(size = 11),
    visible     = TRUE
  )
})

ann_filt <- lapply(seq_len(nrow(etiquetas_filt)), function(i) {
  list(
    x           = etiquetas_filt$Consumo[i],
    y           = etiquetas_filt$Generacion[i],
    xref        = "x",
    yref        = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#7A2E1A;'>",
      etiquetas_filt$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#A85834",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 22,
    yshift      = 10,
    font        = list(size = 11),
    visible     = FALSE
  )
})

ann_todas <- c(ann_full, ann_filt)
n_full    <- length(ann_full)
n_filt    <- length(ann_filt)


visible_full <- c(
  TRUE,  TRUE,
  FALSE, FALSE,
  rep(TRUE,  n_cont),
  rep(FALSE, n_cont)
)

visible_filt <- c(
  FALSE, FALSE,
  TRUE,  TRUE,
  rep(FALSE, n_cont),
  rep(TRUE,  n_cont)
)


idx_full <- 0:(n_full - 1)
idx_filt <- n_full:(n_full + n_filt - 1)


relayout_full_ann <- setNames(
  as.list(c(rep(TRUE, n_full), rep(FALSE, n_filt))),
  paste0("annotations[", c(idx_full, idx_filt), "].visible")
)


relayout_filt_ann <- setNames(
  as.list(c(rep(FALSE, n_full), rep(TRUE, n_filt))),
  paste0("annotations[", c(idx_full, idx_filt), "].visible")
)


fig <- plot_ly()


fig <- fig %>% add_ribbons(
  x = x_seq, ymin = pred_full[, "lwr"], ymax = pred_full[, "upr"],
  fillcolor = "#D4A017", opacity = 0.18,
  line = list(width = 0),
  name = "IC 95% (todos)",
  hoverinfo = "skip",
  showlegend = TRUE
)


fig <- fig %>% add_lines(
  x = x_seq, y = pred_full[, "fit"],
  line = list(color = "#3E2416", width = 3),
  name = "Tendencia (todos)",
  hoverinfo = "skip",
  showlegend = TRUE
)


fig <- fig %>% add_ribbons(
  x = x_seq, ymin = pred_filt[, "lwr"], ymax = pred_filt[, "upr"],
  fillcolor = "#A85834", opacity = 0.15,
  line = list(width = 0),
  name = "IC 95% (sin Top 20)",
  hoverinfo = "skip",
  showlegend = TRUE,
  visible = FALSE
)


fig <- fig %>% add_lines(
  x = x_seq, y = pred_filt[, "fit"],
  line = list(color = "#A85834", width = 3),
  name = "Tendencia (sin Top 20)",
  hoverinfo = "skip",
  showlegend = TRUE,
  visible = FALSE
)


for (cont in continentes) {
  sub <- datos_plot %>% filter(Continente == cont)

  fig <- fig %>% add_markers(
    data = sub,
    x = ~Consumo, y = ~Generacion,
    marker = list(
      size = 10, opacity = 0.85,
      color = colores[cont],
      line = list(color = "#FBF3DD", width = 0.9)
    ),
    text = ~paste0(
      "<b style='color:#3E2416; font-size:13px;'>", Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>Consumo:</b> ",     fmt_num(Consumo),     " kWh per cápita",
      "<br><b>Generación:</b> ",  fmt_num(Generacion),  " TWh"
    ),
    hoverinfo   = "text",
    name        = cont,
    legendgroup = cont,
    showlegend  = TRUE
  )
}


for (cont in continentes) {
  sub <- datos_sin_top %>% filter(Continente == cont)

  fig <- fig %>% add_markers(
    data = sub,
    x = ~Consumo, y = ~Generacion,
    marker = list(
      size = 10, opacity = 0.85,
      color = colores[cont],
      line = list(color = "#FBF3DD", width = 0.9)
    ),
    text = ~paste0(
      "<b style='color:#3E2416; font-size:13px;'>", Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>Consumo:</b> ",     fmt_num(Consumo),     " kWh per cápita",
      "<br><b>Generación:</b> ",  fmt_num(Generacion),  " TWh"
    ),
    hoverinfo   = "text",
    name        = paste0(cont, " (sin Top 20)"),
    legendgroup = cont,
    showlegend  = FALSE,
    visible     = FALSE
  )
}


titulo_base <- paste0(
  "<b style='font-family:Cinzel, Georgia, serif; color:#3E2416; ",
  "font-size:18px; letter-spacing:1px;'>",
  "CONSUMO PER CÁPITA VS GENERACIÓN DE ELECTRICIDAD</b><br>"
)

subtitulo_full <- "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>Todos los países | Tendencia lineal e IC del 95% | Etiquetas: 10 mayores generadores</span>"

subtitulo_filt <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Sin los ", N_TOP, " mayores generadores | Tendencia lineal e IC del 95%",
  " | Etiquetas: 10 mayores del resto</span>"
)


fig <- fig %>% layout(

  title = list(
    text    = paste0(titulo_base, subtitulo_full),
    x       = 0.5,
    xanchor = "center",
    y       = 0.97
  ),

  xaxis = list(
    title         = "<b>Consumo de electricidad per cápita (kWh)</b>",
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  yaxis = list(
    title         = "<b>Generación de electricidad (TWh)</b>",
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  paper_bgcolor = "#FFFFFF",
  plot_bgcolor  = "#FBF3DD",

  font = list(
    family = "EB Garamond, Georgia, serif",
    color  = "#2B1810",
    size   = 12
  ),

  legend = list(
    title = list(
      text = paste0(
        "<b style='font-family:Cinzel, serif; color:#3E2416; ",
        "font-size:12px; letter-spacing:1px;'>❖ CONTINENTE</b>"
      )
    ),
    orientation = "v",
    x           = 1.02,
    xanchor     = "left",
    y           = 1,
    yanchor     = "top",
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 2,
    font = list(
      family = "EB Garamond, Georgia, serif",
      size   = 12,
      color  = "#3E2416"
    ),
    itemsizing = "constant",
    traceorder = "normal"
  ),

  margin = list(t = 130, b = 200, l = 90, r = 190),

  annotations = ann_todas,

  updatemenus = list(
    list(
      type        = "buttons",
      direction   = "right",
      x           = 0.5,
      xanchor     = "center",
      y           = -0.32,
      yanchor     = "top",
      showactive  = TRUE,
      bgcolor     = "#FBF3DD",
      bordercolor = "#D4A017",
      borderwidth = 1.5,
      pad         = list(r = 10, t = 5),
      font = list(
        size   = 12,
        family = "EB Garamond, Georgia, serif",
        color  = "#3E2416"
      ),
      buttons = list(

        
        list(
          label  = "📏 Lineal (todos)",
          method = "update",
          args   = list(
            list(visible = visible_full),
            c(
              list(
                "title.text"      = paste0(titulo_base, subtitulo_full),
                "xaxis.autorange" = TRUE,
                "yaxis.autorange" = TRUE
              ),
              relayout_full_ann
            )
          )
        ),

        
        list(
          label  = paste0("🚫 Sin Top ", N_TOP),
          method = "update",
          args   = list(
            list(visible = visible_filt),
            c(
              list(
                "title.text"      = paste0(titulo_base, subtitulo_filt),
                "xaxis.autorange" = TRUE,
                "yaxis.autorange" = TRUE
              ),
              relayout_filt_ann
            )
          )
        )
      )
    )
  )
) %>%
  config(
    responsive  = TRUE,
    displaylogo = FALSE,
    modeBarButtonsToRemove = list("lasso2d", "select2d"),
    toImageButtonOptions = list(
      format   = "png",
      filename = "dispersion_consumo_generacion_2022",
      width    = 1600,
      height   = 900
    )
  )

fig

4.2.2 Población total

La población total corresponde al número de habitantes de cada país incluido en el estudio. En la Tabla 3 se presentan sus principales estadísticas descriptivas para los 140 países de la muestra, agrupados por continente.

Tabla_poblacion <- Base_datos %>%
  group_by(Continente) %>%
  summarise(
    N = n(),
    Promedio = mean(Poblacion),
    Desv_Estandar = sd(Poblacion),
    Minimo = min(Poblacion),
    Maximo = max(Poblacion)
  )

kable(
  Tabla_poblacion,
  format = "html",
  digits = 2,
  col.names = c(
    "Continente",
    "N",
    "Población promedio",
    "Desv. Estándar",
    "Mínimo",
    "Máximo"
  ),
  caption = "Tabla 3: Estadísticas descriptivas de la población por continente"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = TRUE,
    position = "center"
  ) %>%
  kableExtra::row_spec(
    0,
    bold = TRUE,
    color = "#FBF3DD",
    background = "#3E2416"
  ) %>%
  kableExtra::row_spec(
    seq(2, nrow(Tabla_poblacion), by = 2),
    background = "#F5E6C8"
  )
Tabla 3: Estadísticas descriptivas de la población por continente
Continente N Población promedio Desv. Estándar Mínimo Máximo
Africa 35 37353338 44796150 1218921 223150906
Asia 41 112416953 307587964 455374 1425423209
Europe 39 19119542 29895328 528194 145579889
North America 13 45141777 95319428 1495923 341534041
Oceania 2 15666359 14898214 5131731 26200987
South America 10 40115633 62270828 623172 210306411

En la tabla 3 se puede ver como la población total también presenta diferencias amplias entre los países analizados. Asia registra el promedio más alto, con aproximadamente 112,4 millones de habitantes, seguida de North America y South America, mientras que Oceania presenta el promedio más bajo. La variabilidad es especialmente marcada en Asia, donde conviven países con poblaciones relativamente pequeñas y otros que superan los mil millones de habitantes. En el diagrama de dispersión se aprecia que, en general, los países con mayor población tienden a presentar una mayor generación de electricidad, aunque los puntos no siguen un comportamiento uniforme y algunos países se encuentran bastante alejados del grupo principal. Esto refleja que países con tamaños poblacionales similares pueden tener niveles de generación diferentes.

Para facilitar la interpretación gráfica, se presentan dos versiones del diagrama de dispersión: una con los 140 países de la muestra y otra excluyendo únicamente de la visualización los 5 países con mayor generación de electricidad. Esto permite apreciar con mayor claridad la distribución y la tendencia entre población y generación, evitando que los valores extremos compriman visualmente al resto de las observaciones. Esta exclusión se realizó solo con fines gráficos, por lo que estos países permanecen incluidos en la base y en el modelo de regresión.

library(plotly)
library(dplyr)


VAR_X    <- "Poblacion"
ETIQ_X   <- "Población total (habitantes)"
UNIDAD_X <- " hab"

N_TOP <- 5   # quitar los 5 mayores generadores


colores <- c(
  "Africa"        = "#A85834",
  "Asia"          = "#3E2416",
  "Europe"        = "#C9821B",
  "North America" = "#D4A017",
  "Oceania"       = "#6D4C2F",
  "South America" = "#E8C766"
)


datos_plot <- Base_datos %>%
  filter(
    !is.na(.data[[VAR_X]]), .data[[VAR_X]] > 0,
    !is.na(Generacion),     Generacion > 0,
    !is.na(Continente)
  ) %>%
  mutate(
    Continente = factor(
      Continente,
      levels = c("Africa", "Asia", "Europe",
                 "North America", "Oceania", "South America")
    )
  )


top_n <- datos_plot %>%
  arrange(desc(Generacion)) %>%
  slice(1:N_TOP) %>%
  pull(Codigo)

datos_sin_top <- datos_plot %>% filter(!Codigo %in% top_n)


etiquetas_full <- datos_plot %>%
  arrange(desc(Generacion)) %>%
  slice(1:10)

etiquetas_filt <- datos_sin_top %>%
  arrange(desc(Generacion)) %>%
  slice(1:10)


formula_mod <- as.formula(paste0("Generacion ~ `", VAR_X, "`"))

modelo_full <- lm(formula_mod, data = datos_plot)
modelo_filt <- lm(formula_mod, data = datos_sin_top)

x_seq <- seq(min(datos_plot[[VAR_X]]),
             max(datos_plot[[VAR_X]]),
             length.out = 200)

pred_full <- predict(modelo_full, newdata = setNames(data.frame(x_seq), VAR_X),
                     interval = "confidence", level = 0.95)
pred_filt <- predict(modelo_filt, newdata = setNames(data.frame(x_seq), VAR_X),
                     interval = "confidence", level = 0.95)

continentes <- levels(datos_plot$Continente)
n_cont      <- length(continentes)


fmt_num <- function(x, dec = 2) {
  format(round(x, dec),
         big.mark = ".", decimal.mark = ",",
         scientific = FALSE, trim = TRUE)
}


ann_full <- lapply(seq_len(nrow(etiquetas_full)), function(i) {
  list(
    x           = etiquetas_full[[VAR_X]][i],
    y           = etiquetas_full$Generacion[i],
    xref        = "x", yref = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#2E1A0F;'>",
      etiquetas_full$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 22, yshift = 10,
    font        = list(size = 11),
    visible     = TRUE
  )
})

ann_filt <- lapply(seq_len(nrow(etiquetas_filt)), function(i) {
  list(
    x           = etiquetas_filt[[VAR_X]][i],
    y           = etiquetas_filt$Generacion[i],
    xref        = "x", yref = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#7A2E1A;'>",
      etiquetas_filt$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#A85834",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 22, yshift = 10,
    font        = list(size = 11),
    visible     = FALSE
  )
})

ann_todas <- c(ann_full, ann_filt)
n_full    <- length(ann_full)
n_filt    <- length(ann_filt)


visible_full <- c(
  TRUE,  TRUE,
  FALSE, FALSE,
  rep(TRUE,  n_cont),
  rep(FALSE, n_cont)
)

visible_filt <- c(
  FALSE, FALSE,
  TRUE,  TRUE,
  rep(FALSE, n_cont),
  rep(TRUE,  n_cont)
)


idx_full <- 0:(n_full - 1)
idx_filt <- n_full:(n_full + n_filt - 1)

relayout_full_ann <- setNames(
  as.list(c(rep(TRUE, n_full), rep(FALSE, n_filt))),
  paste0("annotations[", c(idx_full, idx_filt), "].visible")
)

relayout_filt_ann <- setNames(
  as.list(c(rep(FALSE, n_full), rep(TRUE, n_filt))),
  paste0("annotations[", c(idx_full, idx_filt), "].visible")
)


fig <- plot_ly()


fig <- fig %>% add_ribbons(
  x = x_seq, ymin = pred_full[, "lwr"], ymax = pred_full[, "upr"],
  fillcolor = "#D4A017", opacity = 0.18,
  line = list(width = 0),
  name = "IC 95% (todos)",
  hoverinfo = "skip",
  showlegend = TRUE
)


fig <- fig %>% add_lines(
  x = x_seq, y = pred_full[, "fit"],
  line = list(color = "#3E2416", width = 3),
  name = "Tendencia (todos)",
  hoverinfo = "skip",
  showlegend = TRUE
)


fig <- fig %>% add_ribbons(
  x = x_seq, ymin = pred_filt[, "lwr"], ymax = pred_filt[, "upr"],
  fillcolor = "#A85834", opacity = 0.15,
  line = list(width = 0),
  name = paste0("IC 95% (sin Top ", N_TOP, ")"),
  hoverinfo = "skip",
  showlegend = TRUE,
  visible = FALSE
)


fig <- fig %>% add_lines(
  x = x_seq, y = pred_filt[, "fit"],
  line = list(color = "#A85834", width = 3),
  name = paste0("Tendencia (sin Top ", N_TOP, ")"),
  hoverinfo = "skip",
  showlegend = TRUE,
  visible = FALSE
)


for (cont in continentes) {
  sub <- datos_plot %>% filter(Continente == cont)

  fig <- fig %>% add_markers(
    data = sub,
    x = as.formula(paste0("~`", VAR_X, "`")),
    y = ~Generacion,
    marker = list(
      size = 10, opacity = 0.85,
      color = colores[cont],
      line = list(color = "#FBF3DD", width = 0.9)
    ),
    text = ~paste0(
      "<b style='color:#3E2416; font-size:13px;'>", Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>", ETIQ_X, ":</b> ", fmt_num(.data[[VAR_X]], 0), UNIDAD_X,
      "<br><b>Generación:</b> ",  fmt_num(Generacion),  " TWh"
    ),
    hoverinfo   = "text",
    name        = cont,
    legendgroup = cont,
    showlegend  = TRUE
  )
}


for (cont in continentes) {
  sub <- datos_sin_top %>% filter(Continente == cont)

  fig <- fig %>% add_markers(
    data = sub,
    x = as.formula(paste0("~`", VAR_X, "`")),
    y = ~Generacion,
    marker = list(
      size = 10, opacity = 0.85,
      color = colores[cont],
      line = list(color = "#FBF3DD", width = 0.9)
    ),
    text = ~paste0(
      "<b style='color:#3E2416; font-size:13px;'>", Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>", ETIQ_X, ":</b> ", fmt_num(.data[[VAR_X]], 0), UNIDAD_X,
      "<br><b>Generación:</b> ",  fmt_num(Generacion),  " TWh"
    ),
    hoverinfo   = "text",
    name        = paste0(cont, " (sin Top ", N_TOP, ")"),
    legendgroup = cont,
    showlegend  = FALSE,
    visible     = FALSE
  )
}


titulo_base <- paste0(
  "<b style='font-family:Cinzel, Georgia, serif; color:#3E2416; ",
  "font-size:18px; letter-spacing:1px;'>",
  "POBLACIÓN VS GENERACIÓN DE ELECTRICIDAD</b><br>"
)

subtitulo_full <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Todos los países | Tendencia lineal e IC del 95% | ",
  "Etiquetas: 10 mayores generadores</span>"
)

subtitulo_filt <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Sin los ", N_TOP, " mayores generadores | Tendencia lineal e IC del 95%",
  " | Etiquetas: 10 mayores del resto</span>"
)


fig <- fig %>% layout(

  title = list(
    text    = paste0(titulo_base, subtitulo_full),
    x       = 0.5, xanchor = "center",
    y       = 0.97
  ),

  xaxis = list(
    title         = paste0("<b>", ETIQ_X, "</b>"),
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    tickformat    = ",.0f",
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  yaxis = list(
    title         = "<b>Generación de electricidad (TWh)</b>",
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  paper_bgcolor = "#FFFFFF",
  plot_bgcolor  = "#FBF3DD",

  font = list(
    family = "EB Garamond, Georgia, serif",
    color  = "#2B1810",
    size   = 12
  ),

  legend = list(
    title = list(
      text = paste0(
        "<b style='font-family:Cinzel, serif; color:#3E2416; ",
        "font-size:12px; letter-spacing:1px;'>❖ CONTINENTE</b>"
      )
    ),
    orientation = "v",
    x           = 1.02, xanchor = "left",
    y           = 1,    yanchor = "top",
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 2,
    font = list(
      family = "EB Garamond, Georgia, serif",
      size   = 12,
      color  = "#3E2416"
    ),
    itemsizing = "constant",
    traceorder = "normal"
  ),

  margin = list(t = 130, b = 200, l = 110, r = 190),

  annotations = ann_todas,

  updatemenus = list(
    list(
      type        = "buttons",
      direction   = "right",
      x           = 0.5,  xanchor = "center",
      y           = -0.32, yanchor = "top",
      showactive  = TRUE,
      bgcolor     = "#FBF3DD",
      bordercolor = "#D4A017",
      borderwidth = 1.5,
      pad         = list(r = 10, t = 5),
      font = list(
        size   = 12,
        family = "EB Garamond, Georgia, serif",
        color  = "#3E2416"
      ),
      buttons = list(

        list(
          label  = "📏 Lineal (todos)",
          method = "update",
          args   = list(
            list(visible = visible_full),
            c(
              list(
                "title.text"      = paste0(titulo_base, subtitulo_full),
                "xaxis.autorange" = TRUE,
                "yaxis.autorange" = TRUE
              ),
              relayout_full_ann
            )
          )
        ),

        list(
          label  = paste0("🚫 Sin Top ", N_TOP),
          method = "update",
          args   = list(
            list(visible = visible_filt),
            c(
              list(
                "title.text"      = paste0(titulo_base, subtitulo_filt),
                "xaxis.autorange" = TRUE,
                "yaxis.autorange" = TRUE
              ),
              relayout_filt_ann
            )
          )
        )
      )
    )
  )
) %>%
  config(
    responsive  = TRUE,
    displaylogo = FALSE,
    modeBarButtonsToRemove = list("lasso2d", "select2d"),
    toImageButtonOptions = list(
      format   = "png",
      filename = "dispersion_poblacion_generacion_2022",
      width    = 1600,
      height   = 900
    )
  )

fig

4.2.3 PIB total

El PIB total representa el valor de la producción económica de cada país, expresado en dólares estadounidenses (USD). En la Tabla 4 se presentan sus principales estadísticas descriptivas para los 140 países de la muestra, agrupados por continente.

Tabla_pib <- Base_datos %>%
  group_by(Continente) %>%
  summarise(
    N = n(),
    Promedio = mean(PIB),
    Desv_Estandar = sd(PIB),
    Minimo = min(PIB),
    Maximo = max(PIB)
  )

kable(
  Tabla_pib,
  format = "html",
  digits = 2,
  col.names = c(
    "Continente",
    "N",
    "PIB promedio",
    "Desv. Estándar",
    "Mínimo",
    "Máximo"
  ),
  caption = "Tabla 4: Estadísticas descriptivas del PIB total por continente"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = TRUE,
    position = "center"
  ) %>%
  kableExtra::row_spec(
    0,
    bold = TRUE,
    color = "#FBF3DD",
    background = "#3E2416"
  ) %>%
  kableExtra::row_spec(
    seq(2, nrow(Tabla_pib), by = 2),
    background = "#F5E6C8"
  )
Tabla 4: Estadísticas descriptivas del PIB total por continente
Continente N PIB promedio Desv. Estándar Mínimo Máximo
Africa 35 2.466715e+11 4.250435e+11 12100927320 1.842479e+12
Asia 41 1.838284e+12 5.020658e+12 34771064644 3.036079e+13
Europe 39 9.160439e+11 1.422724e+12 15953525339 5.606621e+12
North America 13 2.338753e+12 6.667834e+12 31504952370 2.432453e+13
Oceania 2 9.075842e+11 9.253158e+11 253287094503 1.561881e+12
South America 10 7.830390e+11 1.169676e+12 11679705719 3.902035e+12

El PIB total muestra una marcada diferencia en el tamaño de las economías incluidas en el estudio. North America presenta el promedio más alto, con aproximadamente 2,34 billones de USD, seguido de Asia con 1,84 billones de USD, mientras que África registra el menor promedio, cercano a 246,7 mil millones de USD. A su vez, existe una amplia dispersión entre los países, principalmente en North America y Asia, donde algunos valores son considerablemente superiores al resto. En el diagrama de dispersión se observa que los mayores niveles de PIB tienden a acompañarse de una mayor generación de electricidad, aunque gran parte de los países se concentra en valores más bajos y unas pocas observaciones se encuentran bastante alejadas del conjunto principal.

Para facilitar la interpretación gráfica, se presentan dos versiones del diagrama de dispersión: una con los 140 países de la muestra y otra excluyendo únicamente de la visualización los 5 países con mayor generación de electricidad. Esta segunda representación permite observar con mayor claridad la relación positiva entre el PIB y la generación, evitando que los valores extremos compriman visualmente al resto de las observaciones. La exclusión se realizó solo con fines gráficos, por lo que estos países permanecen incluidos en la base y en el modelo de regresión.

library(plotly)
library(dplyr)


VAR_X    <- "PIB"
ETIQ_X   <- "PIB total (USD)"
UNIDAD_X <- " USD"

N_TOP <- 5


colores <- c(
  "Africa"        = "#A85834",
  "Asia"          = "#3E2416",
  "Europe"        = "#C9821B",
  "North America" = "#D4A017",
  "Oceania"       = "#6D4C2F",
  "South America" = "#E8C766"
)


datos_plot <- Base_datos %>%
  filter(
    !is.na(.data[[VAR_X]]), .data[[VAR_X]] > 0,
    !is.na(Generacion),     Generacion > 0,
    !is.na(Continente)
  ) %>%
  mutate(
    Continente = factor(
      Continente,
      levels = c("Africa", "Asia", "Europe",
                 "North America", "Oceania", "South America")
    )
  )


top_n <- datos_plot %>%
  arrange(desc(Generacion)) %>%
  slice(1:N_TOP) %>%
  pull(Codigo)

datos_sin_top <- datos_plot %>% filter(!Codigo %in% top_n)


etiquetas_full <- datos_plot %>%
  arrange(desc(Generacion)) %>%
  slice(1:10)

etiquetas_filt <- datos_sin_top %>%
  arrange(desc(Generacion)) %>%
  slice(1:10)


formula_mod <- as.formula(paste0("Generacion ~ `", VAR_X, "`"))

modelo_full <- lm(formula_mod, data = datos_plot)
modelo_filt <- lm(formula_mod, data = datos_sin_top)

x_seq <- seq(min(datos_plot[[VAR_X]]),
             max(datos_plot[[VAR_X]]),
             length.out = 200)

pred_full <- predict(modelo_full, newdata = setNames(data.frame(x_seq), VAR_X),
                     interval = "confidence", level = 0.95)
pred_filt <- predict(modelo_filt, newdata = setNames(data.frame(x_seq), VAR_X),
                     interval = "confidence", level = 0.95)

continentes <- levels(datos_plot$Continente)
n_cont      <- length(continentes)


fmt_num <- function(x, dec = 2) {
  format(round(x, dec),
         big.mark = ".", decimal.mark = ",",
         scientific = FALSE, trim = TRUE)
}


ann_full <- lapply(seq_len(nrow(etiquetas_full)), function(i) {
  list(
    x           = etiquetas_full[[VAR_X]][i],
    y           = etiquetas_full$Generacion[i],
    xref        = "x", yref = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#2E1A0F;'>",
      etiquetas_full$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 22, yshift = 10,
    font        = list(size = 11),
    visible     = TRUE
  )
})

ann_filt <- lapply(seq_len(nrow(etiquetas_filt)), function(i) {
  list(
    x           = etiquetas_filt[[VAR_X]][i],
    y           = etiquetas_filt$Generacion[i],
    xref        = "x", yref = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#7A2E1A;'>",
      etiquetas_filt$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#A85834",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 22, yshift = 10,
    font        = list(size = 11),
    visible     = FALSE
  )
})

ann_todas <- c(ann_full, ann_filt)
n_full    <- length(ann_full)
n_filt    <- length(ann_filt)


visible_full <- c(
  TRUE,  TRUE,
  FALSE, FALSE,
  rep(TRUE,  n_cont),
  rep(FALSE, n_cont)
)

visible_filt <- c(
  FALSE, FALSE,
  TRUE,  TRUE,
  rep(FALSE, n_cont),
  rep(TRUE,  n_cont)
)


idx_full <- 0:(n_full - 1)
idx_filt <- n_full:(n_full + n_filt - 1)

relayout_full_ann <- setNames(
  as.list(c(rep(TRUE, n_full), rep(FALSE, n_filt))),
  paste0("annotations[", c(idx_full, idx_filt), "].visible")
)

relayout_filt_ann <- setNames(
  as.list(c(rep(FALSE, n_full), rep(TRUE, n_filt))),
  paste0("annotations[", c(idx_full, idx_filt), "].visible")
)


fig <- plot_ly()


fig <- fig %>% add_ribbons(
  x = x_seq, ymin = pred_full[, "lwr"], ymax = pred_full[, "upr"],
  fillcolor = "#D4A017", opacity = 0.18,
  line = list(width = 0),
  name = "IC 95% (todos)",
  hoverinfo = "skip",
  showlegend = TRUE
)


fig <- fig %>% add_lines(
  x = x_seq, y = pred_full[, "fit"],
  line = list(color = "#3E2416", width = 3),
  name = "Tendencia (todos)",
  hoverinfo = "skip",
  showlegend = TRUE
)


fig <- fig %>% add_ribbons(
  x = x_seq, ymin = pred_filt[, "lwr"], ymax = pred_filt[, "upr"],
  fillcolor = "#A85834", opacity = 0.15,
  line = list(width = 0),
  name = paste0("IC 95% (sin Top ", N_TOP, ")"),
  hoverinfo = "skip",
  showlegend = TRUE,
  visible = FALSE
)


fig <- fig %>% add_lines(
  x = x_seq, y = pred_filt[, "fit"],
  line = list(color = "#A85834", width = 3),
  name = paste0("Tendencia (sin Top ", N_TOP, ")"),
  hoverinfo = "skip",
  showlegend = TRUE,
  visible = FALSE
)


for (cont in continentes) {
  sub <- datos_plot %>% filter(Continente == cont)

  fig <- fig %>% add_markers(
    data = sub,
    x = as.formula(paste0("~`", VAR_X, "`")),
    y = ~Generacion,
    marker = list(
      size = 10, opacity = 0.85,
      color = colores[cont],
      line = list(color = "#FBF3DD", width = 0.9)
    ),
    text = ~paste0(
      "<b style='color:#3E2416; font-size:13px;'>", Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>", ETIQ_X, ":</b> ", fmt_num(.data[[VAR_X]], 0), UNIDAD_X,
      "<br><b>Generación:</b> ",  fmt_num(Generacion),  " TWh"
    ),
    hoverinfo   = "text",
    name        = cont,
    legendgroup = cont,
    showlegend  = TRUE
  )
}


for (cont in continentes) {
  sub <- datos_sin_top %>% filter(Continente == cont)

  fig <- fig %>% add_markers(
    data = sub,
    x = as.formula(paste0("~`", VAR_X, "`")),
    y = ~Generacion,
    marker = list(
      size = 10, opacity = 0.85,
      color = colores[cont],
      line = list(color = "#FBF3DD", width = 0.9)
    ),
    text = ~paste0(
      "<b style='color:#3E2416; font-size:13px;'>", Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>", ETIQ_X, ":</b> ", fmt_num(.data[[VAR_X]], 0), UNIDAD_X,
      "<br><b>Generación:</b> ",  fmt_num(Generacion),  " TWh"
    ),
    hoverinfo   = "text",
    name        = paste0(cont, " (sin Top ", N_TOP, ")"),
    legendgroup = cont,
    showlegend  = FALSE,
    visible     = FALSE
  )
}


titulo_base <- paste0(
  "<b style='font-family:Cinzel, Georgia, serif; color:#3E2416; ",
  "font-size:18px; letter-spacing:1px;'>",
  "PIB VS GENERACIÓN DE ELECTRICIDAD</b><br>"
)

subtitulo_full <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Todos los países | Tendencia lineal e IC del 95% | ",
  "Etiquetas: 10 mayores generadores</span>"
)

subtitulo_filt <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Sin los ", N_TOP, " mayores generadores | Tendencia lineal e IC del 95%",
  " | Etiquetas: 10 mayores del resto</span>"
)


fig <- fig %>% layout(

  title = list(
    text    = paste0(titulo_base, subtitulo_full),
    x       = 0.5, xanchor = "center",
    y       = 0.97
  ),

  xaxis = list(
    title         = paste0("<b>", ETIQ_X, "</b>"),
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    tickformat    = "$,.0s",
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  yaxis = list(
    title         = "<b>Generación de electricidad (TWh)</b>",
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  paper_bgcolor = "#FFFFFF",
  plot_bgcolor  = "#FBF3DD",

  font = list(
    family = "EB Garamond, Georgia, serif",
    color  = "#2B1810",
    size   = 12
  ),

  legend = list(
    title = list(
      text = paste0(
        "<b style='font-family:Cinzel, serif; color:#3E2416; ",
        "font-size:12px; letter-spacing:1px;'>❖ CONTINENTE</b>"
      )
    ),
    orientation = "v",
    x           = 1.02, xanchor = "left",
    y           = 1,    yanchor = "top",
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 2,
    font = list(
      family = "EB Garamond, Georgia, serif",
      size   = 12,
      color  = "#3E2416"
    ),
    itemsizing = "constant",
    traceorder = "normal"
  ),

  margin = list(t = 130, b = 200, l = 100, r = 190),

  annotations = ann_todas,

  updatemenus = list(
    list(
      type        = "buttons",
      direction   = "right",
      x           = 0.5,  xanchor = "center",
      y           = -0.32, yanchor = "top",
      showactive  = TRUE,
      bgcolor     = "#FBF3DD",
      bordercolor = "#D4A017",
      borderwidth = 1.5,
      pad         = list(r = 10, t = 5),
      font = list(
        size   = 12,
        family = "EB Garamond, Georgia, serif",
        color  = "#3E2416"
      ),
      buttons = list(

        list(
          label  = "📏 Lineal (todos)",
          method = "update",
          args   = list(
            list(visible = visible_full),
            c(
              list(
                "title.text"      = paste0(titulo_base, subtitulo_full),
                "xaxis.autorange" = TRUE,
                "yaxis.autorange" = TRUE
              ),
              relayout_full_ann
            )
          )
        ),

        list(
          label  = paste0("🚫 Sin Top ", N_TOP),
          method = "update",
          args   = list(
            list(visible = visible_filt),
            c(
              list(
                "title.text"      = paste0(titulo_base, subtitulo_filt),
                "xaxis.autorange" = TRUE,
                "yaxis.autorange" = TRUE
              ),
              relayout_filt_ann
            )
          )
        )
      )
    )
  )
) %>%
  config(
    responsive  = TRUE,
    displaylogo = FALSE,
    modeBarButtonsToRemove = list("lasso2d", "select2d"),
    toImageButtonOptions = list(
      format   = "png",
      filename = "dispersion_pib_generacion_2022",
      width    = 1600,
      height   = 900
    )
  )

fig

4.2.4 Acceso a electricidad

El acceso a electricidad corresponde al porcentaje de la población de cada país que cuenta con acceso a este servicio. En la Tabla 5 se presentan sus principales estadísticas descriptivas para los 140 países incluidos en la muestra, agrupados por continente.

Tabla_acceso <- Base_datos %>%
  group_by(Continente) %>%
  summarise(
    N = n(),
    Promedio = mean(Acceso),
    Desv_Estandar = sd(Acceso),
    Minimo = min(Acceso),
    Maximo = max(Acceso)
  )

kable(
  Tabla_acceso,
  format = "html",
  digits = 2,
  col.names = c(
    "Continente",
    "N",
    "Acceso promedio (%)",
    "Desv. Estándar",
    "Mínimo",
    "Máximo"
  ),
  caption = "Tabla 5: Estadísticas descriptivas del acceso a electricidad por continente"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = TRUE,
    position = "center"
  ) %>%
  kableExtra::row_spec(
    0,
    bold = TRUE,
    color = "#FBF3DD",
    background = "#3E2416"
  ) %>%
  kableExtra::row_spec(
    seq(2, nrow(Tabla_acceso), by = 2),
    background = "#F5E6C8"
  )
Tabla 5: Estadísticas descriptivas del acceso a electricidad por continente
Continente N Acceso promedio (%) Desv. Estándar Mínimo Máximo
Africa 35 62.18 24.92 11.7 100
Asia 41 98.40 4.73 73.7 100
Europe 39 100.00 0.00 100.0 100
North America 13 94.03 13.99 49.3 100
Oceania 2 100.00 0.00 100.0 100
South America 10 99.51 1.20 96.2 100

Los resultados muestran que el acceso a electricidad es elevado en gran parte de los países analizados. Europe y Oceania presentan un promedio del 100 %, seguidos de South America con 99,51 % y Asia con 98,40 %. En contraste, Africa registra el promedio más bajo con 62,18 % y también la mayor dispersión, con una desviación estándar de 24,92, lo que refleja diferencias importantes entre los países de este continente. North America también presenta cierta variabilidad, con valores que van desde 49,3 % hasta 100 %. En el diagrama de dispersión se observa que muchos países se concentran cerca del 100 % de acceso, pero presentan niveles de generación de electricidad muy diferentes entre sí. Por esta razón, un acceso similar a la electricidad no necesariamente se relaciona con niveles similares de generación.

Para facilitar la interpretación gráfica, se presentan dos versiones del diagrama de dispersión: una con los 140 países de la muestra y otra excluyendo únicamente de la visualización los 5 países con mayor generación de electricidad. Esto permite observar con mayor claridad la concentración de países cerca del 100 % de acceso y las diferencias en sus niveles de generación, evitando que los valores extremos compriman visualmente las demás observaciones. La exclusión se realizó solo con fines gráficos, por lo que estos países permanecen incluidos en la base y en el modelo de regresión.

library(plotly)
library(dplyr)


VAR_X    <- "Acceso"
ETIQ_X   <- "Acceso a electricidad (%)"
UNIDAD_X <- " %"

N_TOP <- 5


colores <- c(
  "Africa"        = "#A85834",
  "Asia"          = "#3E2416",
  "Europe"        = "#C9821B",
  "North America" = "#D4A017",
  "Oceania"       = "#6D4C2F",
  "South America" = "#E8C766"
)


datos_plot <- Base_datos %>%
  filter(
    !is.na(.data[[VAR_X]]), .data[[VAR_X]] >= 0,
    !is.na(Generacion),     Generacion > 0,
    !is.na(Continente)
  ) %>%
  mutate(
    Continente = factor(
      Continente,
      levels = c("Africa", "Asia", "Europe",
                 "North America", "Oceania", "South America")
    )
  )


top_n <- datos_plot %>%
  arrange(desc(Generacion)) %>%
  slice(1:N_TOP) %>%
  pull(Codigo)

datos_sin_top <- datos_plot %>% filter(!Codigo %in% top_n)


etiquetas_full <- datos_plot %>%
  arrange(desc(Generacion)) %>%
  slice(1:10)

etiquetas_filt <- datos_sin_top %>%
  arrange(desc(Generacion)) %>%
  slice(1:10)


formula_mod <- as.formula(paste0("Generacion ~ `", VAR_X, "`"))

modelo_full <- lm(formula_mod, data = datos_plot)
modelo_filt <- lm(formula_mod, data = datos_sin_top)

x_seq <- seq(min(datos_plot[[VAR_X]]),
             max(datos_plot[[VAR_X]]),
             length.out = 200)

pred_full <- predict(modelo_full, newdata = setNames(data.frame(x_seq), VAR_X),
                     interval = "confidence", level = 0.95)
pred_filt <- predict(modelo_filt, newdata = setNames(data.frame(x_seq), VAR_X),
                     interval = "confidence", level = 0.95)

continentes <- levels(datos_plot$Continente)
n_cont      <- length(continentes)


fmt_num <- function(x, dec = 2) {
  format(round(x, dec),
         big.mark = ".", decimal.mark = ",",
         scientific = FALSE, trim = TRUE)
}


ann_full <- lapply(seq_len(nrow(etiquetas_full)), function(i) {
  list(
    x           = etiquetas_full[[VAR_X]][i],
    y           = etiquetas_full$Generacion[i],
    xref        = "x", yref = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#2E1A0F;'>",
      etiquetas_full$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 22, yshift = 10,
    font        = list(size = 11),
    visible     = TRUE
  )
})

ann_filt <- lapply(seq_len(nrow(etiquetas_filt)), function(i) {
  list(
    x           = etiquetas_filt[[VAR_X]][i],
    y           = etiquetas_filt$Generacion[i],
    xref        = "x", yref = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#7A2E1A;'>",
      etiquetas_filt$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#A85834",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 22, yshift = 10,
    font        = list(size = 11),
    visible     = FALSE
  )
})

ann_todas <- c(ann_full, ann_filt)
n_full    <- length(ann_full)
n_filt    <- length(ann_filt)


visible_full <- c(
  TRUE,  TRUE,
  FALSE, FALSE,
  rep(TRUE,  n_cont),
  rep(FALSE, n_cont)
)

visible_filt <- c(
  FALSE, FALSE,
  TRUE,  TRUE,
  rep(FALSE, n_cont),
  rep(TRUE,  n_cont)
)


idx_full <- 0:(n_full - 1)
idx_filt <- n_full:(n_full + n_filt - 1)

relayout_full_ann <- setNames(
  as.list(c(rep(TRUE, n_full), rep(FALSE, n_filt))),
  paste0("annotations[", c(idx_full, idx_filt), "].visible")
)

relayout_filt_ann <- setNames(
  as.list(c(rep(FALSE, n_full), rep(TRUE, n_filt))),
  paste0("annotations[", c(idx_full, idx_filt), "].visible")
)


fig <- plot_ly()


fig <- fig %>% add_ribbons(
  x = x_seq, ymin = pred_full[, "lwr"], ymax = pred_full[, "upr"],
  fillcolor = "#D4A017", opacity = 0.18,
  line = list(width = 0),
  name = "IC 95% (todos)",
  hoverinfo = "skip",
  showlegend = TRUE
)


fig <- fig %>% add_lines(
  x = x_seq, y = pred_full[, "fit"],
  line = list(color = "#3E2416", width = 3),
  name = "Tendencia (todos)",
  hoverinfo = "skip",
  showlegend = TRUE
)


fig <- fig %>% add_ribbons(
  x = x_seq, ymin = pred_filt[, "lwr"], ymax = pred_filt[, "upr"],
  fillcolor = "#A85834", opacity = 0.15,
  line = list(width = 0),
  name = paste0("IC 95% (sin Top ", N_TOP, ")"),
  hoverinfo = "skip",
  showlegend = TRUE,
  visible = FALSE
)


fig <- fig %>% add_lines(
  x = x_seq, y = pred_filt[, "fit"],
  line = list(color = "#A85834", width = 3),
  name = paste0("Tendencia (sin Top ", N_TOP, ")"),
  hoverinfo = "skip",
  showlegend = TRUE,
  visible = FALSE
)


for (cont in continentes) {
  sub <- datos_plot %>% filter(Continente == cont)

  fig <- fig %>% add_markers(
    data = sub,
    x = as.formula(paste0("~`", VAR_X, "`")),
    y = ~Generacion,
    marker = list(
      size = 10, opacity = 0.85,
      color = colores[cont],
      line = list(color = "#FBF3DD", width = 0.9)
    ),
    text = ~paste0(
      "<b style='color:#3E2416; font-size:13px;'>", Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>", ETIQ_X, ":</b> ", fmt_num(.data[[VAR_X]], 2), UNIDAD_X,
      "<br><b>Generación:</b> ",  fmt_num(Generacion),  " TWh"
    ),
    hoverinfo   = "text",
    name        = cont,
    legendgroup = cont,
    showlegend  = TRUE
  )
}


for (cont in continentes) {
  sub <- datos_sin_top %>% filter(Continente == cont)

  fig <- fig %>% add_markers(
    data = sub,
    x = as.formula(paste0("~`", VAR_X, "`")),
    y = ~Generacion,
    marker = list(
      size = 10, opacity = 0.85,
      color = colores[cont],
      line = list(color = "#FBF3DD", width = 0.9)
    ),
    text = ~paste0(
      "<b style='color:#3E2416; font-size:13px;'>", Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>", ETIQ_X, ":</b> ", fmt_num(.data[[VAR_X]], 2), UNIDAD_X,
      "<br><b>Generación:</b> ",  fmt_num(Generacion),  " TWh"
    ),
    hoverinfo   = "text",
    name        = paste0(cont, " (sin Top ", N_TOP, ")"),
    legendgroup = cont,
    showlegend  = FALSE,
    visible     = FALSE
  )
}


titulo_base <- paste0(
  "<b style='font-family:Cinzel, Georgia, serif; color:#3E2416; ",
  "font-size:18px; letter-spacing:1px;'>",
  "ACCESO A ELECTRICIDAD VS GENERACIÓN DE ELECTRICIDAD</b><br>"
)

subtitulo_full <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Todos los países | Tendencia lineal e IC del 95% | ",
  "Etiquetas: 10 mayores generadores</span>"
)

subtitulo_filt <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Sin los ", N_TOP, " mayores generadores | Tendencia lineal e IC del 95%",
  " | Etiquetas: 10 mayores del resto</span>"
)


fig <- fig %>% layout(

  title = list(
    text    = paste0(titulo_base, subtitulo_full),
    x       = 0.5, xanchor = "center",
    y       = 0.97
  ),

  xaxis = list(
    title         = paste0("<b>", ETIQ_X, "</b>"),
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    ticksuffix    = "%",
    range         = c(0, 105),
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  yaxis = list(
    title         = "<b>Generación de electricidad (TWh)</b>",
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  paper_bgcolor = "#FFFFFF",
  plot_bgcolor  = "#FBF3DD",

  font = list(
    family = "EB Garamond, Georgia, serif",
    color  = "#2B1810",
    size   = 12
  ),

  legend = list(
    title = list(
      text = paste0(
        "<b style='font-family:Cinzel, serif; color:#3E2416; ",
        "font-size:12px; letter-spacing:1px;'>❖ CONTINENTE</b>"
      )
    ),
    orientation = "v",
    x           = 1.02, xanchor = "left",
    y           = 1,    yanchor = "top",
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 2,
    font = list(
      family = "EB Garamond, Georgia, serif",
      size   = 12,
      color  = "#3E2416"
    ),
    itemsizing = "constant",
    traceorder = "normal"
  ),

  margin = list(t = 130, b = 200, l = 100, r = 190),

  annotations = ann_todas,

  updatemenus = list(
    list(
      type        = "buttons",
      direction   = "right",
      x           = 0.5,  xanchor = "center",
      y           = -0.32, yanchor = "top",
      showactive  = TRUE,
      bgcolor     = "#FBF3DD",
      bordercolor = "#D4A017",
      borderwidth = 1.5,
      pad         = list(r = 10, t = 5),
      font = list(
        size   = 12,
        family = "EB Garamond, Georgia, serif",
        color  = "#3E2416"
      ),
      buttons = list(

        list(
          label  = "📏 Lineal (todos)",
          method = "update",
          args   = list(
            list(visible = visible_full),
            c(
              list(
                "title.text"      = paste0(titulo_base, subtitulo_full),
                "xaxis.autorange" = FALSE,
                "yaxis.autorange" = TRUE
              ),
              relayout_full_ann
            )
          )
        ),

        list(
          label  = paste0("🚫 Sin Top ", N_TOP),
          method = "update",
          args   = list(
            list(visible = visible_filt),
            c(
              list(
                "title.text"      = paste0(titulo_base, subtitulo_filt),
                "xaxis.autorange" = FALSE,
                "yaxis.autorange" = TRUE
              ),
              relayout_filt_ann
            )
          )
        )
      )
    )
  )
) %>%
  config(
    responsive  = TRUE,
    displaylogo = FALSE,
    modeBarButtonsToRemove = list("lasso2d", "select2d"),
    toImageButtonOptions = list(
      format   = "png",
      filename = "dispersion_acceso_generacion_2022",
      width    = 1600,
      height   = 900
    )
  )

fig

4.3 Variable categórica: Distribución de Frecuencias

4.3.1 Continente

La variable continente permite clasificar los países de la muestra según su ubicación geográfica. En la Tabla 6 se presenta la distribución de frecuencias y porcentajes de los 140 países incluidos en el estudio.

Tabla_continente <- Base_datos %>%
  count(Continente) %>%
  arrange(desc(n)) %>%
  mutate(
    Porcentaje = n / sum(n) * 100,
    Porcentaje_Acumulado = cumsum(Porcentaje)
  ) %>%
  rename(
    Frecuencia = n
  )



knitr::kable(
  Tabla_continente,
  format = "html",
  digits = 1,
  col.names = c(
    "Continente",
    "Frecuencia",
    "Porcentaje (%)",
    "Porcentaje Acumulado (%)"
  ),
  caption = "Tabla 6: Distribución de frecuencias de los países según continente"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = TRUE,
    position = "center"
  ) %>%
  kableExtra::row_spec(
    0,
    bold = TRUE,
    color = "#FBF3DD",
    background = "#3E2416"
  ) %>%
  kableExtra::row_spec(
    seq(2, nrow(Tabla_continente), by = 2),
    background = "#F5E6C8"
  )
Tabla 6: Distribución de frecuencias de los países según continente
Continente Frecuencia Porcentaje (%) Porcentaje Acumulado (%)
Asia 41 29.3 29.3
Europe 39 27.9 57.1
Africa 35 25.0 82.1
North America 13 9.3 91.4
South America 10 7.1 98.6
Oceania 2 1.4 100.0

La muestra está conformada principalmente por países de Asia, con 41 observaciones (29,3 %), seguida de Europe con 39 (27,9 %) y Africa con 35 (25,0 %). En menor proporción se encuentran North America con 13 países (9,3 %), South America con 10 (7,1 %) y Oceania con solo 2 (1,4 %). Al observar la distribución de la generación de electricidad por continente, se evidencian diferencias importantes entre los países de cada grupo, con una mayor dispersión y presencia de valores elevados especialmente en Asia y North America. También se observa que el número de países no es igual entre continentes, por lo que los resultados de grupos con pocas observaciones, particularmente Oceania, deben interpretarse con cautela.

library(plotly)
library(dplyr)


colores_continente <- c(
  "Africa"        = "#A85834",
  "Asia"          = "#3E2416",
  "Europe"        = "#C9821B",
  "North America" = "#D4A017",
  "Oceania"       = "#6D4C2F",
  "South America" = "#E8C766"
)


datos_box <- Base_datos %>%
  filter(
    !is.na(Generacion), Generacion > 0,
    !is.na(Continente)
  ) %>%
  mutate(
    Continente = factor(
      Continente,
      levels = c("Africa", "Asia", "Europe",
                 "North America", "Oceania", "South America")
    )
  )

continentes <- levels(datos_box$Continente)
n_cont      <- length(continentes)


top5 <- datos_box %>%
  arrange(desc(Generacion)) %>%
  slice(1:5)


fmt_num <- function(x, dec = 2) {
  format(round(x, dec),
         big.mark = ".", decimal.mark = ",",
         scientific = FALSE, trim = TRUE)
}


fig <- plot_ly()

for (cont in continentes) {
  sub <- datos_box %>% filter(Continente == cont)

  fig <- fig %>% add_boxplot(
    data       = sub,
    x          = ~Continente,
    y          = ~Generacion,
    name       = cont,
    legendgroup = cont,
    boxpoints  = "outliers",
    fillcolor  = paste0(colores_continente[cont], "55"),
    line       = list(color = colores_continente[cont], width = 2),
    marker     = list(
      color   = colores_continente[cont],
      size    = 8,
      opacity = 0.90,
      line    = list(color = "#FBF3DD", width = 1)
    ),
    text = ~paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#2E1A0F; font-size:13px;'>",
      Codigo, "</b>",
      "<br><b>Continente:</b> ",  as.character(Continente),
      "<br><b>Generación:</b> ",  fmt_num(Generacion), " TWh"
    ),
    hoverinfo  = "text",
    boxmean    = FALSE,
    showlegend = TRUE
  )
}


ann_top5 <- lapply(seq_len(nrow(top5)), function(i) {
  list(
    x           = as.character(top5$Continente[i]),
    y           = top5$Generacion[i],
    xref        = "x", yref = "y",
    text        = paste0(
      "<b style='font-family:Cinzel, Georgia, serif; color:#2E1A0F;'>",
      top5$Codigo[i], "</b>"
    ),
    showarrow   = FALSE,
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 1.2,
    borderpad   = 3,
    xshift      = 35, yshift = 12,
    font        = list(size = 11),
    visible     = TRUE
  )
})


titulo_base <- paste0(
  "<b style='font-family:Cinzel, Georgia, serif; color:#3E2416; ",
  "font-size:18px; letter-spacing:1px;'>",
  "DISTRIBUCIÓN DE LA GENERACIÓN DE ELECTRICIDAD POR CONTINENTE</b><br>"
)

subtitulo_lin <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Escala lineal | Año 2022 | Etiquetas: 5 mayores generadores",
  " | Pasa el cursor para detalles</span>"
)

subtitulo_log <- paste0(
  "<span style='font-size:12px; color:#8B5E34; font-style:italic;'>",
  "Escala logarítmica (mejor visualización) | Año 2022",
  " | Etiquetas: 5 mayores generadores</span>"
)


fig <- fig %>% layout(

  title = list(
    text    = paste0(titulo_base, subtitulo_lin),
    x       = 0.5, xanchor = "center",
    y       = 0.97
  ),

  xaxis = list(
    title         = "<b>Continente</b>",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 12, color = "#2B1810"),
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1,
    categoryorder = "array",
    categoryarray = continentes
  ),

  yaxis = list(
    title         = "<b>Generación de electricidad (TWh)</b>",
    type          = "linear",
    gridcolor     = "#E7D3A8",
    zerolinecolor = "#E7D3A8",
    tickfont      = list(size = 11, color = "#2B1810"),
    showline      = TRUE,
    linecolor     = "#D4A017",
    linewidth     = 1
  ),

  paper_bgcolor = "#FFFFFF",
  plot_bgcolor  = "#FBF3DD",

  font = list(
    family = "EB Garamond, Georgia, serif",
    color  = "#2B1810",
    size   = 12
  ),

  legend = list(
    title = list(
      text = paste0(
        "<b style='font-family:Cinzel, serif; color:#3E2416; ",
        "font-size:12px; letter-spacing:1px;'>❖ CONTINENTE</b>"
      )
    ),
    orientation = "v",
    x           = 1.02, xanchor = "left",
    y           = 1,    yanchor = "top",
    bgcolor     = "rgba(251, 243, 221, 0.95)",
    bordercolor = "#D4A017",
    borderwidth = 2,
    font = list(
      family = "EB Garamond, Georgia, serif",
      size   = 12,
      color  = "#3E2416"
    ),
    itemsizing = "constant",
    traceorder = "normal"
  ),

  margin = list(t = 130, b = 180, l = 90, r = 190),

  annotations = ann_top5,

  updatemenus = list(
    list(
      type        = "buttons",
      direction   = "right",
      x           = 0.5,  xanchor = "center",
      y           = -0.22, yanchor = "top",
      showactive  = TRUE,
      bgcolor     = "#FBF3DD",
      bordercolor = "#D4A017",
      borderwidth = 1.5,
      pad         = list(r = 10, t = 5),
      font = list(
        size   = 12,
        family = "EB Garamond, Georgia, serif",
        color  = "#3E2416"
      ),
      buttons = list(
        list(
          label  = "📏 Escala lineal",
          method = "relayout",
          args   = list(list(
            "title.text"      = paste0(titulo_base, subtitulo_lin),
            "yaxis.type"      = "linear",
            "yaxis.autorange" = TRUE
          ))
        ),
        list(
          label  = "📐 Escala logarítmica",
          method = "relayout",
          args   = list(list(
            "title.text"      = paste0(titulo_base, subtitulo_log),
            "yaxis.type"      = "log",
            "yaxis.autorange" = TRUE
          ))
        )
      )
    )
  )
) %>%
  config(
    responsive  = TRUE,
    displaylogo = FALSE,
    modeBarButtonsToRemove = list("lasso2d", "select2d"),
    toImageButtonOptions = list(
      format   = "png",
      filename = "boxplot_generacion_continente_2022",
      width    = 1600,
      height   = 900
    )
  )

fig

5 Estimación del modelo de regresión multiple

library(broom)
library(dplyr)
library(kableExtra)

Modelo_final <- lm(
  Generacion ~ Poblacion + PIB + Consumo + Acceso + Continente,
  data = Base_datos
)

resumen_mod <- broom::tidy(Modelo_final) %>%
  mutate(across(where(is.numeric), ~ round(., 5))) %>%
  rename(
    `Variable` = term,
    `Coeficiente` = estimate,
    `Error Estándar` = std.error,
    `Estadístico t` = statistic,
    `Valor p` = p.value
  ) %>%
  mutate(
    Significancia = case_when(
      `Valor p` < 0.001 ~ "***",
      `Valor p` < 0.01  ~ "**",
      `Valor p` < 0.05  ~ "*",
      `Valor p` < 0.1   ~ ".",
      TRUE ~ ""
    ),
    `Valor p formateado` = case_when(
      is.na(`Valor p`) ~ "NA",
      `Valor p` < 0.0001 ~ "< 0.0001",
      TRUE ~ sprintf("%.4f", `Valor p`)
    )
  )

resumen_global <- broom::glance(Modelo_final)

R2 <- round(resumen_global$adj.r.squared, 4)
Fstat <- round(resumen_global$statistic, 2)

pvalor_modelo <- ifelse(
  resumen_global$p.value < 0.0001,
  "< 0.0001",
  sprintf("%.4f", resumen_global$p.value)
)

N <- nobs(Modelo_final)

filas_resumen <- tibble(
  Variable = c("R² ajustado", "F", "Valor p (modelo)", "N"),
  Coeficiente = as.character(c(R2, Fstat, pvalor_modelo, N)),
  `Error Estándar` = "",
  `Estadístico t` = "",
  `Valor p formateado` = "",
  Significancia = ""
)

tabla_principal <- resumen_mod %>%
  select(
    Variable,
    Coeficiente,
    `Error Estándar`,
    `Estadístico t`,
    `Valor p formateado`,
    Significancia
  ) %>%
  mutate_all(as.character)

tabla_final <- bind_rows(tabla_principal, filas_resumen)

names(tabla_final) <- c(
  "Variable",
  "Coeficiente",
  "Error Estándar",
  "Estadístico t",
  "Valor p",
  "Sig."
)

kbl(
  tabla_final,
  caption = "Tabla 7: Resultados del modelo de regresión lineal múltiple",
  align = c("l", "r", "r", "r", "r", "c")
) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE,
    font_size = 14,
    position = "center"
  ) %>%
  row_spec(
    0,
    background = "#3E2416",
    color = "#FBF3DD",
    bold = TRUE
  ) %>%
  column_spec(
    1,
    bold = TRUE,
    width = "4cm"
  ) %>%
  column_spec(
    2:6,
    width = "2.5cm"
  ) %>%
  row_spec(
    (nrow(tabla_principal) + 1):nrow(tabla_final),
    bold = TRUE,
    background = "#F0DFA8",
    color = "#2B1810"
  ) %>%
  footnote(
    general = "Elaboración propia con base en Our World in Data, 2022.",
    general_title = "Nota:",
    footnote_as_chunk = TRUE
  )
Tabla 7: Resultados del modelo de regresión lineal múltiple
Variable Coeficiente Error Estándar Estadístico t Valor p Sig.
(Intercept) 1.79718 105.22413 0.01708 0.9864
Poblacion 0 0 1.16954 0.2443
PIB 0 0 21.16211 < 0.0001 ***
Consumo 0.00277 0.00554 0.49987 0.6180
Acceso -0.68043 1.56169 -0.4357 0.6638
ContinenteAsia 1.96096 80.95144 0.02422 0.9807
ContinenteEurope -39.26934 83.50788 -0.47025 0.6390
ContinenteNorth America -65.99239 93.84946 -0.70317 0.4832
ContinenteOceania -6.87202 188.20229 -0.03651 0.9709
ContinenteSouth America -9.03019 103.91658 -0.0869 0.9309
R² ajustado 0.9192
F 176.75
Valor p (modelo) < 0.0001
N 140
Nota: Elaboración propia con base en Our World in Data, 2022.

El intercepto del modelo es 1,797 TWh y presenta un valor p de 0,9864, por lo que no es estadísticamente significativo. Este valor representa la generación esperada cuando las variables cuantitativas toman el valor de cero y el país pertenece al continente de referencia. Sin embargo, estas condiciones no representan un escenario realista para los países analizados, por lo que el intercepto tiene principalmente una función matemática dentro del modelo.

En cuanto a la población, el coeficiente aparece como cero debido a la escala en la que está medida la variable, ya que se encuentra expresada en número de habitantes. Su valor p es 0,2443, por lo que no presenta una asociación estadísticamente significativa con la generación de electricidad una vez se mantienen constantes las demás variables del modelo. Esto no significa que la población no tenga relación con la generación, sino que su efecto individual no resulta significativo al analizarla conjuntamente con los demás factores.

El PIB total es la única variable cuantitativa que presenta una asociación estadísticamente significativa con la generación de electricidad (p < 0,0001). Aunque su coeficiente aparece como cero en la tabla debido a que el PIB está expresado en dólares y, por tanto, el efecto de un solo dólar es muy pequeño, el estadístico t de 21,16 muestra una relación positiva y claramente significativa. En otras palabras, manteniendo constantes las demás variables, los países con un PIB total mayor tienden a presentar una mayor generación de electricidad.

Para el consumo de electricidad per cápita, el coeficiente estimado es 0,00277, lo que indica una asociación positiva con la generación. Sin embargo, esta relación no es estadísticamente significativa (p = 0,6180) después de controlar por las demás variables. De forma similar, el acceso a electricidad presenta un coeficiente de −0,68043 y un valor p de 0,6638, por lo que tampoco se encuentra evidencia suficiente de una asociación estadísticamente significativa dentro del modelo.

Para la variable continente, Africa funciona como categoría de referencia. Frente a ella, Asia presenta una diferencia estimada de 1,96 TWh, Europe de −39,27 TWh, North America de −65,99 TWh, Oceania de −6,87 TWh y South America de −9,03 TWh, manteniendo constantes las demás variables. Sin embargo, ninguna de estas diferencias es estadísticamente significativa, ya que todos sus valores p son superiores a 0,05. Por lo tanto, con esta muestra y una vez considerados simultáneamente los demás factores, no se encuentra evidencia suficiente para afirmar que la generación difiera por continente respecto a Africa.

Finalmente, el modelo presenta un R² ajustado de 0,9192, lo que indica que aproximadamente el 91,92 % de la variabilidad observada en la generación de electricidad entre los países de la muestra es explicada conjuntamente por las variables incluidas. Además, el estadístico F es 176,75 y el valor p global es menor a 0,0001, lo que indica que el modelo, considerado en conjunto, es estadísticamente significativo. Estos resultados muestran una alta capacidad explicativa del modelo para los 140 países analizados, aunque posteriormente es necesario revisar los supuestos y diagnósticos de la regresión antes de establecer las conclusiones finales.

6 Resultados del modelo

6.1 Diagnóstico gráfico de supuestos

Para evaluar la validez del modelo de regresión lineal múltiple se realizó un diagnóstico gráfico de sus principales supuestos. Este análisis permite revisar el comportamiento de los residuos y detectar posibles problemas relacionados con la linealidad, normalidad y homocedasticidad, así como la presencia de observaciones que puedan afectar el ajuste del modelo. Cada uno de estos aspectos se analiza a continuación mediante los gráficos correspondientes.

6.1.1 Lineal

El supuesto de linealidad se evaluó mediante el gráfico de residuos frente a los valores ajustados. En este caso, los residuos no se distribuyen de manera completamente aleatoria alrededor de cero, ya que la línea de tendencia presenta una curvatura marcada, especialmente a medida que aumentan los valores ajustados de generación. Además, se observan algunas observaciones alejadas del resto, principalmente en los niveles más altos de generación. Este comportamiento sugiere que el supuesto de linealidad no se cumple completamente y que el modelo lineal puede tener dificultades para representar adecuadamente la relación en los países con niveles de generación más elevados. Este resultado se tendrá en cuenta junto con los demás diagnósticos antes de establecer las conclusiones finales del modelo.

res_df <- broom::augment(Modelo_final)


resid_vs_ajustados <- ggplot(
  res_df,
  aes(x = .fitted, y = .resid)
) +
  
  geom_point(
    aes(
      color = abs(.resid),
      size = abs(.resid)
    ),
    alpha = 0.6,
    show.legend = FALSE
  ) +
  
  
  geom_hline(
    yintercept = 0,
    color = "#A85834",
    linetype = "dashed",
    linewidth = 1.2,
    alpha = 0.8
  ) +
  
  
  geom_smooth(
    method = "loess",
    color = "#3E2416",
    fill = "#D4A017",
    alpha = 0.20,
    linewidth = 1.2,
    se = TRUE
  ) +
  
  scale_color_gradient(
    low = "#E8C766",
    high = "#A85834"
  ) +
  
  scale_size_continuous(
    range = c(2, 6)
  ) +
  
  labs(
    title = "ANÁLISIS DE RESIDUOS VS VALORES AJUSTADOS",
    subtitle = "Validación de los supuestos de linealidad y homocedasticidad",
    x = "Valores ajustados de generación (TWh)",
    y = "Residuos",
    caption = paste(
      "Fuente: Elaboración propia con base en Our World in Data, 2022 |",
      "Línea chocolate: tendencia LOESS |",
      "Línea terracota: residuo cero"
    )
  ) +
  
  theme_minimal() +
  
  theme(
    text = element_text(
      family = "sans",
      color = "#2B1810"
    ),
    
    plot.title = element_text(
      face = "bold",
      size = 16,
      hjust = 0.5,
      color = "#3E2416",
      margin = margin(b = 10)
    ),
    
    plot.subtitle = element_text(
      size = 12,
      hjust = 0.5,
      color = "#8B5E34",
      margin = margin(b = 20)
    ),
    
    plot.caption = element_text(
      size = 10,
      color = "#6D4C2F",
      hjust = 0.5,
      margin = margin(t = 15)
    ),
    
    axis.title = element_text(
      face = "bold",
      size = 12,
      color = "#2B1810"
    ),
    
    axis.text = element_text(
      size = 10,
      color = "#2B1810"
    ),
    
    panel.grid.major = element_line(
      color = "#E7D3A8"
    ),
    
    panel.grid.minor = element_line(
      color = "#F0DFA8"
    ),
    
    plot.background = element_rect(
      fill = "white",
      color = NA
    ),
    
    panel.background = element_rect(
      fill = "#FBF3DD",
      color = NA
    )
  )

print(resid_vs_ajustados)

6.1.2 Normalidad

La normalidad de los residuos se evaluó mediante el gráfico Q-Q, comparando los cuantiles observados de los residuos con los esperados bajo una distribución normal. Cuando los puntos se mantienen próximos a la línea de referencia, se considera que los residuos presentan un comportamiento cercano a la normalidad.

res_df <- broom::augment(Modelo_final)


G_qq <- ggplot(
  res_df,
  aes(sample = .resid)
) +
  
  
  geom_qq(
    alpha = 0.65,
    color = "#B8892E",
    size = 2
  ) +
  
  
  geom_qq_line(
    color = "#3E2416",
    linewidth = 1.2
  ) +
  
  
  labs(
    title = "GRÁFICO Q-Q DE LOS RESIDUOS",
    subtitle = "Validación de normalidad - Residuos vs distribución normal teórica",
    x = "Cuantiles teóricos",
    y = "Cuantiles de los residuos",
    caption = "Fuente: Elaboración propia con base en Our World in Data, 2022"
  ) +
  
  
  theme_minimal() +
  
  theme(
    text = element_text(
      family = "sans",
      color = "#2B1810"
    ),
    
    plot.title = element_text(
      face = "bold",
      size = 16,
      hjust = 0.5,
      color = "#3E2416",
      margin = margin(b = 10)
    ),
    
    plot.subtitle = element_text(
      size = 12,
      hjust = 0.5,
      color = "#8B5E34",
      margin = margin(b = 20)
    ),
    
    plot.caption = element_text(
      size = 10,
      color = "#6D4C2F",
      hjust = 0.5,
      margin = margin(t = 15)
    ),
    
    axis.title = element_text(
      face = "bold",
      size = 12,
      color = "#2B1810"
    ),
    
    axis.text = element_text(
      size = 10,
      color = "#2B1810"
    ),
    
    panel.grid.major = element_line(
      color = "#E7D3A8"
    ),
    
    panel.grid.minor = element_line(
      color = "#F0DFA8"
    ),
    
    plot.background = element_rect(
      fill = "white",
      color = NA
    ),
    
    panel.background = element_rect(
      fill = "#FBF3DD",
      color = NA
    )
  )

print(G_qq)

El gráfico muestra que los residuos se ajustan razonablemente a la línea de referencia en la parte central de la distribución. Sin embargo, hacia ambos extremos los puntos comienzan a separarse de manera considerable, con algunas observaciones especialmente alejadas de la línea. La desviación es particularmente evidente en la cola superior, donde aparece un residuo mucho mayor que el resto. Por lo tanto, el supuesto de normalidad no se cumple completamente, principalmente por la presencia de residuos extremos. Este comportamiento es coherente con la alta dispersión observada previamente en la generación de electricidad entre los países y deberá tenerse en cuenta al interpretar los resultados del modelo.

6.1.3 Homocedasticidad

El supuesto de homocedasticidad se evaluó mediante el gráfico Scale-Location, que permite observar si la dispersión de los residuos se mantiene aproximadamente constante a lo largo de los valores ajustados. Una tendencia relativamente horizontal indicaría una varianza estable, mientras que cambios marcados en la dispersión pueden evidenciar problemas de heterocedasticidad.

res_df <- broom::augment(Modelo_final)


res_df <- res_df %>%
  mutate(
    sqrt_resid_std = sqrt(abs(.std.resid))
  )


media_scale <- mean(
  res_df$sqrt_resid_std,
  na.rm = TRUE
)


G_scale <- ggplot(
  res_df,
  aes(
    x = .fitted,
    y = sqrt_resid_std
  )
) +
  
  
  geom_point(
    aes(
      color = sqrt_resid_std,
      size = sqrt_resid_std
    ),
    alpha = 0.65,
    show.legend = FALSE
  ) +
  
  
  geom_hline(
    yintercept = media_scale,
    color = "#A85834",
    linetype = "dashed",
    linewidth = 1.2,
    alpha = 0.8
  ) +
  
 
  geom_smooth(
    method = "loess",
    color = "#3E2416",
    fill = "#D4A017",
    alpha = 0.20,
    linewidth = 1.2,
    se = TRUE
  ) +
  
  
  scale_color_gradient(
    low = "#E8C766",
    high = "#A85834"
  ) +
  
  scale_size_continuous(
    range = c(2, 6)
  ) +
  
  
  labs(
    title = "GRÁFICO SCALE-LOCATION - VERIFICACIÓN DE HOMOCEDASTICIDAD",
    subtitle = "Raíz de los residuos estandarizados vs valores ajustados",
    x = "Valores ajustados de generación (TWh)",
    y = expression(sqrt("|Residuos estandarizados|")),
    caption = paste(
      "Fuente: Elaboración propia con base en Our World in Data, 2022 |",
      "Línea terracota: media |",
      "Línea chocolate: tendencia LOESS"
    )
  ) +
  
  
  theme_minimal() +
  
  theme(
    text = element_text(
      family = "sans",
      color = "#2B1810"
    ),
    
    plot.title = element_text(
      face = "bold",
      size = 16,
      hjust = 0.5,
      color = "#3E2416",
      margin = margin(b = 10)
    ),
    
    plot.subtitle = element_text(
      size = 12,
      hjust = 0.5,
      color = "#8B5E34",
      margin = margin(b = 20)
    ),
    
    plot.caption = element_text(
      size = 10,
      color = "#6D4C2F",
      hjust = 0.5,
      margin = margin(t = 15)
    ),
    
    axis.title = element_text(
      face = "bold",
      size = 12,
      color = "#2B1810"
    ),
    
    axis.text = element_text(
      size = 10,
      color = "#2B1810"
    ),
    
    panel.grid.major = element_line(
      color = "#E7D3A8"
    ),
    
    panel.grid.minor = element_line(
      color = "#F0DFA8"
    ),
    
    plot.background = element_rect(
      fill = "white",
      color = NA
    ),
    
    panel.background = element_rect(
      fill = "#FBF3DD",
      color = NA
    )
  )

print(G_scale)

En el gráfico se observa que la dispersión de los residuos no permanece constante a medida que aumentan los valores ajustados de generación. La línea de tendencia presenta un crecimiento marcado y alcanza sus valores más altos en los países con mayores niveles de generación estimada. Además, algunas observaciones se encuentran considerablemente alejadas del grupo principal. Este comportamiento indica la presencia de heterocedasticidad, por lo que el supuesto de varianza constante de los errores no se cumple adecuadamente. Esto sugiere que la precisión del modelo no es uniforme para todos los países, especialmente en aquellos con niveles de generación más elevados.

6.1.4 VIF

La multicolinealidad entre las variables explicativas se evaluó mediante el Factor de Inflación de la Varianza (VIF). Debido a que el modelo incluye Continente, una variable categórica con varios niveles, se utilizó el GVIF ajustado para facilitar la comparación entre los términos del modelo. Valores elevados indicarían que algunas variables comparten demasiada información entre sí, lo que podría reducir la precisión de los coeficientes estimados.

library(car)
library(dplyr)
library(kableExtra)


Base_datos$Continente <- factor(Base_datos$Continente)


vif_resultados <- car::vif(Modelo_final)


if (is.matrix(vif_resultados)) {
  
  tabla_vif <- data.frame(
    Variable = rownames(vif_resultados),
    GVIF = vif_resultados[, "GVIF"],
    Df = vif_resultados[, "Df"],
    `GVIF ajustado` = vif_resultados[, "GVIF^(1/(2*Df))"],
    row.names = NULL,
    check.names = FALSE
  ) %>%
    mutate(
      GVIF = round(GVIF, 3),
      `GVIF ajustado` = round(`GVIF ajustado`, 3),
      Diagnóstico = case_when(
        `GVIF ajustado` < sqrt(5) ~ "ACEPTABLE",
        `GVIF ajustado` < sqrt(10) ~ "REVISAR",
        TRUE ~ "ALTO"
      )
    ) %>%
    arrange(desc(`GVIF ajustado`))
  
} else {
  
  tabla_vif <- data.frame(
    Variable = names(vif_resultados),
    VIF = as.numeric(vif_resultados),
    row.names = NULL
  ) %>%
    mutate(
      VIF = round(VIF, 3),
      Tolerancia = round(1 / VIF, 4),
      Diagnóstico = case_when(
        VIF < 5 ~ "ACEPTABLE",
        VIF < 10 ~ "REVISAR",
        TRUE ~ "ALTO"
      )
    ) %>%
    arrange(desc(VIF))
}


kbl(
  tabla_vif,
  format = "html",
  caption = "Tabla 8: Análisis de multicolinealidad mediante VIF/GVIF",
  align = "c"
) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE,
    font_size = 14,
    position = "center"
  ) %>%
  row_spec(
    0,
    background = "#3E2416",
    color = "#FBF3DD",
    bold = TRUE
  ) %>%
  column_spec(
    1,
    bold = TRUE,
    width = "4cm"
  ) %>%
  row_spec(
    seq(2, nrow(tabla_vif), by = 2),
    background = "#F5E6C8"
  ) %>%
  footnote(
    general = paste(
      "Elaboración propia con base en Our World in Data, 2022.",
      "Para términos con varios grados de libertad se reporta el GVIF ajustado."
    ),
    general_title = "Nota:",
    footnote_as_chunk = TRUE
  )
Tabla 8: Análisis de multicolinealidad mediante VIF/GVIF
Variable GVIF Df GVIF ajustado Diagnóstico
PIB 3.261 1 1.806 ACEPTABLE
Poblacion 3.230 1 1.797 ACEPTABLE
Acceso 2.498 1 1.580 ACEPTABLE
Consumo 1.481 1 1.217 ACEPTABLE
Continente 3.036 5 1.117 ACEPTABLE
Nota: Elaboración propia con base en Our World in Data, 2022. Para términos con varios grados de libertad se reporta el GVIF ajustado.

Los resultados muestran que todas las variables presentan valores de GVIF ajustado dentro de rangos aceptables, por lo que no se evidencian problemas importantes de multicolinealidad en el modelo. Los valores más altos corresponden al PIB (1,806) y la Población (1,797), aunque ambos se mantienen en niveles adecuados. Por su parte, Acceso presenta un valor de 1,580, Consumo de 1,217 y Continente de 1,117. En conjunto, estos resultados indican que, aunque existe cierta relación entre algunas de las variables explicativas, esta no alcanza niveles que representen un problema relevante para la estimación del modelo. Por lo tanto, el supuesto relacionado con la ausencia de multicolinealidad importante se considera satisfecho.

7 Conclusiones

El análisis permitió responder a la pregunta de investigación sobre qué factores socioeconómicos y energéticos están relacionados con la generación total de electricidad de los países durante 2022. El modelo presentó un R² ajustado de 0,9192 y fue globalmente significativo (p < 0,0001), lo que muestra que, en conjunto, las variables consideradas explican una proporción importante de las diferencias observadas en la generación eléctrica. Sin embargo, al analizar el aporte individual de cada predictor y mantener constantes las demás variables, únicamente el PIB total presentó una asociación estadísticamente significativa con la generación de electricidad (p < 0,0001). La población, el consumo de electricidad per cápita, el acceso a electricidad y el continente no mostraron evidencia suficiente de una asociación independiente al nivel de significancia del 5 %. Esto no significa que estas variables no estén relacionadas con el fenómeno, sino que su aporte adicional dentro del modelo planteado no resultó estadísticamente significativo.

A pesar de la alta capacidad explicativa del modelo, los diagnósticos evidenciaron algunas limitaciones. Los residuos presentaron una curvatura marcada, desviaciones respecto a la normalidad y una dispersión creciente en los valores ajustados, indicando que los supuestos de linealidad, normalidad y homocedasticidad no se cumplen completamente. Por el contrario, el análisis mediante VIF/GVIF no evidenció problemas importantes de multicolinealidad. También debe considerarse la presencia de países con niveles de generación considerablemente superiores al resto, así como las diferencias en el número de observaciones entre continentes. Además, al utilizar información observacional correspondiente únicamente a 2022, los resultados describen asociaciones estadísticas y no permiten establecer relaciones causales.

En este sentido, el modelo responde parcialmente al objetivo de investigación, ya que permite identificar al PIB como la variable con la asociación estadística más clara con la generación total de electricidad y evidencia que el conjunto de variables posee una alta capacidad explicativa, pero las limitaciones encontradas en los supuestos reducen la confianza con la que puede interpretarse la especificación lineal actual. Por ello, para futuros análisis se recomienda evaluar transformaciones de variables, especificaciones no lineales o métodos robustos, además de estudiar con mayor detalle la influencia de las observaciones extremas. También sería conveniente ampliar el análisis a varios años, lo que permitiría estudiar no solo las diferencias entre países, sino también la evolución de la generación eléctrica en el tiempo.

8 Referencias Bibliograficas

Banco Mundial. (s. f.). Consumo de energía eléctrica (kWh per cápita). Datos del Banco Mundial. https://datos.bancomundial.org/indicador/EG.USE.ELEC.KH.PC?utm_source

Banco Mundial. (2022). Informe sobre el desarrollo mundial 2022: Finanzas al servicio de la recuperación equitativa. https://www.bancomundial.org/es/publication/wdr2022?utm_source

Banco Mundial. (s. f.). PIB (US$ a precios actuales). Datos del Banco Mundial. https://datos.bancomundial.org/indicador/NY.GDP.MKTP.CD?utm_source

El Economista. (2024, 12 de junio). El acceso a la electricidad en el mundo disminuyó en 2022 por primera vez en una década. https://www.eleconomista.com.mx/internacionales/El-acceso-a-la-electricidad-en-el-mundo-disminuyo-en-2022-por-primera-vez-en-una-decada-20240612-0038.html?utm_source.

International Energy Agency. (2022). World Energy Outlook 2022. IEA. https://www.iea.org/reports/world-energy-outlook-2022?utm_source

Our World in Data. (s. f.). Access to Energy. https://ourworldindata.org/energy-access?utm_source

Our World in Data. (s. f.). Electricity generation. https://ourworldindata.org/grapher/electricity-mix?source=total&metric=generation&frequency=annual

Our World in Data. (s. f.). Population & Demography Data Explorer. https://ourworldindata.org/explorers/population-and-demography?indicator=Population&Sex=Both+sexes&Age=Total&Projection+scenario=None&country=CHN~IND~USA~IDN~PAK~NGA~BRA~JPN

Our World in Data. (s. f.). World regions according to Our World in Data. https://ourworldindata.org/grapher/continents-according-to-our-world-in-data?utm_source

Ritchie, H., Rosado, P., & Roser, M. (2022). Energy. Our World in Data. https://ourworldindata.org/energy?utm_source

Semana. (2023). En el 2022 se incrementaron los proyectos de generación y de transmisión energética. https://www.semana.com/economia/empresas/minas-y-energia/articulo/en-el-2022-se-incrementaron-los-proyectos-de-generacion-y-de-transmision-energetica/202342/?utm_source