# Tema: Estadística Descriptiva
# Autor: Camila Zambrano
# Fecha: 26/05/2026

0.- Carga de librerias

library(knitr)
library(kableExtra)
library(readr)
library(gt)
## Warning: package 'gt' was built under R version 4.5.3
library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following object is masked from 'package:kableExtra':
## 
##     group_rows
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

1.- Leer datos

setwd("~/Camila/Estadística")
datos <- read.csv("Datos cambiados..csv",
                  header = TRUE, 
                  sep = ",", dec = "." )

2.- Selección de la variable

# Limpiar variable
datos$SO2[datos$SO2 == "-"] <- NA
datos$SO2 <- as.numeric(datos$SO2)

# Eliminar NA
dioxido_azufre <- na.omit(datos$SO2)
dioxido_azufre <-
  dioxido_azufre[dioxido_azufre >=0]

# Tamaño de muestra
n <- length(dioxido_azufre)
n
## [1] 25677

3.- Conteo (frecuencia)

Construcción manual (Regla de Sturges)

# Parámetros
minimo <- min(dioxido_azufre)
maximo <- max(dioxido_azufre)

R <- maximo - minimo
K <- floor(1 + 3.322 * log10(n))
A <- R / K

# Límites 
Li <- round(seq(from = minimo, to = maximo, length.out = K), 2)
Ls <- c(Li[-1], round(maximo,2))

# Marca de clase
Mc <- (Li + Ls)/2

# Frecuencia absoluta
ni <- numeric(K)

for (i in 1:K) {
  if (i < K) {
    ni[i] <- sum(dioxido_azufre >= Li[i] & 
                   dioxido_azufre < Ls[i])
  } else {
    ni[i] <- sum(dioxido_azufre >= Li[i] & 
                   dioxido_azufre <= Ls[i])
  }
}

# Frecuencia relativa
hi <- round((ni / sum(ni)) * 100, 2)
hi[length(hi)] <- round(
  100 - sum(hi[-length(hi)]),
  2
)

# Frecuencia acumuladas 
Ni_asc <- cumsum(ni)
Ni_dsc <- rev(cumsum(rev(ni)))
Hi_asc <- round(cumsum(hi), 2)
Hi_dsc <- round(rev(cumsum(rev(hi))), 2)

4.- Tabla de distribución de frecuencia

4.1 Tabla general

TDF_dioxido_azufre <-data.frame(Li, Ls,
                                Mc, ni,
                                hi,Ni_asc,
                                Ni_dsc,
                                Hi_asc,
                                Hi_dsc)

# Totales
total_ni <- sum(ni)
total_hi <- sum(hi)

# Agregra fila total
TDF_dioxido_azufre_completo <- rbind(
  TDF_dioxido_azufre,
  data.frame(
    Li = "Total",
    Ls = "-",
    Mc = "-",
    ni = total_ni,
    hi = total_hi,
    Ni_asc = "-",
    Ni_dsc = "-",
    Hi_asc = "-",
    Hi_dsc = "-"
  )
)

# Redondeo
TDF_dioxido_azufre_completo$hi <- round(
  as.numeric(TDF_dioxido_azufre_completo$hi),
  2
)

tabla_dioxido_azufre <- TDF_dioxido_azufre_completo %>%
  gt() %>%
  
  fmt_number(
    columns = hi,
    decimals = 2
  ) %>%
  
  tab_header(
    title = md("*Tabla Nº1*"),
    subtitle = md(
      "**Distribución de frecuencia de Dióxiodo de Azufre en el análisis
      sobre la calidad del aire en India**"
    )
  ) %>%
  
  tab_source_note(
    source_note = md("Autor: Grupo 1")
  ) %>%
  
  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"
  ) %>%
  
  tab_style(
    style = cell_text(weight = "bold"),
    locations = cells_body(
      rows = Li == "Total"
    )
  )

tabla_dioxido_azufre
Tabla Nº1
Distribución de frecuencia de Dióxiodo de Azufre en el análisis sobre la calidad del aire en India
Li Ls Mc ni hi Ni_asc Ni_dsc Hi_asc Hi_dsc
0.01 13.86 6.935 18336 71.41 18336 25677 71.41 100
13.86 27.7 20.78 4542 17.69 22878 7341 89.1 28.59
27.7 41.55 34.625 1195 4.65 24073 2799 93.75 10.9
41.55 55.4 48.475 743 2.89 24816 1604 96.64 6.25
55.4 69.24 62.32 286 1.11 25102 861 97.75 3.36
69.24 83.09 76.165 150 0.58 25252 575 98.33 2.25
83.09 96.94 90.015 117 0.46 25369 425 98.79 1.67
96.94 110.78 103.86 99 0.39 25468 308 99.18 1.21
110.78 124.63 117.705 74 0.29 25542 209 99.47 0.82
124.63 138.47 131.55 57 0.22 25599 135 99.69 0.53
138.47 152.32 145.395 30 0.12 25629 78 99.81 0.31
152.32 166.17 159.245 19 0.07 25648 48 99.88 0.19
166.17 180.01 173.09 24 0.09 25672 29 99.97 0.12
180.01 193.86 186.935 4 0.02 25676 5 99.99 0.03
193.86 193.86 193.86 1 0.01 25677 1 100 0.01
Total - - 25677 100.00 - - - -
Autor: Grupo 1

