0.- carga de librerías

# carga de librerías

library(gt)
library(dplyr)
library(e1071)

1.- carga de datos

# carga de datos

datos <- read.csv(
  "C:/Users/JOSELYN/Documents/UNIVERSIDAD 3-4 SEMESTRE/ESTADISTICA/MAPA QGIS/Datos Cambiados.csv",
  header = TRUE,
  dec = ".",
  sep = ","
)

2.- selección de variable

# selección de la variable NO

NO <- datos$NO[datos$NO != "-"]

# conversión a numérico
NO <- as.numeric(NO)

3.- frecuencia

# frecuencias para NO

# tamaño de muestra
n <- length(NO)

# valor mínimo y máximo
min_NO <- min(NO, na.rm = TRUE)
max_NO <- max(NO, na.rm = TRUE)

# rango
R <- max_NO - min_NO

# número de intervalos
# se conserva el cálculo funcional del código original de NO
k_detallado <- floor(1 + (3.3 * log(n)))

# amplitud de clase
A <- R / k_detallado

# mostrar resultados
cat("Número de intervalos (k):", k_detallado, "\n")
## Número de intervalos (k): 34
cat("Amplitud de clase:", A, "\n")
## Amplitud de clase: 11.49
# 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
)

# marcas de clase
MC <- (Li + Ls) / 2

# frecuencias absolutas
ni <- numeric(length(Li))

for (i in 1:length(Li)) {

  if (i < length(Li)) {

    ni[i] <- sum(
      NO >= Li[i] & NO < Ls[i],
      na.rm = TRUE
    )

  } else {

    ni[i] <- sum(
      NO >= Li[i] & NO <= Ls[i],
      na.rm = TRUE
    )
  }
}

# frecuencias relativas y acumuladas
N <- sum(ni)

hi <- (ni / N) * 100

Ni_asc <- cumsum(ni)
Ni_desc <- rev(cumsum(rev(ni)))

Hi_asc <- cumsum(hi)
Hi_desc <- rev(cumsum(rev(hi)))

# intervalos
Intervalo <- paste0(
  "[",
  round(Li, 2),
  " - ",
  round(Ls, 2),
  ")"
)

# último intervalo cerrado
Intervalo[length(Intervalo)] <- paste0(
  "[",
  round(Li[length(Li)], 2),
  " - ",
  round(Ls[length(Ls)], 2),
  "]"
)

# tabla de distribución de frecuencias
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)
)

# fila de totales
totales <- data.frame(
  Intervalo = "Totales",
  MC = "-",
  ni = sum(ni),
  hi = round(sum(hi), 2),
  Ni_ascendente = "-",
  Ni_descendente = "-",
  Hi_ascendente = "-",
  Hi_descendente = "-"
)

# tabla completa
TDF_NO_completa <- rbind(
  TDF_NO,
  totales
)

4.- tabla de distribución de frecuencia

tabla con regla de Sturges

# tabla de frecuencias detallada

TDF_NO_completa %>%
  gt() %>%

  tab_header(
    title = "Tabla Nro. 1",
    subtitle = "Distribución de frecuencia de concentración de Monóxido de Nitrógeno (NO), estudio calidad del aire en India entre 2015-2020"
  ) %>%

  tab_source_note(
    source_note = md(
      "Grupo: 1 <br> Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india"
    )
  ) %>%

  tab_style(
    style = cell_borders(
      sides = "left",
      color = "black",
      weight = px(2)
    ),
    locations = cells_body()
  ) %>%

  tab_style(
    style = cell_borders(
      sides = "right",
      color = "black",
      weight = px(2)
    ),
    locations = cells_body()
  ) %>%

  tab_style(
    style = cell_borders(
      sides = "left",
      color = "black",
      weight = px(2)
    ),
    locations = cells_column_labels()
  ) %>%

  tab_style(
    style = cell_borders(
      sides = "right",
      color = "black",
      weight = px(2)
    ),
    locations = cells_column_labels()
  ) %>%

  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 de concentración de Monóxido de Nitrógeno (NO), estudio calidad del aire en India entre 2015-2020
