UNIVERSIDAD CENTRAL DEL ECUADOR

PROYECTO:ESTUDIO ESTADÍSTICO DE LA CALIDAD DEL AIRE EN INDIA

FECHA: 22/11/2025

#============================
# 1. CARGA DE PAQUETES Y DATOS
# ==============================================================================

# Cargar librerías necesarias
library(gt)
library(dplyr)

# Carga de datos
# El archivo ya está cargado en el entorno
datos <- read.csv("C:/Users/JOSELYN/Desktop/kangle/Datos Cambiados.csv", # ¡ATENCIÓN! Ruta cambiada para usar el archivo cargado.
                  header = TRUE,
                  sep = ",",
                  dec = ".")

# ==============================================================================
# 2. PREPARACIÓN Y LIMPIEZA DE DATOS DE MONÓXIDO DE NITRÓGENO (NO)
# ==============================================================================

# Extracción de los "-" (valores inexistentes) de la variable NO
no_data <- datos$NO[datos$NO != "-"]
# Renombrado a 'no' para evitar conflictos con funciones internas si fuera el caso
no <- no_data

# Tamaño muestral después de la limpieza
cat("Tamaño muestral del Monóxido de Nitrógeno (NO) (sin '-'):", length(no), "\n")
## Tamaño muestral del Monóxido de Nitrógeno (NO) (sin '-'): 25949
# Conversión a numérico
no <- as.numeric(no)

# ==============================================================================
# 3. CÁLCULOS PARA LA DISTRIBUCIÓN DE FRECUENCIAS DETALLADA (34 CLASES)
# ==============================================================================

N <- length(no)
min_no <- min(no)
max_no <- max(no)
R <- max_no - min_no

# Número de clases (k): Se mantienen 34 clases
k_detallado <- 34

# Amplitud de clase (A)
A <- R / k_detallado

# Generación de límites de intervalos
Li <- seq(from = min_no, to = max_no - A, by = A)
Ls <- c(seq(from = min_no + A, to = max_no - A, by = A), max_no)

# Redondeo para cálculos de intervalos precisos
no <- round(no, 3)
Li <- round(Li, 3)
Ls <- round(Ls, 3)

# Marcas de Clase (MC)
MC <- (Li + Ls) / 2

# Creación de frecuencias absolutas (ni)
ni <- numeric(length(Li))
for (i in 1:length(Li)) {
  if (i < length(Li)) {
    # Intervalo abierto por la derecha: [Li, Ls)
    ni[i] <- sum(no >= Li[i] & no < Ls[i])
  } else {
    # Último intervalo cerrado: [Li, Ls]
    ni[i] <- sum(no >= Li[i] & no <= Ls[i])
  }
}

# Frecuencias relativas y acumuladas
hi <- (ni / N) * 100
Ni_asc <- cumsum(ni)
Ni_desc <- rev(cumsum(rev(ni)))
Hi_asc <- cumsum(hi)
Hi_desc <- rev(cumsum(rev(hi)))

# Formatear la columna Intervalo
Intervalo <- paste0("[", round(Li, 2), " - ", round(Ls, 2), ")")
# Corregir el último intervalo para que sea cerrado
Intervalo[length(Intervalo)] <- paste0("[", round(Li[length(Li)], 2), " - ",
                                       round(Ls[length(Ls)], 2), "]")

# Crear el Data Frame (TDF)
TDF_no <- data.frame(
  Intervalo = Intervalo,
  MC = round(MC, 2),
  ni = ni,
  hi = round(hi, 2),
  Ni_ascendente = Ni_asc,
  Ni_descendente = Ni_desc,
  Hi_ascendente = round(Hi_asc, 2),
  Hi_descendente = round(Hi_desc, 2)
)

# Agregar la fila de totales
totales <- data.frame(
  Intervalo = "Totales",
  MC = "-",
  ni = sum(ni),
  hi = sum(hi),
  Ni_ascendente = "-",
  Ni_descendente = "-",
  Hi_ascendente = "-",
  Hi_descendente = "-"
)
TDF_no_completa <- rbind(TDF_no, totales)

# Renombrar columnas con los nombres finales (usando comillas invertidas para % en R)
colnames(TDF_no_completa) <- c("Intervalo", "MC", "ni", "hi(%)",
                               "Ni_asc", "Ni_desc", "Hi_asc (%)", "Hi_desc (%)")