4.2 Tabla simplificada

histograma_simplificado <- hist(
  dioxido_azufre,
  breaks = 10,
  plot = FALSE
)

# Límites y frecuencias simplificadas independientes
Limites_simp <- histograma_simplificado$breaks

Li_simp <- Limites_simp[1:(length(Limites_simp)-1)]
Ls_simp <- Limites_simp[2:length(Limites_simp)]

Mc_simp <- histograma_simplificado$mids
ni_simp <- histograma_simplificado$counts

hi_simp <- ni_simp/sum(ni_simp)*100
hi_simp <- round(hi_simp, 2)
hi_simp[length(hi_simp)] <- round(
  100 - sum(hi_simp[-length(hi_simp)]),
  2
)

Ni_asc_simp <- cumsum(ni_simp)
Ni_dsc_simp <- rev(cumsum(rev(ni_simp)))

Hi_asc_simp <- cumsum(hi_simp)
Hi_dsc_simp <- rev(cumsum(rev(hi_simp)))
Hi_asc_simp <- round(Hi_asc_simp, 2)
Hi_dsc_simp <- round(Hi_dsc_simp, 2)
Hi_asc_simp[length(Hi_asc_simp)] <- 100
Hi_dsc_simp[1] <- 100

# Tabla
TDF_completa <- data.frame(
  Li = Li_simp,
  Ls = Ls_simp,
  Mc = Mc_simp,
  ni = ni_simp,
  hi = hi_simp,
  Ni_asc = Ni_asc_simp,
  Ni_dsc = Ni_dsc_simp,
  Hi_asc = Hi_asc_simp,
  Hi_dsc = Hi_dsc_simp
)

# Totales
totalni <- sum(ni_simp)
totalhi <- sum(hi_simp)

# Agregar fila total
TDF_simplificada_completa <-rbind(
  TDF_completa,
  data.frame(
    Li = "Total",
    Ls = "-",
    Mc = "-",
    ni = totalni,
    hi = totalhi,
    Ni_asc = "-",
    Ni_dsc = "-",
    Hi_asc = "-",
    Hi_dsc = "-"
  )
)

# Crear tabla gt
tabla_simplificada <-TDF_simplificada_completa %>%
  gt() %>%
  
  tab_header(
    title = md("*Tabla Nº2*"),
    subtitle = md(
      "**Distribución de frecuencia simplificada de Dióxiodo de Azufre en el 
    análisis sobre la calidad del aire en India 2015-2020**")
  ) %>%
  tab_source_note(
    source_note = md("Autor:Grupo 1")
  ) %>%
  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"
  )  %>%
  
  tab_style(
    style = cell_text(weight = "bold"),
    locations = cells_body(
      rows = Li == "Total"
    )
  )

tabla_simplificada
Tabla Nº2
Distribución de frecuencia simplificada de Dióxiodo de Azufre en el análisis sobre la calidad del aire en India 2015-2020
Li Ls Mc ni hi Ni_asc Ni_dsc Hi_asc Hi_dsc
0 20 10 21244 82.74 21244 25677 82.74 100
20 40 30 2735 10.65 23979 4433 93.39 17.26
40 60 50 953 3.71 24932 1698 97.1 6.61
60 80 70 287 1.12 25219 745 98.22 2.9
80 100 90 174 0.68 25393 458 98.9 1.78
100 120 110 128 0.50 25521 284 99.4 1.1
120 140 130 83 0.32 25604 156 99.72 0.6
140 160 150 40 0.16 25644 73 99.88 0.28
160 180 170 28 0.11 25672 33 99.99 0.12
180 200 190 5 0.01 25677 5 100 0.01
Total - - 25677 100.00 - - - -
Autor:Grupo 1

5.- Gráficas de distribución de frecuencia

5.1 Histrograma

Histograma general

histograma_general <-hist(
  dioxido_azufre,
  main= "Gráfica Nº1: Distribución de frecuencia de Dióxiodo de Azufre en el 
  análisis sobre la calidad del aire en India 2015-2020",
  xlab= "Dióxido de azufre (µg/m3)",
  ylab= "Cantidad", col="blue",
)

Histograma simplificado

