# 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$Xylene[datos$Xylene == "-"] <- NA
datos$Xylene <- as.numeric(datos$Xylene)

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

# Tamaño de muestra
n <- length(xileno)
n
## [1] 11422

3.- Conteo (frecuencia)

Construcción manual (Regla de Sturges)

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

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(xileno >= Li[i] & 
                   xileno < Ls[i])
  } else {
    ni[i] <- sum(xileno >= Li[i] & 
                   xileno <= 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_xileno <-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_xileno_completo <- rbind(
  TDF_xileno,
  data.frame(
    Li = "Total",
    Ls = "-",
    Mc = "-",
    ni = total_ni,
    hi = total_hi,
    Ni_asc = "-",
    Ni_dsc = "-",
    Hi_asc = "-",
    Hi_dsc = "-"
  )
)

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

tabla_xileno <- TDF_xileno_completo %>%
  gt() %>%
  
  fmt_number(
    columns = hi,
    decimals = 2
  ) %>%
  
  tab_header(
    title = md("*Tabla Nº1*"),
    subtitle = md(
      "**Distribución de frecuencia de Xileno 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_xileno
Tabla Nº1
Distribución de frecuencia de Xileno 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 13.11 6.555 10892 95.36 10892 11422 95.36 100
13.11 26.21 19.66 409 3.58 11301 530 98.94 4.64
26.21 39.32 32.765 71 0.62 11372 121 99.56 1.06
39.32 52.42 45.87 27 0.24 11399 50 99.8 0.44
52.42 65.53 58.975 11 0.10 11410 23 99.9 0.2
65.53 78.63 72.08 2 0.02 11412 12 99.92 0.1
78.63 91.74 85.185 3 0.03 11415 10 99.95 0.08
91.74 104.84 98.29 1 0.01 11416 7 99.96 0.05
104.84 117.95 111.395 3 0.03 11419 6 99.99 0.04
117.95 131.05 124.5 1 0.01 11420 3 100 0.01
131.05 144.16 137.605 1 0.01 11421 2 100.01 0
144.16 157.26 150.71 0 0.00 11421 1 100.01 -0.01
157.26 170.37 163.815 0 0.00 11421 1 100.01 -0.01
170.37 170.37 170.37 1 −0.01 11422 1 100 -0.01
Total - - 11422 100.00 - - - -
Autor: Grupo 1

4.2 Tabla simplificada

histograma_simplificado <- hist(
  xileno,
  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 Xileno 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 Xileno 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 11198 98.04 11198 11422 98.04 100
20 40 30 177 1.55 11375 224 99.59 1.96
40 60 50 32 0.28 11407 47 99.87 0.41
60 80 70 5 0.04 11412 15 99.91 0.13
80 100 90 4 0.04 11416 10 99.95 0.09
100 120 110 3 0.03 11419 6 99.98 0.05
120 140 130 2 0.02 11421 3 100 0.02
140 160 150 0 0.00 11421 1 100 0
160 180 170 1 0.00 11422 1 100 0
Total - - 11422 100.00 - - - -
Autor:Grupo 1

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

5.1 Histrograma

Histograma general

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

Histograma simplificado

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

Histograma con relación al todo

hist(
  xileno,
  breaks = seq(minimo, maximo, A),
  main = "Gráfica Nº3: Distribución de frecuencia de Xileno en el
  análisis sobre la calidad del aire en India 2015-2020",
  xlab = "Xileno (µ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 Xileno en el 
  análisis sobre la calidad del aire en India 2015-2020",
  xlab = "Xileno (µ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 Xileno en el 
  análisis sobre la calidad del aire en India",
  xlab = "Xileno (µ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(xileno,
        horizontal = TRUE,
        main = "Gráfica N°6: Diagrama de caja del Xileno en el
        análisis sobre la calidad del aire en India 2015-2020",
        xlab = "Xileno (µg/m3)",
        col = "orange",
        outline = TRUE)

summary(xileno)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00    0.14    0.98    3.07    3.35  170.37
# Valores atípicos
atipicos <- boxplot.stats(xileno)$out
rango_atipicos <- range(atipicos)
print(rango_atipicos)
## [1]   8.17 170.37

5.4 Diagrama de Ojivas

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

Ni_asc_graf <- TDF_xileno$Ni_asc
Ni_dsc_graf <- TDF_xileno$Ni_dsc
Hi_asc_graf <- TDF_xileno$Hi_asc
Hi_dsc_graf <- TDF_xileno$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 xileno",
  xlab = "Xileno (µ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 xileno",
  xlab = "Xileno (µ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(xileno), 2)
media
## [1] 3.07
# Mediana
mediana <- median(xileno)
mediana
## [1] 0.98
# Moda
max_ni <- max(TDF_xileno$ni)
moda <- TDF_xileno$Mc[TDF_xileno$ni == max_ni]
moda
## [1] 6.555

6.2 Indicadores de Dispersión

# Varianza
varianza <- var(xileno)
varianza
## [1] 39.98346
# Desviación estándar
sd <- sd(xileno)
sd
## [1] 6.323247
# Coeficiente de variación
cv <- round((sd / media) * 100, 2)
cv
## [1] 205.97

6.3 Indicadores de Forma

# Asimetría
library(e1071)
asimetria <- skewness(xileno, type = 2)
asimetria
## [1] 7.891515
# Curtosis
curtosis <- kurtosis(xileno)
curtosis
## [1] 119.9056
tabla_indicadores <- data.frame(
  "Variable" = c("Xileno"),
  "Rango" = paste0("[",
                   min(xileno), ";",
                   max(xileno), "]"),
  "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" = "[8.17;170.37]" 
)

library(knitr)

kable(
  tabla_indicadores,
  align = "c",
  caption = "Conclusiones de la variable Xileno"
)
Conclusiones de la variable Xileno
Variable Rango X Me Mo V Sd Cv As K Valores.Atípicos
Xileno [0;170.37] 3.07 0.98 6.555 39.98 6.32 205.97 7.89 119.91 [8.17;170.37]

7.- Conclusión

La variable Xileno fluctúa entre un mínimo de 0 y un máximo de 170.37 (\(\mu g/m^3\)), con una media de 0.98 y una desviación estándar de 6.32. Debido a un coeficiente de variación del 205.97%, 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 - 13.11). No obstante, se han detectado valores atípicos en el intervalo [8.17 ; 170.37], los cuales representan picos de contaminación que pueden afectar moderadamente al medio ambiente.