# ==============================================================================
# 4. TABLA DE FRECUENCIAS DETALLADA (Tabla Nro. 1)
# ==============================================================================

TDF_no_completa %>%
  gt() %>%
  tab_header(
    title = "Tabla Nro. 1",
    subtitle = "Distribuci\u00F3n de frecuencia detallada de concentraci\u00F3n de Mon\u00F3xido de Nitr\u00F3geno (NO), estudio calidad del aire en India entre 2015-2020"
  ) %>%
  tab_source_note(
    source_note = "Autor: Grupo 2\n Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india"
  ) %>%
  tab_options(
    table.border.top.color = "black",
    table.border.bottom.color = "black",
    table.border.top.style = "solid",
    table.border.bottom.style = "solid",
    column_labels.border.top.color = "black",
    column_labels.border.bottom.color = "black",
    column_labels.border.bottom.width = px(2),
    row.striping.include_table_body = TRUE,
    heading.border.bottom.color = "black",
    heading.border.bottom.width = px(2),
    table_body.hlines.color = "gray",
    table_body.border.bottom.color = "black"
  )
Tabla Nro. 1
Distribución de frecuencia detallada de concentración de Monóxido de Nitrógeno (NO), estudio calidad del aire en India entre 2015-2020
Intervalo MC ni hi(%) Ni_asc Ni_desc Hi_asc (%) Hi_desc (%)
[0.02 - 11.51) 5.76 14740 56.80 14740 25949 56.8 100
[11.51 - 23) 17.25 5622 21.67 20362 11209 78.47 43.2
[23 - 34.49) 28.75 2369 9.13 22731 5587 87.6 21.53
[34.49 - 45.98) 40.24 1115 4.30 23846 3218 91.9 12.4
[45.98 - 57.47) 51.72 637 2.45 24483 2103 94.35 8.1
[57.47 - 68.96) 63.21 445 1.71 24928 1466 96.07 5.65
[68.96 - 80.45) 74.7 302 1.16 25230 1021 97.23 3.93
[80.45 - 91.94) 86.19 223 0.86 25453 719 98.09 2.77
[91.94 - 103.43) 97.68 138 0.53 25591 496 98.62 1.91
[103.43 - 114.92) 109.18 93 0.36 25684 358 98.98 1.38
[114.92 - 126.41) 120.66 82 0.32 25766 265 99.29 1.02
[126.41 - 137.9) 132.16 59 0.23 25825 183 99.52 0.71
[137.9 - 149.39) 143.64 31 0.12 25856 124 99.64 0.48
[149.39 - 160.88) 155.14 33 0.13 25889 93 99.77 0.36
[160.88 - 172.37) 166.62 14 0.05 25903 60 99.82 0.23
[172.37 - 183.86) 178.12 11 0.04 25914 46 99.87 0.18
[183.86 - 195.35) 189.61 6 0.02 25920 35 99.89 0.13
[195.35 - 206.84) 201.1 8 0.03 25928 29 99.92 0.11
[206.84 - 218.33) 212.58 4 0.02 25932 21 99.93 0.08
[218.33 - 229.82) 224.07 5 0.02 25937 17 99.95 0.07
[229.82 - 241.31) 235.56 0 0.00 25937 12 99.95 0.05
[241.31 - 252.8) 247.06 1 0.00 25938 12 99.96 0.05
[252.8 - 264.29) 258.54 0 0.00 25938 11 99.96 0.04
[264.29 - 275.78) 270.03 4 0.02 25942 11 99.97 0.04
[275.78 - 287.27) 281.52 1 0.00 25943 7 99.98 0.03
[287.27 - 298.76) 293.02 2 0.01 25945 6 99.98 0.02
[298.76 - 310.25) 304.5 1 0.00 25946 4 99.99 0.02
[310.25 - 321.74) 316 0 0.00 25946 3 99.99 0.01
[321.74 - 333.23) 327.48 0 0.00 25946 3 99.99 0.01
[333.23 - 344.72) 338.98 0 0.00 25946 3 99.99 0.01
[344.72 - 356.21) 350.47 1 0.00 25947 3 99.99 0.01
[356.21 - 367.7) 361.96 0 0.00 25947 2 99.99 0.01
[367.7 - 379.19) 373.44 0 0.00 25947 2 99.99 0.01
[379.19 - 390.68] 384.94 2 0.01 25949 2 100 0.01
Totales - 25949 100.00 - - - -
Autor: Grupo 2 Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india
# Cargar librerías necesarias (Ya cargadas, solo por referencia)
library(gt)
library(dplyr)

