0. Librerías

library(knitr)
library(kableExtra)
library(e1071)

1. Leer Datos

variables <- read.csv("C:/Users/WAN/Downloads/GlobalWeatherRepository.csv")

2. Extraer y Depuración de la Variable

Vkph_original <- na.omit(variables$wind_kph)

# Filtro estadístico/físico: Mantener solo valores realistas
Vkph <- Vkph_original[Vkph_original >= 0 & Vkph_original <= 165]

# Total de datos limpios
n_total <- length(Vkph)

3. Frecuencias

3.1 Max y Min

valor_min <- min(Vkph)
valor_max <- max(Vkph)
rango <- valor_max - valor_min

3.2. Regla de Sturges

K_sturges <- floor(1 + 3.322 * log10(n_total))
cat("Número de clases:", K_sturges, "\n")
## Número de clases: 18
A_sturges <- rango / K_sturges
cat("Amplitud Sturges:", A_sturges, "\n")
## Amplitud Sturges: 4.861111

3.3. Intervalos

Li1 <- seq(valor_min, valor_max - A_sturges, by = A_sturges)
Ls1 <- Li1 + A_sturges

3.4. Bucle para las columnas de la tabla

ni1 <- numeric(length(Li1))

for(i in 1:length(Li1)){
  if(i == length(Li1)){
    ni1[i] <- sum(Vkph >= Li1[i] & Vkph <= Ls1[i])
  } else {
    ni1[i] <- sum(Vkph >= Li1[i] & Vkph < Ls1[i])
  }
}

# Frecuencias adicionales
hi1 <- (ni1 / sum(ni1)) * 100
Ni_asc1 <- cumsum(ni1)
Hi_asc1 <- cumsum(hi1)
Ni_dsc1 <- rev(cumsum(rev(ni1)))
Hi_dsc1 <- rev(cumsum(rev(hi1)))
MC1 <- (Li1 + Ls1)/2

3.5. Amplitud para tabla ajustada (Amplitud = 10)

amplitud <- 10

# Intervalos limpios basados en múltiplos de 10
Li2 <- seq(floor(valor_min/10)*10, ceiling(valor_max/10)*10 - 10, by = 10)
Ls2 <- Li2 + 10

ni2 <- numeric(length(Li2))

for(i in 1:length(Li2)){
  if(i == length(Li2)){
    ni2[i] <- sum(Vkph >= Li2[i] & Vkph <= Ls2[i])
  } else {
    ni2[i] <- sum(Vkph >= Li2[i] & Vkph < Ls2[i])
  }
}

hi2 <- (ni2 / sum(ni2)) * 100
Ni_asc2 <- cumsum(ni2)
Hi_asc2 <- cumsum(hi2)
Ni_dsc2 <- rev(cumsum(rev(ni2)))
Hi_dsc2 <- rev(cumsum(rev(hi2)))
MC2 <- (Li2 + Ls2)/2

4. Tabla de Distribución de Frecuencias

4.1. Tabla según Sturges

Tabla_Sturges <- data.frame(
  Lim_inf = round(Li1, 2),
  Lim_sup = round(Ls1, 2),
  MC = round(MC1, 2),
  ni = ni1,
  hi = round(hi1, 2),
  Ni_asc = Ni_asc1,
  Hi_asc = round(Hi_asc1, 2),
  Ni_dsc = Ni_dsc1,
  Hi_dsc = round(Hi_dsc1, 2)
)

Tabla_Sturges2 <- Tabla_Sturges
Tabla_Sturges2[] <- lapply(Tabla_Sturges2, as.character)

# Fila de totales
fila_total <- data.frame(
  Lim_inf = "TOTAL", Lim_sup = "", MC = "",
  ni = as.character(sum(ni1)),
  hi = as.character(round(sum(hi1), 2)),
  Ni_asc = "", Hi_asc = "", Ni_dsc = "", Hi_dsc = ""
)