hist(
  dioxido_azufre,
  breaks = seq(minimo, maximo, A),
  main = "Gráfica Nº2: Distribución de frecuencia de Dióxiodo de azufre en el 
  análisis sobre la calidad del aire en India 2015-2020",
  xlab = "Dióxido de azufre (µg/m3)",
  ylab = "Cantidad",
  col = "lightgreen",
  cex.main = 1.1,
  cex.lab = 1.1
)

Histograma con relación al todo

hist(
  dioxido_azufre,
  breaks = seq(minimo, maximo, A),
  main = "Gráfica Nº3: Distribución de frecuencia de Dióxido de azufre en el
  análisis sobre la calidad del aire en India 2015-2020",
  xlab = "Dióxido de azufre (µg/m3)",
  ylab = "Cantidad",
  col = "skyblue",
  ylim = c(0, 30000),
  xlim = c(0, 150),
  cex.main = 1.1,
  cex.lab = 1.1
)

5.2 Histograma porcentual

Histograma porcentual simplificado

# Eliminar la fila total de la tabla
TDF_simplificada_completa_sintotal <- 
  TDF_simplificada_completa[
    TDF_simplificada_completa$Li != "Total", 
  ]

barplot(
  TDF_simplificada_completa_sintotal$hi,
  space = 0,
  col = "pink",
  main = "Gráfica Nº4: Diagrama porcentual de Dióxido de azufre en el 
  análisis sobre la calidad del aire en India 2015-2020",
  xlab = "Dióxido de azufre (µg/m3)",
  ylab = "Porcentaje",
  names.arg = TDF_simplificada_completa_sintotal$Mc,
  cex.names = 0.9,
  cex.main = 1.1,
  cex.lab = 1.1
)

Histograma porcentual con relación al todo

barplot(
  TDF_simplificada_completa_sintotal$hi,
  space = 0,
  col = "yellow",
  main = "Gráfica Nº5: Diagrama porcentual de Dióxido de azufre en el 
  análisis sobre la calidad del aire en India",
  xlab = "Dióxido de azufre (µg/m3)",
  ylab = "Porcentaje",
  names.arg = TDF_simplificada_completa_sintotal$Mc,
  ylim = c(0, 100),
  cex.names = 0.8,
  cex.main = 1.1,
  cex.lab = 1.1
)

5.3 Diagrama de caja

boxplot(dioxido_azufre,
        horizontal = TRUE,
        main = "Gráfica N°6: Diagrama de caja del Dióxido de azufre en el
        análisis sobre la calidad del aire en India 2015-2020",
        xlab = "Dióxido de azufre (µg/m3)",
        col = "orange",
        outline = TRUE)

summary(dioxido_azufre)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.01    5.67    9.16   14.53   15.22  193.86
# Valores atípicos
atipicos <- boxplot.stats(dioxido_azufre)$out
rango_atipicos <- range(atipicos)
print(rango_atipicos)
## [1]  29.56 193.86

5.4 Diagrama de Ojivas

# Recuperar de manera segura los datos exactos de la construcción manual (Sturges)
Li_graf <- TDF_dioxido_azufre$Li
Ls_graf <- TDF_dioxido_azufre$Ls
ni_graf <- TDF_dioxido_azufre$ni
hi_graf <- TDF_dioxido_azufre$hi

Ni_asc_graf <- TDF_dioxido_azufre$Ni_asc
Ni_dsc_graf <- TDF_dioxido_azufre$Ni_dsc
Hi_asc_graf <- TDF_dioxido_azufre$Hi_asc
Hi_dsc_graf <- TDF_dioxido_azufre$Hi_dsc

Ojivas Ascendentes y Descendentes (ni)

par(mar = c(5, 6, 4, 2) + 0.1)

x <- Ls_graf
marcas_x <- seq(0, max(Ls_graf), by = 20)

plot(
  x, Ni_asc_graf,
  type = "b",
  col = "skyblue",
  pch = 19,
  lwd = 2,
  main = "Gráfica N°7: Distribución de frecuencia ascendente y descendente de\n dióxido de azufre",
  xlab = "Dióxido de azufre (µg/m3)",
  ylab = "Cantidad",
  xlim = c(0, max(Ls_graf)),
  ylim = c(0, max(c(Ni_asc_graf, Ni_dsc_graf))),
  xaxt = "n",
  yaxt = "n",
  las = 1
)

lines(
  x, Ni_dsc_graf,
  type = "b",
  col = "red",
  pch = 19,
  lwd = 2
)

axis(
  1,
  at = marcas_x,
  labels = marcas_x,
  las = 1,
  cex.axis = 0.9
)

marcas_y <- pretty(c(0, max(c(Ni_asc_graf, Ni_dsc_graf))))