# Carga de datos
datos <- read.csv("C:/Users/JOSELYN/Desktop/kangle/Datos Cambiados.csv",
                  header = TRUE,
                  sep = ",",
                  dec = ".")

# ==============================================================================
# 2. PREPARACIÓN Y LIMPIEZA DE DATOS DE MONÓXIDO DE NITRÓGENO (NO)
# ==============================================================================

# Extracción de los "-" (valores inexistentes) de la variable NO
no <- datos$NO[datos$NO != "-"]
# Conversión a numérico
no <- as.numeric(no)
# Redondeo para cálculos de intervalos precisos
no <- round(no, 3)

# Definir N (Tamaño muestral)
N <- length(no)
min_no <- min(no)
max_no <- max(no)

# ==============================================================================
# 5. CÁLCULOS PARA LA DISTRIBUCIÓN SIMPLIFICADA (13 CLASES)
# ==============================================================================

# Se utiliza la función hist() para obtener los intervalos simplificados
Histograma_no <- hist(no, breaks = 13, plot = FALSE) # No mostrar la gráfica aún

# Extraer elementos simplificados
Lis <- Histograma_no$breaks[1:(length(Histograma_no$breaks) - 1)]
Lss <- Histograma_no$breaks[2:length(Histograma_no$breaks)]
MCs <- (Lis + Lss) / 2
nis <- Histograma_no$counts

# Frecuencias relativas y acumuladas simplificadas
his <- (nis / N) * 100
Nis_asc <- cumsum(nis)
His_asc <- cumsum(his)
Nis_desc <- rev(cumsum(rev(nis)))
His_desc <- rev(cumsum(rev(his)))

# Crear el Data Frame Simplificado
TDF_nosimplificado <- data.frame(
  Intervalo = paste0("[", round(Lis, 2), " - ", round(Lss, 2), ")"),
  MC = round(MCs, 2),
  ni = nis,
  hi = round(his, 2),
  Ni_asc = Nis_asc,
  Hi_asc = round(His_asc, 2),
  Ni_desc = Nis_desc,
  Hi_desc = round(His_desc, 2)
)

# Renombrar columnas con los nombres finales (usando comillas invertidas para % en R)
colnames(TDF_nosimplificado) <- c("Intervalo", "MC", "ni", "hi(%)",
                                  "Ni_asc", "Hi_asc (%)", "Ni_desc", "Hi_desc (%)")

# Agregar la fila de totales (Usando nombres temporales para compatibilidad)
totaless <- data.frame(
  Intervalo = "Totales",
  MC = "-",
  ni = sum(nis),
  hi = sum(his),
  Ni_asc = "-",
  Hi_asc = "-",
  Ni_desc = "-",
  Hi_desc = "-"
)

# Asegurar que las columnas de totaless coincidan con los nombres finales
colnames(totaless) <- colnames(TDF_nosimplificado)

# Unir los data frames
TDF_nosimplificado_completa <- rbind(TDF_nosimplificado, totaless)

# ==============================================================================
# 6. TABLA DE FRECUENCIAS SIMPLIFICADA (Tabla Nro. 2)
# ==============================================================================

TDF_nosimplificado_completa %>%
  gt() %>%
  tab_header(
    title = "Tabla Nro. 2",
    # *** Título actualizado a NO ***
    subtitle = "Distribuci\u00F3n de frecuencia simplificada de concentraci\u00F3n de Mon\u00F3xido de Nitr\u00F3geno (NO), estudio calidad del aire en India entre 2015-2020"
  ) %>%
  tab_source_note(
    source_note = "Autor: Grupo 2\n Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india"
  ) %>%
  tab_options(
    table.border.top.color = "black",
    table.border.bottom.color = "black",
    table.border.top.style = "solid",
    table.border.bottom.style = "solid",
    column_labels.border.top.color = "black",
    column_labels.border.bottom.color = "black",
    column_labels.border.bottom.width = px(2),
    row.striping.include_table_body = TRUE,
    heading.border.bottom.color = "black",
    heading.border.bottom.width = px(2),
    table_body.hlines.color = "gray",
    table_body.border.bottom.color = "black"
  )