Intervalo MC ni hi Ni_ascendente Ni_descendente Hi_ascendente Hi_descendente
[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.73 637 2.45 24483 2103 94.35 8.1
[57.47 - 68.96) 63.22 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.2 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.17 93 0.36 25684 358 98.98 1.38
[114.92 - 126.41) 120.67 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.97 0 0.00 25946 3 99.99 0.01
[344.72 - 356.21) 350.46 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 - - - -
Grupo: 1
Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india

tabla de intervalos reducidos

# por una gran cantidad de intervalos se realiza una reducción
# en la tabla Nro. 2, creando solamente 10 intervalos

k_tabla2 <- 10

# amplitud para conservar los intervalos funcionales del código de NO
A2 <- ceiling(R / k_tabla2)

# nuevos límites
Li2 <- seq(
  from = floor(min_NO),
  by = A2,
  length.out = k_tabla2
)

Ls2 <- seq(
  from = floor(min_NO) + A2,
  by = A2,
  length.out = k_tabla2
)

# marcas de clase
MC2 <- (Li2 + Ls2) / 2

# frecuencias absolutas
ni2 <- numeric(length(Li2))

for (i in 1:length(Li2)) {

  if (i < length(Li2)) {

    ni2[i] <- sum(
      NO >= Li2[i] & NO < Ls2[i],
      na.rm = TRUE
    )

  } else {

    ni2[i] <- sum(
      NO >= Li2[i] & NO <= Ls2[i],
      na.rm = TRUE
    )
  }
}

# frecuencias relativas y acumuladas
N2 <- sum(ni2)

hi2 <- (ni2 / N2) * 100

Ni2_asc <- cumsum(ni2)
Ni2_desc <- rev(cumsum(rev(ni2)))

Hi2_asc <- cumsum(hi2)
Hi2_desc <- rev(cumsum(rev(hi2)))

# intervalos
Intervalo2 <- paste0(
  "[",
  round(Li2, 2),
  " - ",
  round(Ls2, 2),
  ")"
)

# último intervalo cerrado
Intervalo2[length(Intervalo2)] <- paste0(
  "[",
  round(Li2[length(Li2)], 2),
  " - ",
  round(Ls2[length(Ls2)], 2),
  "]"
)

# tabla 2
TDF_NO_10 <- data.frame(
  Intervalo = Intervalo2,
  MC = round(MC2, 2),
  ni = ni2,
  hi = round(hi2, 2),
  Ni_ascendente = Ni2_asc,
  Ni_descendente = Ni2_desc,
  Hi_ascendente = round(Hi2_asc, 2),
  Hi_descendente = round(Hi2_desc, 2)
)

# totales
totales2 <- data.frame(
  Intervalo = "Totales",
  MC = "-",
  ni = sum(ni2),
  hi = round(sum(hi2), 2),
  Ni_ascendente = "-",
  Ni_descendente = "-",
  Hi_ascendente = "-",
  Hi_descendente = "-"
)

TDF_NO_10_completa <- rbind(
  TDF_NO_10,
  totales2
)

# tabla 2: distribución de frecuencias de NO con 10 intervalos
TDF_NO_10_completa %>%
  gt() %>%

  tab_header(
    title = "Tabla Nro. 2",
    subtitle = "Distribución de frecuencia de concentración de Monóxido de Nitrógeno (NO), estudio calidad del aire en India entre 2015-2020"
  ) %>%

  tab_source_note(
    source_note = md(
      "Grupo: 1 <br> Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india"
    )
  ) %>%

  tab_style(
    style = cell_borders(
      sides = "left",
      color = "black",
      weight = px(2)
    ),
    locations = cells_body()
  ) %>%

  tab_style(
    style = cell_borders(
      sides = "right",
      color = "black",
      weight = px(2)
    ),
    locations = cells_body()
  ) %>%

  tab_style(
    style = cell_borders(
      sides = "left",
      color = "black",
      weight = px(2)
    ),
    locations = cells_column_labels()
  ) %>%

  tab_style(
    style = cell_borders(
      sides = "right",
      color = "black",
      weight = px(2)
    ),
    locations = cells_column_labels()
  ) %>%

  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 de concentración de Monóxido de Nitrógeno (NO), estudio calidad del aire en India entre 2015-2020
Intervalo MC ni hi Ni_ascendente Ni_descendente Hi_ascendente Hi_descendente
[0 - 40) 20 23347 89.97 23347 25949 89.97 100
[40 - 80) 60 1867 7.19 25214 2602 97.17 10.03
[80 - 120) 100 506 1.95 25720 735 99.12 2.83
[120 - 160) 140 169 0.65 25889 229 99.77 0.88
[160 - 200) 180 37 0.14 25926 60 99.91 0.23
[200 - 240) 220 11 0.04 25937 23 99.95 0.09
[240 - 280) 260 5 0.02 25942 12 99.97 0.05
[280 - 320) 300 4 0.02 25946 7 99.99 0.03
[320 - 360) 340 1 0.00 25947 3 99.99 0.01
[360 - 400] 380 2 0.01 25949 2 100 0.01
Totales - 25949 100.00 - - - -
Grupo: 1
Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india

5.- gráficos de distribución de frecuencia

histogramas de cantidad

# histograma que genera RStudio

Histograma_NO <- hist(
  NO,
  breaks = 13,
  plot = FALSE
)

hist(
  NO,
  breaks = 13,
  main = "Gráfica Nro.1 de distribución de frecuencias de concentración de NO\nen el estudio calidad del aire en India de 2015-2020",
  xlab = "NO (µg/m³)",
  ylab = "Cantidad",
  ylim = c(0, max(Histograma_NO$counts)),
  col = "darkseagreen3",
  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
)

grid()

# histograma con relación a la totalidad de los datos

Histograma_NO <- hist(
  NO,
  breaks = 13,
  plot = FALSE
)

par(mgp = c(3.2, 1, 0))

techo_total <- ceiling(n / 5000) * 5000

hist(
  NO,
  breaks = 13,
  main = "Gráfica Nro.2 de distribución de frecuencias de concentración de NO\nen el estudio calidad del aire en India de 2015-2020",
  xlab = "NO (µg/m³)",
  ylab = "Cantidad",
  ylim = c(0, techo_total),
  col = "darkseagreen3",
  cex.main = 0.9,
  cex.lab = 1,
  cex.axis = 0.9,
  xaxt = "n",
  yaxt = "n"
)

# eje X
axis(
  1,
  at = Histograma_NO$breaks,
  labels = round(Histograma_NO$breaks, 0),
  las = 1,
  cex.axis = 0.9
)

# eje Y
axis(
  2,
  at = seq(0, techo_total, by = 5000),
  labels = seq(0, techo_total, by = 5000),
  las = 1,
  cex.axis = 0.9
)

grid()

histogramas porcentuales

# histograma porcentual que genera RStudio

bp <- barplot(
  hi2,
  space = 0,
  names.arg = FALSE,
  xaxt = "n",
  main = "Gráfica Nro.3 de distribución porcentual de NO\nen el estudio calidad del aire en India de 2015-2020",
  xlab = "NO (µg/m³)",
  ylab = "Porcentaje (%)",
  col = "darkseagreen3",
  border = "black",
  ylim = c(0, max(hi2) + 5),
  cex.main = 0.9,
  cex.lab = 1,
  cex.axis = 0.9
)

# bordes de las barras
bordes <- c(
  bp[1] - 0.5,
  bp + 0.5
)

eje_x_max <- ceiling(max_NO / 100) * 100
etiquetas_x <- seq(0, eje_x_max, by = 100)

axis(
  1,
  at = seq(
    min(bordes),
    max(bordes),
    length.out = length(etiquetas_x)
  ),
  labels = etiquetas_x,
  las = 1,
  tck = -0.03
)

grid()

# histograma con relación a la totalidad porcentualmente

bp <- barplot(
  hi2,
  space = 0,
  names.arg = FALSE,
  xaxt = "n",
  yaxt = "n",
  main = "Gráfica Nro.4 de distribución porcentual de NO\nen el estudio calidad del aire en India de 2015-2020",
  xlab = "NO (µg/m³)",
  ylab = "Porcentaje (%)",
  col = "darkseagreen3",
  border = "black",
  ylim = c(0, 100),
  cex.main = 0.9,
  cex.lab = 1,
  cex.axis = 0.9
)

# eje X
bordes <- c(
  bp[1] - 0.5,
  bp + 0.5
)

axis(
  1,
  at = seq(
    min(bordes),
    max(bordes),
    length.out = length(etiquetas_x)
  ),
  labels = etiquetas_x,
  las = 1,
  tck = -0.03
)

# eje Y
axis(
  2,
  at = seq(0, 100, by = 20),
  labels = paste0(seq(0, 100, by = 20)),
  las = 1
)

grid()

diagrama de caja y bigotes

# diagrama de caja y bigotes

boxplot(
  NO,
  horizontal = TRUE,
  xaxt = "n",
  yaxt = "n",
  main = "Gráfica Nro.5: Diagrama de caja de la concentración de NO\nen el estudio calidad del aire en India de 2015-2020",
  xlab = "NO (µg/m³)",
  col = "turquoise3",
  border = "black",
  cex.main = 0.9,
  cex.lab = 1,
  cex.axis = 0.9
)

# eje X personalizado
axis(
  1,
  at = seq(0, eje_x_max, by = 100),
  labels = seq(0, eje_x_max, by = 100),
  las = 1
)

grid()

diagrama de ojivas

# ojiva ascendente y descendente iniciada desde cero

x_ojiva <- c(
  0,
  Ls2
)

Ni2_asc_cero <- c(
  0,
  Ni2_asc
)

Ni2_desc_cero <- c(
  N2,
  Ni2_desc
)

plot(
  x_ojiva,
  Ni2_asc_cero,
  type = "b",
  pch = 16,
  col = "turquoise3",
  lwd = 1,
  ylim = c(0, N2),
  xlim = c(0, eje_x_max),
  xaxt = "n",
  xlab = "NO",
  ylab = "Cantidad",
  main = "Gráfica N°6: Ojiva ascendente y descendente de la\nconcentración de Monóxido de Nitrógeno (NO)",
  cex.main = 1
)

# eje X desde cero
axis(
  1,
  at = seq(0, eje_x_max, by = 100)
)

# ojiva descendente
lines(
  x_ojiva,
  Ni2_desc_cero,
  type = "b",
  pch = 16,
  col = "black",
  lwd = 1
)

grid()
box()

# ojiva porcentual ascendente y descendente iniciada desde cero

Hi2_asc_cero <- c(
  0,
  Hi2_asc
)

Hi2_desc_cero <- c(
  100,
  Hi2_desc
)

plot(
  x_ojiva,
  Hi2_asc_cero,
  type = "b",
  pch = 16,
  col = "turquoise3",
  lwd = 1,
  ylim = c(0, 100),
  xlim = c(0, eje_x_max),
  xaxt = "n",
  xlab = "NO",
  ylab = "Porcentaje (%)",
  main = "Gráfica N°7: Ojiva porcentual ascendente y descendente de la\nconcentración de Monóxido de Nitrógeno (NO)",
  cex.main = 1
)

# eje X desde cero
axis(
  1,
  at = seq(0, eje_x_max, by = 100)
)

# ojiva porcentual descendente
lines(
  x_ojiva,
  Hi2_desc_cero,
  type = "b",
  pch = 16,
  col = "black",
  lwd = 1
)

grid()
box()

6.- indicadores estadísticos

# cálculo previo de indicadores

X <- mean(NO, na.rm = TRUE)
Me <- median(NO, na.rm = TRUE)

# moda
moda_index <- which.max(
  TDF_NO_10_completa$ni[
    1:(nrow(TDF_NO_10_completa) - 1)
  ]
)

Mo <- TDF_NO_10_completa$Intervalo[moda_index]

# indicadores de dispersión
desv <- sd(NO, na.rm = TRUE)
CV <- (desv / X) * 100

# asimetría y curtosis
As <- skewness(NO, na.rm = TRUE)
K <- kurtosis(NO, na.rm = TRUE)

# creación del data frame
Tabla_indicadores <- data.frame(
  Variable = "NO",
  Rango = paste0(
    "[",
    round(min(NO, na.rm = TRUE), 2),
    " - ",
    round(max(NO, na.rm = TRUE), 2),
    "]"
  ),
  Media = X,
  Mediana = Me,
  Moda = Mo,
  DesvEst = desv,
  CV = CV,
  Asimetria = As,
  Curtosis = K
)

# visualización de la tabla
Tabla_indicadores %>%
  gt() %>%

  cols_label(
    Variable = "Variable",
    Rango = "Rango",
    Media = "Media (X)",
    Mediana = "Mediana (Me)",
    Moda = "Moda (Mo)",
    DesvEst = "Desv. Est. (sd)",
    CV = "CV (%)",
    Asimetria = "Asimetría (As)",
    Curtosis = "Curtosis (K)"
  ) %>%

  tab_header(
    title = "Tabla Nro. 3",
    subtitle = "Indicadores Estadísticos de la concentración de NO, estudio calidad del aire en India entre 2015-2020"
  ) %>%

  tab_source_note(
    source_note = "Autor: Grupo 1 | Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india"
  ) %>%

  tab_spanner(
    label = "Tendencia Central",
    columns = c(
      Media,
      Mediana,
      Moda
    )
  ) %>%

  tab_spanner(
    label = "Dispersión",
    columns = c(
      DesvEst,
      CV
    )
  ) %>%

  tab_spanner(
    label = "Forma",
    columns = c(
      Asimetria,
      Curtosis
    )
  ) %>%

  fmt_number(
    columns = c(
      Media,
      Mediana,
      DesvEst,
      CV,
      Asimetria,
      Curtosis
    ),
    decimals = 2
  ) %>%

  tab_style(
    style = cell_borders(
      sides = c(
        "left",
        "right",
        "top",
        "bottom"
      ),
      color = "black",
      weight = px(1)
    ),
    locations = list(
      cells_body(
        columns = everything(),
        rows = everything()
      ),
      cells_column_labels(
        columns = everything()
      ),
      cells_column_spanners(
        spanners = everything()
      )
    )
  ) %>%

  tab_options(
    table.border.top.color = "black",
    table.border.bottom.color = "black",
    table.border.left.color = "black",
    table.border.right.color = "black",
    table_body.hlines.color = "black",
    table_body.vlines.color = "black",
    column_labels.border.bottom.width = px(2)
  )
Tabla Nro. 3
Indicadores Estadísticos de la concentración de NO, estudio calidad del aire en India entre 2015-2020
Variable Rango
Tendencia Central
Dispersión
Forma
Media (X) Mediana (Me) Moda (Mo) Desv. Est. (sd) CV (%) Asimetría (As) Curtosis (K)
NO [0.02 - 390.68] 17.57 9.89 [0 - 40) 22.79 129.65 3.88 25.16
Autor: Grupo 1 | Fuente: https://www.kaggle.com/datasets/rohanrao/air-quality-data-in-india

7.- conclusión

# identificación de valores atípicos

atipicos_NO <- boxplot.stats(NO)$out

# conclusión con la misma estructura utilizada para NOx
texto_conclusion <- paste0(
  "La variable Monóxido de Nitrógeno (NO) fluctúa entre un mínimo de ",
  round(min(NO, na.rm = TRUE), 2),
  " y un máximo de ",
  round(max(NO, na.rm = TRUE), 2),
  " microgramos por metro cúbico (µg/m³), con una media de ",
  round(X, 2),
  " y una desviación estándar de ",
  round(desv, 2),
  ". Debido a un coeficiente de variación del ",
  round(CV, 2),
  "%, se concluye que es un conjunto de valores heterogéneos con una alta dispersión. ",
  "Los datos se acumulan de manera predominante en el primer intervalo ",
  Mo,
  ". No obstante, se han detectado ",
  format(length(atipicos_NO), big.mark = ","),
  " valores atípicos, los cuales representan picos de contaminación que pueden afectar moderadamente al medio ambiente."
)

df_conclusion_NO <- data.frame(
  Conclusión = texto_conclusion
)

df_conclusion_NO %>%
  gt() %>%

  tab_header(
    title = md("## **Conclusión**")
  ) %>%

  tab_options(
    column_labels.hidden = TRUE,
    table.border.top.color = "black",
    table.border.bottom.color = "black",
    table.border.top.width = px(3),
    table.border.bottom.width = px(3),
    heading.align = "center"
  ) %>%

  tab_style(
    style = cell_text(
      align = "justify",
      v_align = "middle"
    ),
    locations = cells_body(
      columns = Conclusión
    )
  )

Conclusión

La variable Monóxido de Nitrógeno (NO) fluctúa entre un mínimo de 0.02 y un máximo de 390.68 microgramos por metro cúbico (µg/m³), con una media de 17.57 y una desviación estándar de 22.79. Debido a un coeficiente de variación del 129.65%, se concluye que es un conjunto de valores heterogéneos con una alta dispersión. Los datos se acumulan de manera predominante en el primer intervalo [0 - 40). No obstante, se han detectado 2,459 valores atípicos, los cuales representan picos de contaminación que pueden afectar moderadamente al medio ambiente.