axis(
  2,
  at = marcas_y,
  labels = marcas_y,
  las = 1,
  cex.axis = 0.9
)

grid(
  nx = NULL,
  ny = NA,
  col = "gray85",
  lty = 1
)

legend(
  "right",
  legend = c(
    "Ascendente",
    "Descendente"
  ),
  col = c("skyblue", "red"),
  pch = 19,
  lty = 1,
  lwd = 2,
  seg.len = 1.2,
  bty = "n",
  cex = 0.9
)

Ojivas Ascendentes y Descendentes (hi)

par(mar = c(5, 6, 4, 2) + 0.1)

x <- Ls_graf 
marcas_x <- seq(0, max(x), by = 20) 

plot(
  x, Hi_asc_graf,
  type = "b",
  col = "skyblue",
  pch = 19,
  lwd = 2,
  main = "Gráfica N°8: Distribución porcentual ascendente y descendente de\n dióxido de azufre",
  xlab = "Dióxido de azufre (µg/m3)",
  ylab = "Porcentaje",
  xlim = c(0, max(x)), 
  ylim = c(0, 100),    
  xaxt = "n",
  yaxt = "n",
  las = 1
)

lines(
  x, Hi_dsc_graf,
  type = "b",
  col = "red",
  pch = 19,
  lwd = 2
)

axis(
  1,
  at = marcas_x,
  labels = marcas_x,
  las = 1,
  cex.axis = 0.9
)

marcas_y <- pretty(c(0, 100))

axis(
  2,
  at = marcas_y,
  labels = marcas_y,
  las = 1,
  cex.axis = 0.9
)

grid(
  nx = NULL,
  ny = NA,
  col = "gray85",
  lty = 1
)

legend(
  "right",
  legend = c(
    "Ascendente",
    "Descendente"
  ),
  col = c("skyblue", "red"),
  pch = 19,
  lty = 1,
  lwd = 2,
  seg.len = 1.2,
  bty = "n",
  cex = 0.9
)

6.- Indicadores Estadísticos

6.1 Indicadores de Tendencia Central

# Media aritmética
media <- round(mean(dioxido_azufre), 2)
media
## [1] 14.53
# Mediana
mediana <- median(dioxido_azufre)
mediana
## [1] 9.16
# Moda
max_ni <- max(TDF_dioxido_azufre$ni)
moda <- TDF_dioxido_azufre$Mc[TDF_dioxido_azufre$ni == max_ni]
moda
## [1] 6.935

6.2 Indicadores de Dispersión

# Varianza
varianza <- var(dioxido_azufre)
varianza
## [1] 328.8338
# Desviación estándar
sd <- sd(dioxido_azufre)
sd
## [1] 18.13377
# Coeficiente de variación
cv <- round((sd / media) * 100, 2)
cv
## [1] 124.8

6.3 Indicadores de Forma

# Asimetría
library(e1071)
asimetria <- skewness(dioxido_azufre, type = 2)
asimetria
## [1] 4.08366
# Curtosis
curtosis <- kurtosis(dioxido_azufre)
curtosis
## [1] 22.06062
tabla_indicadores <- data.frame(
  "Variable" = c("Dióxido de azufre"),
  "Rango" = paste0("[",
                   min(dioxido_azufre), ";",
                   max(dioxido_azufre), "]"),
  "X" = media,
  "Me" = round(mediana, 2),
  "Mo" = moda,
  "V" = round(varianza, 2),
  "Sd" = round(sd, 2),
  "Cv" = cv,
  "As" = round(asimetria, 2),
  "K" = round(curtosis, 2),
  "Valores Atípicos" = "[29.56;193.86]" # Ajusta este rango si calculaste nuevos atípicos para el azufre
)

library(knitr)

kable(
  tabla_indicadores,
  align = "c",
  caption = "Conclusiones de la variable Dióxido de azufre"
)
Conclusiones de la variable Dióxido de azufre
Variable Rango X Me Mo V Sd Cv As K Valores.Atípicos
Dióxido de azufre [0.01;193.86] 14.53 9.16 6.935 328.83 18.13 124.8 4.08 22.06 [29.56;193.86]

7.- Conclusión

La variable Dióxido de Azufre (\(SO_2\)) fluctúa entre un mínimo de 0.01 y un máximo de 193.86 (\(\mu g/m^3\)), con una media de 9.16 y una desviación estándar de 18.13.
Debido a un coeficiente de variación del 124.8%, se concluye que es un conjunto de valores muy heterogéneo con una alta dispersión. Los datos se acumulan de manera predominante en el primer intervalo [0.01 - 13.86). No obstante, se han detectado valores atípicos en el intervalo [29.56 ; 193.86], los cuales representan picos de contaminación que pueden afectar moderadamente al medio ambiente.