Tabla Nro. 2
Distribución de frecuencia simplificada de concentración de Monóxido de Nitrógeno (NO), estudio calidad del aire en India entre 2015-2020
Intervalo MC ni hi(%) Ni_asc Hi_asc (%) Ni_desc Hi_desc (%)
[0 - 50) 25 24089 92.83 24089 92.83 25949 100
[50 - 100) 75 1458 5.62 25547 98.45 1860 7.17
[100 - 150) 125 311 1.20 25858 99.65 402 1.55
[150 - 200) 175 68 0.26 25926 99.91 91 0.35
[200 - 250) 225 12 0.05 25938 99.96 23 0.09
[250 - 300) 275 7 0.03 25945 99.98 11 0.04
[300 - 350) 325 1 0.00 25946 99.99 4 0.02
[350 - 400) 375 3 0.01 25949 100 3 0.01
Totales - 25949 100.00 - - - -
Autor: Grupo 2 Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india
# El código asume que las variables 'no' (vector de datos) y 'Histograma_no'
# (generada en la sección 5: Histograma_no <- hist(no, breaks = 13, plot = FALSE))
# están disponibles en el entorno.

# Símbolo para microgramos/metro cúbico (µg/m³)
unidades_no <- "NO (\u00B5g/m\u00B3)"
# ------------------------------------------------------------------------------
# 7. GRÁFICA N°1: Histograma Local (Frecuencia Absoluta - Eje Y ajustado a la frecuencia más alta)
# ------------------------------------------------------------------------------

hist(no, breaks = 13,
     # *** Título y variable actualizados a NO ***
     main = "Gr\u00E1fica N\u00B01: Distribuci\u00F3n de la Concentraci\u00F3n de Mon\u00F3xido de Nitr\u00F3geno (NO)
     presente en el estudio sobre calidad del aire en India entre 2015-2020",
     # *** Etiqueta del eje X actualizada a NO ***
     xlab = unidades_no,
     ylab = "Cantidad",
     # max(nis) es la altura máxima de la frecuencia absoluta más alta
     ylim = c(0, max(Histograma_no$counts)),
     col = "darkseagreen3", # Nuevo color
     cex.main = 0.9,
     cex.lab = 1,
     cex.axis = 0.9,
     xaxt = "n")
axis(1, at = Histograma_no$breaks,
     labels = round(Histograma_no$breaks, 0), las = 1,
     cex.axis = 0.9)

# ----------------------------------
# Gráfica N°2: Histograma Global (Frecuencia Absoluta - Eje Y ajustado al tamaño total de la muestra)
# ----------------------------------
hist(no, breaks = 13,
     # *** Título y variable actualizados a NO ***
     main = "Gr\u00E1fica N\u00B02: Distribuci\u00F3n de la Concentraci\u00F3n de Mon\u00F3xido de Nitr\u00F3geno (NO)
     presente en el estudio sobre calidad del aire en India entre 2015-2020",
     # *** Etiqueta del eje X actualizada a NO ***
     xlab = unidades_no,
     ylab = "Cantidad",
     # length(no) es la altura máxima (tamaño muestral)
     ylim = c(0, length(no)),
     col = "darkgreen",
     cex.main = 1,
     cex.lab = 1,
     cex.axis = 0.9,
     xaxt = "n")
axis(1, at = Histograma_no$breaks,
     labels = round(Histograma_no$breaks, 0), las = 1,
     cex.axis = 0.9)

# El código asume que el data frame simplificado 'TDF_nosimplificado'
# con la columna 'hi(%)' está disponible.

# Símbolo para microgramos/metro cúbico (µg/m³)
unidades_no <- "NO (\u00B5g/m\u00B3)"

# ------------------------------------------------------------------------------
# Gráfica N°3: Histograma Porcentual Global (Superposición Eje Y 0-100%)
# ------------------------------------------------------------------------------