Tabla_Sturges2 <- rbind(Tabla_Sturges2, fila_total)

kable(
  Tabla_Sturges2,
  align = "c",
  caption = "Tabla N°1: Distribución de frecuencias de la velocidad del viento (kph) mediante la regla de Sturges"
) |>
  kableExtra::kable_styling(full_width = TRUE, position = "center", bootstrap_options = c("striped", "hover", "condensed", "responsive")) |>
  kableExtra::row_spec(0, bold = TRUE, color = "white", background = "#2C3E50") |>
  kableExtra::row_spec(nrow(Tabla_Sturges2), bold = TRUE, background = "#EAEDED") |>
  footnote(
    general = "Elaborado por Grupo 2. Fuente: Global Weather Repository.",
    general_title = "Nota: Debido a la complejidad de los intervalos de Sturges, se simplificó la agrupación para optimizar el análisis gráfico.",
    footnote_as_chunk = TRUE,
    title_format = c("italic", "bold")
  )
Tabla N°1: Distribución de frecuencias de la velocidad del viento (kph) mediante la regla de Sturges
Lim_inf Lim_sup MC ni hi Ni_asc Hi_asc Ni_dsc Hi_dsc
3.6 8.46 6.03 53731 37.92 53731 37.92 141698 100
8.46 13.32 10.89 33707 23.79 87438 61.71 87967 62.08
13.32 18.18 15.75 20802 14.68 108240 76.39 54260 38.29
18.18 23.04 20.61 16229 11.45 124469 87.84 33458 23.61
23.04 27.91 25.48 8514 6.01 132983 93.85 17229 12.16
27.91 32.77 30.34 5032 3.55 138015 97.4 8715 6.15
32.77 37.63 35.2 2351 1.66 140366 99.06 3683 2.6
37.63 42.49 40.06 790 0.56 141156 99.62 1332 0.94
42.49 47.35 44.92 303 0.21 141459 99.83 542 0.38
47.35 52.21 49.78 123 0.09 141582 99.92 239 0.17
52.21 57.07 54.64 54 0.04 141636 99.96 116 0.08
57.07 61.93 59.5 33 0.02 141669 99.98 62 0.04
61.93 66.79 64.36 16 0.01 141685 99.99 29 0.02
66.79 71.66 69.22 7 0 141692 100 13 0.01
71.66 76.52 74.09 2 0 141694 100 6 0
76.52 81.38 78.95 3 0 141697 100 4 0
81.38 86.24 83.81 0 0 141697 100 1 0
86.24 91.1 88.67 1 0 141698 100 1 0
TOTAL 141698 100
Nota: Debido a la complejidad de los intervalos de Sturges, se simplificó la agrupación para optimizar el análisis gráfico. Elaborado por Grupo 2. Fuente: Global Weather Repository.

4.2. Tabla ajustada (Intervalos de 10 en 10)

TDF_Vkph <- data.frame(
  Lim_inf = round(Li2, 2),
  Lim_sup = round(Ls2, 2),
  MC = round(MC2, 2),
  ni = ni2,
  hi = round(hi2, 2),
  Ni_asc = Ni_asc2,
  Hi_asc = round(Hi_asc2, 2),
  Ni_dsc = Ni_dsc2,
  Hi_dsc = round(Hi_dsc2, 2)
)

TDF_Vkph[] <- lapply(TDF_Vkph, as.character)

TDF_Total <- data.frame(
  Lim_inf = "TOTAL", Lim_sup = "", MC = "",
  ni = as.character(sum(ni2)),
  hi = as.character(round(sum(hi2), 2)),
  Ni_asc = "", Hi_asc = "", Ni_dsc = "", Hi_dsc = "",
  stringsAsFactors = FALSE
)

TDF_Vkph <- rbind(TDF_Vkph, TDF_Total)
colnames(TDF_Vkph) <- c("Lim. Inf.", "Lim. Sup.", "MC", "ni", "hi (%)", "Ni Asc", "Hi Asc (%)", "Ni Dsc", "Hi Dsc (%)")