# Para esta gráfica, usaremos el 'hi(%)' de la tabla simplificada.
n <- as.numeric(nrow(TDF_nosimplificado))
# Se extraen los porcentajes, excluyendo la fila de totales (n-1)
porcentajes <- TDF_nosimplificado$`hi(%)`[1:(n-1)]
marcas_clase <- TDF_nosimplificado$MC[1:(n-1)]

post <- barplot(porcentajes,
                space = 0,
                col = "skyblue",
                # *** Título actualizado a NO ***
                main = "Gr\u00E1fica N\u00B03: Distribuci\u00F3n Porcentual Global de Mon\u00F3xido de Nitr\u00F3geno (NO)
                Estudio Calidad del Aire en India, 2015-2020",
                # *** Etiqueta del eje X actualizada a NO ***
                xlab = unidades_no,
                ylab = "Porcentaje (%)",
                # Fijamos el límite Y entre 0 y 100
                ylim = c(0, 100), 
                cex.main = 0.9,
                cex.lab = 1,
                xaxt = "n",
                yaxt = "n") 

# Dibujamos las etiquetas del Eje X (Marca de Clase)
axis(side = 1,
     at = post,
     labels = marcas_clase,
     tck = -0.02, 
     las = 2,     
     cex.axis = 0.6) 

# Dibujamos las marcas del Eje Y
axis(side = 2,
     at = seq(0, 100, by = 20),
     las = 1,
     cex.axis = 0.9)

# El código asume que el data frame simplificado 'TDF_nosimplificado'
# con la columna 'hi(%)' está disponible.

# Símbolo para microgramos/metro cúbico (µg/m³)
unidades_no <- "NO (\u00B5g/m\u00B3)"

# ------------------------------------------------------------------------------
# Gráfica N°4: Histograma Porcentual Local (Ajustado para máximo)
# ------------------------------------------------------------------------------

n <- as.numeric(nrow(TDF_nosimplificado))
# Se extraen los porcentajes, excluyendo la fila de totales (n-1)
porcentajes <- TDF_nosimplificado$`hi(%)`[1:(n-1)]
marcas_clase <- TDF_nosimplificado$MC[1:(n-1)]

# Nota: El límite Y=80 podría ser demasiado alto si el porcentaje máximo de NO es bajo.
# Usaremos un valor dinámico basado en el máximo porcentaje de NO,
# o mantendremos 80 si así lo requieres para la visualización.
# Si usamos max(porcentajes) * 1.2, se ajustará automáticamente.

pos <- barplot(
  porcentajes,
  space = 0,
  # *** Título y variable actualizados a NO ***
  main = "Gr\u00E1fica N\u00B04: Distribuci\u00F3n Porcentual de Concentraci\u00F3n de Mon\u00F3xido de Nitr\u00F3geno (NO)
  Estudio Calidad del Aire en India, 2015-2020",
  ylab = "Porcentaje (%)",
  # *** Etiqueta del eje X actualizada a NO ***
  xlab = unidades_no,
  
  # AJUSTE CLAVE 1: Usamos un valor fijo si es requerido (80)
  # Si quieres un ajuste dinámico, cambiaría a: ylim = c(0, max(porcentajes) * 1.2)
  ylim = c(0, 80),
  
  col = "darkseagreen",
  cex.main = 0.9,
  cex.lab = 1,
  
  # Ocultamos etiquetas automáticas para control manual
  xaxt = "n",
  yaxt = "n" 
)


# Dibujamos las etiquetas del Eje X (Marca de Clase)
axis(side = 1,
     at = pos,
     labels = marcas_clase,
     tck = -0.04,    
     las = 2,      # Rota etiquetas verticalmente
     cex.axis = 0.6) 

# AJUSTE CLAVE 2: Dibujamos las marcas del Eje Y solo hasta 80
axis(side = 2,
     at = seq(0, 80, by = 20), 
     las = 1,      # Horizontal
     cex.axis = 0.9)

# El código asume que las variables 'no' (vector de datos), 'N', 'Lis', 'Lss',
# 'Nis_asc', 'Nis_desc' (creadas en las secciones 2, 3 y 5) están disponibles.

# Etiqueta del eje X simplificada:
etiqueta_eje_x <- "NO"