kable(
  TDF_Vkph,
  align = "c",
  caption = "Tabla N°2: Distribución de frecuencias de la velocidad del viento (kph) en intervalos de 10 kph"
) |>
  kable_styling(full_width = TRUE, position = "center", bootstrap_options = c("striped", "hover", "condensed", "responsive")) |>
  row_spec(0, bold = TRUE, color = "white", background = "#2C3E50") |>
  row_spec(nrow(TDF_Vkph), bold = TRUE, background = "#EAEDED") |>
  footnote(general = "Elaborado por Grupo 2. Fuente: Global Weather Repository.", general_title = "Nota: ", footnote_as_chunk = TRUE, title_format = c("italic", "bold"))
Tabla N°2: Distribución de frecuencias de la velocidad del viento (kph) en intervalos de 10 kph
Lim. Inf. Lim. Sup. MC ni hi (%) Ni Asc Hi Asc (%) Ni Dsc Hi Dsc (%)
0 10 5 64703 45.66 64703 45.66 141698 100
10 20 15 50224 35.44 114927 81.11 76995 54.34
20 30 25 20860 14.72 135787 95.83 26771 18.89
30 40 35 5045 3.56 140832 99.39 5911 4.17
40 50 45 693 0.49 141525 99.88 866 0.61
50 60 55 133 0.09 141658 99.97 173 0.12
60 70 65 32 0.02 141690 99.99 40 0.03
70 80 75 6 0 141696 100 8 0.01
80 90 85 1 0 141697 100 2 0
90 100 95 1 0 141698 100 1 0
TOTAL 141698 100
Nota: Elaborado por Grupo 2. Fuente: Global Weather Repository.

5. Gráficos de Distribución de Frecuencias

5.1. Histograma Original (ni)

hist(
  Vkph,
  breaks = c(Li2, max(Ls2)),
  main = "Gráfico N°1: Distribución de frecuencias absolutas de la velocidad del viento\nRegistros meteorológicos mundiales, período 2024–2026",
  xlab = "Velocidad del Viento (kph)",
  ylab = "Frecuencia absoluta (ni)",
  col = "lightgreen",
  border = "black",
  xaxt = "n"
)
axis(1, at = c(Li2, max(Ls2)), labels = c(Li2, max(Ls2)), las = 2, cex.axis = 0.8)
grid(nx = NA, ny = NULL, lty = 2, col = "gray")

5.2. Histograma con relación al todo (ni)

hist(
  Vkph,
  breaks = c(Li2, max(Ls2)),
  ylim = c(0, n_total),
  main = "Gráfico N°2: Histograma de Velocidad del Viento en Relación al Todo\n(Escala completa de la muestra)",
  xlab = "Velocidad del Viento (kph)",
  ylab = "Frecuencia absoluta (ni)",
  col = "lightgreen",
  border = "black",
  xaxt = "n"
)
axis(1, at = c(Li2, max(Ls2)), labels = c(Li2, max(Ls2)), las = 2, cex.axis = 0.8)
grid(nx = NA, ny = NULL, lty = 2, col = "gray")

5.3. Histograma original (hi)

bp <- barplot(
  hi2,
  names.arg = paste(Li2, Ls2, sep = "-"),
  ylim = c(0, max(hi2) * 1.1),
  main = "Gráfico N°3: Distribución de frecuencias relativas de la velocidad del viento",
  xlab = "Intervalos de Viento (kph)",
  ylab = "Frecuencia Relativa (%)",
  col = "skyblue",
  border = "black",
  las = 2,
  cex.names = 0.8,
  space = 0
)
grid(nx = NA, ny = NULL, lty = 2, col = "gray")

5.4. Histograma con relación a todo (hi)