# ------------------------------------------------------------------------------
# Gráfica N°5: Diagrama de Caja (Box Plot) para Monóxido de Nitrógeno (NO)
# ------------------------------------------------------------------------------

CajaNO <- boxplot(no, 
                  horizontal = TRUE,
                  col = "turquoise", 
                  border = "black",
                  # *** Título y variable actualizados a NO ***
                  main = "Gr\u00E1fica N\u00B05: Distribuci\u00F3n de la concentraci\u00F3n de Mon\u00F3xido de Nitr\u00F3geno (NO),
                  estudio calidad del aire en India desde 2015-2020",
                  # *** Etiqueta del eje X actualizada a NO ***
                  xlab = "NO",
                  # Ajustes de texto
                  cex.main = 0.9,
                  cex.lab = 1)

# ------------------------------------------------------------------------------
# Gráfica N°6: Ojiva Ascendente y Descendente (Frecuencia Absoluta) para NO
# ------------------------------------------------------------------------------

# 1. Definir los límites de clase extendidos (añadiendo el punto cero)
# Esto asegura que la gráfica inicie en 0 y termine en el máximo.
Limites_X <- c(Lis[1], Lss) # [Min_NO, Ls1, Ls2, ..., Ls_max]

# 2. Definir frecuencias acumuladas extendidas

# Frecuencia Ascendente: [0, Ni_asc1, Ni_asc2, ..., N]
Frec_Asc_Ext <- c(0, Nis_asc) 

# Frecuencia Descendente: [N, Ni_desc1, Ni_desc2, ..., 0]
Frec_Desc_Ext <- c(Nis_desc, 0)

# Ojiva ascendente
plot(Limites_X, Frec_Asc_Ext, 
     type = "b", 
     # *** Título y variable actualizados a NO ***
     main = "Gr\u00E1fica N\u00B06: Ojiva ascendente y descendente de la
     distribuci\u00F3n de la concentraci\u00F3n de Mon\u00F3xido de Nitr\u00F3geno (NO)",
     
     # Ajustamos la etiqueta X para NO
     xlab = etiqueta_eje_x,
     ylab = "Cantidad", 
     
     pch = 19,
     col = "turquoise", 
     
     # Aseguramos que el eje Y cubra desde 0 hasta el total de datos (N)
     ylim = c(0, N), 
     
     # Aseguramos que el eje X vaya desde 0 hasta el límite superior máximo
     xlim = c(0, max(Lss)), 
     
     cex.main = 0.9,
     cex.lab = 1,
     cex.axis = 0.9
)

# Ojiva descendente (Usa los mismos Limites_X extendidos)
lines(Limites_X, Frec_Desc_Ext, 
      type = "b", 
      col = "black", 
      pch = 19)

# El código asume que las variables 'Lis', 'Lss', 'His_asc', 'His_desc'
# (generadas en la sección 5 para NO) están disponibles.

# Etiqueta del eje X simplificada:
etiqueta_eje_x <- "NO"

# ------------------------------------------------------------------------------
# Gráfica N°7: Ojiva Ascendente y Descendente PORCENTUAL para Monóxido de Nitrógeno (NO)
# ------------------------------------------------------------------------------

# 1. Definir los límites de clase extendidos (igual que en la Gráfica N°6)
Limites_X <- c(Lis[1], Lss) 

# 2. Definir frecuencias PORCENTUALES acumuladas extendidas

# Frecuencia Ascendente: [0, Hi_asc1, Hi_asc2, ..., 100]
Frec_H_Asc_Ext <- c(0, His_asc) 

# Frecuencia Descendente: [100, Hi_desc1, Hi_desc2, ..., 0]
Frec_H_Desc_Ext <- c(His_desc, 0)

# Ojiva ascendente (usa Límites Extendidos y Frecuencia Relativa Acumulada Ascendente)
plot(Limites_X, Frec_H_Asc_Ext, 
     type = "b", 
     # *** Título y variable actualizados a NO ***
     main = "Gr\u00E1fica N\u00B07: Ojiva ascendente y descendente de la
     distribuci\u00F3n PORCENTUAL de Mon\u00F3xido de Nitr\u00F3geno (NO)",
     
     # Etiqueta X simplificada a "NO"
     xlab = etiqueta_eje_x,
     # Etiqueta Y para Porcentaje
     ylab = "Porcentaje (%)", 
     
     pch = 19,
     col = "blue", # Color azul para la ascendente
     
     # Ajuste CLAVE: El eje Y va de 0 a 100
     ylim = c(0, 100), 
     
     # Aseguramos que el eje X vaya desde 0 hasta el límite superior máximo
     xlim = c(0, max(Lss)), 
     
     cex.main = 0.9,
     cex.lab = 1,
     cex.axis = 0.9
)

# Ojiva descendente (Usa los mismos Limites_X extendidos)
lines(Limites_X, Frec_H_Desc_Ext, 
      type = "b", 
      col = "red", # Color rojo para la descendente
      pch = 19)

# Opcional: Añadir leyenda para claridad
legend("topright", 
       legend = c("Ojiva Ascendente", "Ojiva Descendente"), 
       col = c("blue", "red"), 
       pch = 19, 
       bty = "n")

# El código asume que las variables 'no', 'min_no', 'max_no' y
# 'TDF_nosimplificado' (creadas en los pasos anteriores para NO) están disponibles.

# ==============================================================================
# 8. CÁLCULO DE INDICADORES ESTADÍSTICOS (NO)
# ==============================================================================

# Carga de librería para Asimetría y Curtosis
library(e1071) 

# --------------------------------
# Indicadores de Tendencia Central
# --------------------------------

# Mediana (Me)
Me <- median(no)

# Media (X)
X <- mean(no)

# Moda (Mo)
# Obtenemos el intervalo de la clase con la frecuencia más alta (Moda de la distribución simplificada)
moda_index <- which.max(TDF_nosimplificado$ni[1:(nrow(TDF_nosimplificado)-1)])
Mo <- TDF_nosimplificado$Intervalo[moda_index]


# --------------------------------
# Indicadores de Dispersión
# --------------------------------

# Varianza
Var_no <- var(no)

# Desviación estándar (sd)
desv <- sd(no)

# Coeficiente de variación (CV)
CV <- (desv / X) * 100

# --------------------------------
# Indicadores de Forma
# --------------------------------

# Coeficiente de Asimetría (As)
As <- skewness(no)

# Curtosis (K)
K <- kurtosis(no)


# --------------------------------
# Creación del Data Frame (Tabla_indicadores)
# --------------------------------

Variable_NO <- "Monóxido de Nitrógeno (NO)"
Rango_NO <- paste0("[", round(min_no, 2), " - ", round(max_no, 2), "]")

Tabla_indicadores_NO <- data.frame(
  Variable = Variable_NO,
  Rango = Rango_NO,
  X = round(X, 3),
  Me = round(Me, 3), 
  Mo = Mo,
  sd = round(desv, 2),
  CV = round(CV, 2),
  As = round(As, 2),
  K = round(K, 2)
)

# Renombrar columnas para la tabla (Mejora de Legibilidad)
# NOTA: He corregido la columna 'kurtosis (K)' a 'Curtosis (K)' para mantener el formato.
colnames(Tabla_indicadores_NO) <- c("Variable", "Rango", "Media (X)", "Mediana (Me)", "Moda (Mo)", "Desv. Est. (sd)", "CV (%)", "Asimetr\u00EDa (As)", "Curtosis (K)")

# El código asume que las variables 'no', 'min_no', 'max_no' y
# 'TDF_nosimplificado' (creadas en los pasos anteriores para NO) están disponibles.

# ==============================================================================
# 8. CÁLCULO DE INDICADORES ESTADÍSTICOS (NO)
# ==============================================================================

# Carga de librería para Asimetria y Curtosis
library(e1071) 

# --------------------------------
# Indicadores de Tendencia Central
# --------------------------------

# Mediana (Me)
Me <- median(no)

# Media (X)
X <- mean(no)

# Moda (Mo)
# Obtenemos el intervalo de la clase con la frecuencia más alta (Moda de la distribución simplificada)
moda_index <- which.max(TDF_nosimplificado$ni[1:(nrow(TDF_nosimplificado)-1)])
Mo <- TDF_nosimplificado$Intervalo[moda_index]


# --------------------------------
# Indicadores de Dispersión
# --------------------------------

# Varianza
Var_no <- var(no)

# Desviación estándar (sd)
desv <- sd(no)