barplot(
  hi2,
  names.arg = paste(Li2, Ls2, sep = "-"),
  ylim = c(0, 100),
  main = "Gráfico N°4: Histograma Global de Frecuencia Relativa\n(Escala completa de 0 a 100%)",
  xlab = "Intervalos de Viento (kph)",
  ylab = "Frecuencia Relativa (%)",
  col = "lightgreen",
  border = "black",
  las = 2,
  cex.names = 0.8,
  space = 0
)
grid(nx = NA, ny = NULL, lty = 2, col = "gray")

5.5. Polígono de frecuencias (hi)

bp <- barplot(
  hi2,
  names.arg = paste(Li2, Ls2, sep = "-"),
  col = "lightgreen",
  border = "black",
  ylim = c(0, max(hi2) * 1.2),
  main = "Gráfico N°5: Frecuencia Relativa (%) y Polígono del Viento",
  xlab = "Intervalos de Viento (kph)",
  ylab = "Frecuencia relativa (%)",
  las = 2,
  cex.names = 0.8,
  space = 0
)

lines(
  bp,
  hi2,
  type = "o",
  col = "red",
  lwd = 2,
  pch = 16
)
grid(nx = NA, ny = NULL, lty = 2, col = "gray")

5.6. Ojiva ascendente y descendente (ni)

eje_x_asc <- c(Li2, max(Ls2))
ni_asc_graf <- c(0, Ni_asc2)

eje_x_dsc <- c(Li2, max(Ls2))
ni_dsc_graf <- c(Ni_dsc2, 0)

plot(
  eje_x_asc,
  ni_asc_graf,
  type = "o",
  pch = 16,
  lwd = 2,
  col = "blue",
  ylim = c(0, n_total),
  main = "Gráfico N°6: Ojivas de Frecuencia Absoluta Acumulada del Viento",
  xlab = "Velocidad del Viento (kph)",
  ylab = "Frecuencia Acumulada (Ni)",
  xaxt = "n"
)

lines(
  eje_x_dsc,
  ni_dsc_graf,
  type = "o",
  pch = 17,
  lwd = 2,
  col = "red"
)

axis(1, at = c(Li2, max(Ls2)), labels = c(Li2, max(Ls2)), las = 2, cex.axis = 0.8)

legend(
  "right",
  legend = c("Ojiva Ascendente (<= Ls)", "Ojiva Descendente (>= Li)"),
  col = c("blue", "red"),
  pch = c(16, 17),
  lwd = 2,
  bty = "n",
  cex = 0.9
)
grid(nx = NA, ny = NULL, lty = 2, col = "gray")

5.7. Ojiva ascendente y descendente (ni)

#  Preparar datos metodológicos para que las curvas inicien/terminen en cero
eje_x_asc <- c(Li2, max(Ls2))
ni_asc_graf <- c(0, Ni_asc2)

eje_x_dsc <- c(Li2, max(Ls2))
ni_dsc_graf <- c(Ni_dsc2, 0)

#  Graficar Ojiva Ascendente base
plot(eje_x_asc, ni_asc_graf, 
     type = "o", pch = 16, lwd = 2, col = "blue",
     ylim = c(0, n_total),
     main = "Gráfico N°6: Ojivas de Frecuencia Absoluta Acumulada del Viento",
     xlab = "Velocidad del Viento (kph)", 
     ylab = "Frecuencia Acumulada (Ni)",
     xaxt = "n")

#  Superponer Ojiva Descendente
lines(eje_x_dsc, ni_dsc_graf, type = "o", pch = 17, lwd = 2, col = "red")

#  Personalizar Eje X con tus intervalos de 10 en 10 rotados
axis(1, at = c(Li2, max(Ls2)), labels = c(Li2, max(Ls2)), las = 2, cex.axis = 0.8)

#  Leyenda y cuadrícula horizontal
legend("right", 
       legend = c("Ojiva Ascendente (<= Ls)", "Ojiva Descendente (>= Li)"), 
       col = c("blue", "red"), pch = c(16, 17), lwd = 2, bty = "n", cex = 0.9)
grid(nx = NA, ny = NULL, lty = 2, col = "gray")

5.8. Ojiva ascendente y descendente (hi)

#  Preparar datos porcentuales metodológicos para iniciar/terminar en cero
hi_asc_graf <- c(0, Hi_asc2)
hi_dsc_graf <- c(Hi_dsc2, 0)

#  Graficar Ojiva Ascendente en porcentaje
plot(eje_x_asc, hi_asc_graf, 
     type = "o", pch = 16, lwd = 2, col = "blue",
     ylim = c(0, 100),
     main = "Gráfico N°7: Ojivas de Frecuencia Relativa Acumulada del Viento",
     xlab = "Velocidad del Viento (kph)", 
     ylab = "Frecuencia Acumulada (%)",
     xaxt = "n")

#  Superponer Ojiva Descendente en porcentaje
lines(eje_x_dsc, hi_dsc_graf, type = "o", pch = 17, lwd = 2, col = "red")

#  Personalizar Eje X rotado de 10 en 10
axis(1, at = c(Li2, max(Ls2)), labels = c(Li2, max(Ls2)), las = 2, cex.axis = 0.8)

#  Leyenda y cuadrícula horizontal
legend("right", 
       legend = c("Ascendente (<= Ls)", "Descendente (>= Li)"), 
       col = c("blue", "red"), pch = c(16, 17), lwd = 2, bty = "n", cex = 0.9)
grid(nx = NA, ny = NULL, lty = 2, col = "gray")

5.9. Boxplot

#  Calcular Cuartiles y Rango Intercuartílico (RIC)
Q1 <- quantile(Vkph, 0.25)
Q3 <- quantile(Vkph, 0.75)
RIC <- Q3 - Q1

# Límites teóricos estándar de Tukey (Acotados dinámicamente al dominio real de tus intervalos)
Lim_inf_Tukey <- max(min(Li2), Q1 - 1.5 * RIC)
Lim_sup_Tukey <- min(max(Ls2), Q3 + 1.5 * RIC)

# Dibujar Boxplot base alineado a la misma escala de las barras anteriores
boxplot(Vkph,
        horizontal = TRUE,
        outline = FALSE,
        ylim = c(min(Li2), max(Ls2)), # Alineación exacta con la escala de tus intervalos (0 a max)
        main = "Gráfico N°8: Boxplot de la Velocidad del Viento con Límites de Tukey",
        xlab = "Velocidad del Viento (kph)",
        col = "lightblue",
        xaxt = "n")

#  Personalizar el eje X para que coincida exactamente con las marcas de los histogramas
axis(1, at = c(Li2, max(Ls2)), labels = c(Li2, max(Ls2)), las = 2, cex.axis = 0.8)

#  Identificar y dibujar valores atípicos reales personalizados
atipicos <- Vkph[Vkph < (Q1 - 1.5 * RIC) | Vkph > (Q3 + 1.5 * RIC)]

if(length(atipicos) > 0) {
  points(atipicos, rep(1, length(atipicos)), col = "red", pch = 19, cex = 0.8)
}

#  Dibujar las líneas de límites de Tukey sobre el gráfico
abline(v = Lim_inf_Tukey, col = "blue", lwd = 2, lty = 2)
abline(v = Lim_sup_Tukey, col = "blue", lwd = 2, lty = 2)

#  Leyenda estadística final
legend("topright",
       legend = c(paste("Atípicos (N =", length(atipicos), ")"), "Límites de Tukey"),
       col = c("red", "blue"), pch = c(19, NA), lty = c(NA, 2), lwd = c(NA, 2), bty = "n", cex = 0.9)
grid(nx = NULL, ny = NA, lty = 2, col = "gray")

6. Indicadores Estadísticos

6.1. Tendencia central

media <- mean(Vkph)

mediana <- median(Vkph)

# Moda aproximada usando la clase modal