# Coeficiente de variación (CV)
CV <- (desv / X) * 100

# --------------------------------
# Indicadores de Forma
# --------------------------------

# Coeficiente de Asimetria (As)
As <- skewness(no)

# kurtosis (K)
K <- kurtosis(no)


# --------------------------------
# Creación del Data Frame (Tabla_indicadores)
# --------------------------------

Variable_NO <- "Monoxido de Nitrogeno (NO)"
Rango_NO <- paste0("[", round(min_no, 2), " - ", round(max_no, 2), "]")

Tabla_indicadores_NO <- data.frame(
  Variable = Variable_NO,
  Rango = Rango_NO,
  X = round(X, 3),
  Me = round(Me, 3), 
  Mo = Mo,
  sd = round(desv, 2),
  CV = round(CV, 2),
  As = round(As, 2),
  K = round(K, 2)
)

# Renombrar columnas para la tabla (Mejora de Legibilidad)
# NOTA: He corregido la columna 'kurtosis (K)' a 'Curtosis (K)' para mantener el formato.
colnames(Tabla_indicadores_NO) <- c("Variable", "Rango", "Media (X)", "Mediana (Me)", "Moda (Mo)", "Desv. Est. (sd)", "CV (%)", "Asimetria (As)", "kurtosis (K)")

# El código asume que el data frame 'Tabla_indicadores_NO' ya fue generado
# en el paso anterior y está disponible.

# ==============================================================================
# 9. TABLA DE INDICADORES ESTADÍSTICOS (Tabla Nro. 3) - Usando GT
# ==============================================================================

Tabla_indicadores_NO %>% # *** Usamos la nueva tabla de NO ***
  gt() %>%
  tab_header(
    title = md("Tabla Nro. 3"),
    # *** Subtítulo actualizado a NO y se usa Unicode para acentos ***
    subtitle = md("*Indicadores Estadisticos de concentracion de Monoxido de Nitrogeno (NO), estudio calidad del aire en India entre 2015-2020 *")
  ) %>%
  tab_source_note(
    source_note = md("Autor: Grupo 2\n Fuente:https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india")
  ) %>%
  # Agrupamos las columnas por categoría (Mejora de la presentación)
  tab_spanner(
    label = "Tendencia Central",
    columns = c("Media (X)", "Mediana (Me)", "Moda (Mo)")
  ) %>%
  tab_spanner(
    # Usando código Unicode para 'Dispersión'
    label = "Dispersion",
    columns = c("Desv. Est. (sd)", "CV (%)")
  ) %>%
  tab_spanner(
    label = "Forma",
    # *** Usando código Unicode para seleccionar las columnas 'Asimetria (As)' y 'Curtosis (K)' ***
    columns = c("Asimetria (As)", "kurtosis (K)")
  ) %>%
  # Formateo de números
  fmt_number(
    # *** Usando código Unicode para referenciar las columnas ***
    columns = c("Media (X)", "Mediana (Me)", "Desv. Est. (sd)", "CV (%)", "Asimetria (As)", "kurtosis (K)"),
    decimals = 2
  ) %>%
  # Opciones de estilo (basado en tu plantilla)
  tab_options(
    table.border.top.color = "black",
    table.border.bottom.color = "black",
    table.border.top.style = "solid",
    table.border.bottom.style = "solid",
    column_labels.border.top.color = "black",
    column_labels.border.bottom.color = "black",
    column_labels.border.bottom.width = px(2),
    row.striping.include_table_body = TRUE,
    heading.border.bottom.color = "black",
    heading.border.bottom.width = px(2),
    table_body.hlines.color = "gray",
    table_body.border.bottom.color = "black"
  )
Tabla Nro. 3
*Indicadores Estadisticos de concentracion de Monoxido de Nitrogeno (NO), estudio calidad del aire en India entre 2015-2020 *
Variable Rango
Tendencia Central
Dispersion
Forma
Media (X) Mediana (Me) Moda (Mo) Desv. Est. (sd) CV (%) Asimetria (As) kurtosis (K)
Monoxido de Nitrogeno (NO) [0.02 - 390.68] 17.57 9.89 [0 - 50) 22.79 129.65 3.88 25.16
Autor: Grupo 2 Fuente:https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india