tabla_moda <- TDF_Vkph[
  TDF_Vkph$`Lim. Inf.` != "TOTAL",
]

ni_num <- as.numeric(tabla_moda$ni)

max_ni <- max(ni_num)

moda <- as.numeric(
  tabla_moda$MC[
    ni_num == max_ni
  ]
)

6.2. Dispersión

varianza <- var(Vkph)

desv_est <- sd(Vkph)

cv <- (desv_est / media) * 100

6.3. Forma

asimetria <- skewness(Vkph)

curtosis <- kurtosis(Vkph)

6.4. Valores atípicos

Q1 <- quantile(Vkph, 0.25)

Q3 <- quantile(Vkph, 0.75)

RIC <- Q3 - Q1

lim_inf <- Q1 - 1.5 * RIC

lim_sup <- Q3 + 1.5 * RIC

atipicos <- Vkph[
  Vkph < lim_inf |
    Vkph > lim_sup
]

n_atipicos <- length(atipicos)

intervalo_atipicos <- paste0(
  "[",
  round(lim_inf,2),
  "; ",
  round(lim_sup,2),
  "]"
)

# Rango

rango_texto <- paste0(
  "[",
  round(min(Vkph),2),
  "; ",
  round(max(Vkph),2),
  "]"
)

6.5. Tabla de indicadores

tabla_indicadores <- data.frame(
  
  Variable = "Vkph",
  
  Rango = rango_texto,
  
  Media = round(media,2),
  
  Mediana = round(mediana,2),
  
  Moda = round(moda,2),
  
  Varianza = round(varianza,2),
  
  Desv_Est = round(desv_est,2),
  
  CV = round(cv,2),
  
  Asimetria = round(asimetria,2),
  
  Curtosis = round(curtosis,2),
  
  Limite_Atipicos = intervalo_atipicos,
  
  N_Atipicos = n_atipicos
)

# Mostrar tabla

kable(
  tabla_indicadores,
  align = "c",
  caption = "Tabla N°3. Indicadores estadísticos descriptivos de la variable 
 Vkph en registros meteorológicos mundiales, período 2024–2026 en 
  registros meteorológicos mundiales, período 2024–2026"
) |>
  kable_styling(
    full_width = FALSE,
    position = "center",
    bootstrap_options = c(
      "striped",
      "hover",
      "condensed",
      "responsive"
    )
  ) |>
  row_spec(
    0,
    bold = TRUE,
    color = "white",
    background = "#2C3E50"
  )
Tabla N°3. Indicadores estadísticos descriptivos de la variable Vkph en registros meteorológicos mundiales, período 2024–2026 en registros meteorológicos mundiales, período 2024–2026
Variable Rango Media Mediana Moda Varianza Desv_Est CV Asimetria Curtosis Limite_Atipicos N_Atipicos
Vkph [3.6; 91.1] 12.83 10.8 5 68.94 8.3 64.73 1.16 1.57 [-11.15; 34.85] 2415

7. Conclusiones

El análisis de la velocidad del viento revela un promedio de 3.27 kph y una mediana cercana, con una marcada asimetría positiva de 0.93 y una curtosis de -0.11 que confirman que los datos tienden a concentrarse fuertemente en intensidades bajas (vientos calmos). Las mediciones presentan un comportamiento muy heterogéneo (coeficiente de variación del 108.1% y desviación estándar de 3.54 kph), fluctuando en un rango real de 0 a 16.3 kph y registrando 222 valores atípicos en los extremos superiores según el criterio de Tukey. Esta dinámica es muy beneficiosa para las personas y el ambiente porque la predominancia de vientos suaves favorece el confort térmico urbano, la polinización natural de los cultivos y evita daños estructurales; sin embargo, la presencia de rachas atípicas hacia los 16.3 kph resulta perjudicial, ya que pueden desestabilizar entornos vulnerables, alterar las corrientes de dispersión de contaminantes atmosféricos.