0.- Librerías

library(readr)
library(dplyr)
library(knitr)
library(kableExtra)
library(ggplot2)
library(e1071)

1.- leer datos

variables <- read_csv("C:/Users/CESAR/Downloads/proyecto x/GlobalWeatherRepository.csv", show_col_types = TRUE)

2.- Depuración y selección de la variable

Depuración

variables <- na.omit(variables)

Selección

Nubosidad <- variables$cloud

3.- Frecuencias

Min y max

n_total <- length(Nubosidad)

valor_min <- min(Nubosidad, na.rm = TRUE)
valor_max <- max(Nubosidad, na.rm = TRUE)
rango <- valor_max - valor_min
n_total <- length(Nubosidad)
n_total
## [1] 141703

Regla de sturges

K_sturges <- floor(1 + 3.322 * log10(n_total))
K_sturges
## [1] 18
A_sturges <- rango / K_sturges
A_sturges
## [1] 5.555556

Intervalos

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

Ls1 <- Li1 + A_sturges

Bucle para columnas

ni1 <- numeric(length(Li1))

for(i in 1:length(Li1)){
  if(i == length(Li1)){
    ni1[i] <- sum(
      Nubosidad >= Li1[i] &
        Nubosidad <= Ls1[i],
      na.rm = TRUE
    )
  } else {
    ni1[i] <- sum(
      Nubosidad >= Li1[i] &
        Nubosidad < Ls1[i],
      na.rm = TRUE
    )
  }
}

# Frecuencia relativa
hi1 <- (ni1 / sum(ni1)) * 100

# Acumuladas
Ni_asc1 <- cumsum(ni1)
Hi_asc1 <- cumsum(hi1)

Ni_dsc1 <- rev(cumsum(rev(ni1)))
Hi_dsc1 <- rev(cumsum(rev(hi1)))

# Marca de clase
MC1 <- (Li1 + Ls1) / 2

4.- Tablas de distribución de frecuencia

TDF 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)
)

# Convertir a caracteres para poder mezclar números y texto con la fila TOTAL
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 = ""
)

# Agregar fila de totales
Tabla_Sturges2 <- rbind(Tabla_Sturges2, fila_total)

# Renderizado estético de la tabla con kableExtra
kable(
  Tabla_Sturges2,
  align = "c",
  caption = "Tabla N2: Distribución de frecuencias de cobertura de nubes de los registros meteorológicos mundiales mediante la regla de Sturges, período 2024-2026"
) |> 
  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.\nFuente: Global Weather Repository.",
    general_title = "Nota: ",
    footnote_as_chunk = TRUE,
    title_format = c("italic", "bold")
  )
Tabla N2: Distribución de frecuencias de cobertura de nubes de los registros meteorológicos mundiales mediante la regla de Sturges, período 2024-2026
Lim_inf Lim_sup MC ni hi Ni_asc Hi_asc Ni_dsc Hi_dsc
0 5.56 2.78 41110 29.01 41110 29.01 141703 100
5.56 11.11 8.33 4204 2.97 45314 31.98 100593 70.99
11.11 16.67 13.89 2230 1.57 47544 33.55 96389 68.02
16.67 22.22 19.44 2060 1.45 49604 35.01 94159 66.45
22.22 27.78 25 20834 14.7 70438 49.71 92099 64.99
27.78 33.33 30.56 1394 0.98 71832 50.69 71265 50.29
33.33 38.89 36.11 1085 0.77 72917 51.46 69871 49.31
38.89 44.44 41.67 954 0.67 73871 52.13 68786 48.54
44.44 50 47.22 1111 0.78 74982 52.91 67832 47.87
50 55.56 52.78 17927 12.65 92909 65.57 66721 47.09
55.56 61.11 58.33 1794 1.27 94703 66.83 48794 34.43
61.11 66.67 63.89 1201 0.85 95904 67.68 47000 33.17
66.67 72.22 69.44 2128 1.5 98032 69.18 45799 32.32
72.22 77.78 75 26817 18.92 124849 88.11 43671 30.82
77.78 83.33 80.56 2935 2.07 127784 90.18 16854 11.89
83.33 88.89 86.11 2287 1.61 130071 91.79 13919 9.82
88.89 94.44 91.67 934 0.66 131005 92.45 11632 8.21
94.44 100 97.22 10698 7.55 141703 100 10698 7.55
TOTAL 141703 100
Nota: Elaborado por Grupo 2.
Fuente: Global Weather Repository.

Devido a la tabla de propuesta es dificil de interpretar nace la tabla de distribución de frecuencia simplificada

TDF simplificada

Nubosidad_N<- variables$cloud
Li1 <- seq(0, 90, by = 10)  # Empieza en -25 y el último límite inferior es 150
Ls1 <- seq(10, 100, by = 10)   # Empieza en 0 y el último límite superior es 175

# 3.4 Bucle para el conteo de frecuencias en los intervalos definidos
ni1 <- numeric(length(Li1))

for(i in 1:length(Li1)){
  if(i == length(Li1)){
    ni1[i] <- sum(Nubosidad_N   >= Li1[i] & Nubosidad_N <= Ls1[i], na.rm = TRUE)
  } else {
    ni1[i] <- sum(Nubosidad_N>= Li1[i] & Nubosidad_N < Ls1[i], na.rm = TRUE)
  }
}

# Frecuencias relativas y acumuladas
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)))

# Marca de clase
MC1 <- (Li1 + Ls1) / 2

Tabla_Manual <- 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)
)

# Clonar y transformar a carácter para poder acoplar el TOTAL al final
Tabla_Final <- Tabla_Manual
Tabla_Final[] <- lapply(Tabla_Final, as.character)

# Crear 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 = ""
)

# Combinar dataframes con rbind
Tabla_Final <- rbind(Tabla_Final, fila_total)

kable(
  Tabla_Final,
  align = "c",
  caption = "Tabla N2: Distribución de frecuencias agrupadas de la variable cobertura de nubes en intervalos de 10 unidades, período 2024-2026"
) |> 
  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"  # Encabezado azul oscuro
  ) |> 
  kableExtra::row_spec(
    nrow(Tabla_Final),
    bold = TRUE,
    background = "#EAEDED"  # Resaltado gris claro para la fila TOTAL
  ) |> 
  footnote(
    general = "Elaborado por Grupo 2.\nFuente: Global Weather Repository.",
    general_title = "Nota: ",
    footnote_as_chunk = TRUE,
    title_format = c("italic", "bold")
  )
Tabla N2: Distribución de frecuencias agrupadas de la variable cobertura de nubes en intervalos de 10 unidades, período 2024-2026
Lim_inf Lim_sup MC ni hi Ni_asc Hi_asc Ni_dsc Hi_dsc
0 10 5 44188 31.18 44188 31.18 141703 100
10 20 15 4452 3.14 48640 34.33 97515 68.82
20 30 25 22244 15.7 70884 50.02 93063 65.67
30 40 35 2183 1.54 73067 51.56 70819 49.98
40 50 45 1915 1.35 74982 52.91 68636 48.44
50 60 55 18881 13.32 93863 66.24 66721 47.09
60 70 65 2559 1.81 96422 68.05 47840 33.76
70 80 75 29402 20.75 125824 88.79 45281 31.95
80 90 85 4711 3.32 130535 92.12 15879 11.21
90 100 95 11168 7.88 141703 100 11168 7.88
TOTAL 141703 100
Nota: Elaborado por Grupo 2.
Fuente: Global Weather Repository.

5.- Gráficos de Distribución de Frecuencias

5.1.- histograma Ni

cortes <- seq(0, 100, by = 10)

hist(
  Nubosidad_N,
  breaks = cortes,                           
  right = FALSE,                             
  col = "skyblue",                           
  border = "black",                          
  main = "Gráfico N°1 : Histograma de Frecuencia absolutas de cobertura de 
  nubes para el análisis meteorológico en capitales del mundo
  Periodo: Mayo 2024 a Mayo 2026",
  sub = "Fuente: Global Weather Repository",
  xlab = "Nubosidad (%)",
  ylab = "",                                 
  yaxt = "n",                                
  ylim = c(0, 50000)                         
)

marcas_y <- seq(0, 50000, by = 10000)
axis(side = 2, at = marcas_y, labels = format(marcas_y, big.mark = ","), font = 2, las = 1)

mtext(text = "Frecuencia Absoluta (ni)", side = 2, line = 3.5, font = 2)

grid(nx = NULL, ny = NULL, lty = "dashed", col = "gray", lwd = 1)

5.2.- Histograma Hi

cortes <- c(Li1, Ls1[length(Ls1)])  

h_relativo <- hist(Nubosidad_N, breaks = cortes, right = FALSE, plot = FALSE)

h_relativo$counts <- Tabla_Manual$hi

plot(
  h_relativo,
  col = "skyblue",                          
  border = "black",                         
  main = "Gráfico N°2 : Histograma de Frecuencia relativa de coberturas de
  nubes para el análisis meteorológico en capitales del mundo
  Periodo: Mayo 2024 a Mayo 2026",
  sub = "Fuente: Global Weather Repository",
  xlab = "Nubosidad(%)",
  ylab = "",                                
  yaxt = "n",                               
  ylim = c(0, 35)                           
)
marcas_y <- seq(0, 35, by = 10)
axis(side = 2, at = marcas_y, labels = paste0(marcas_y, "%"), font = 2, las = 1)
mtext(
  text = "Frecuencia Relativa (hi %)", 
  side = 2, 
  line = 3.3,                               
  font = 2
)

grid(nx = NA, ny = NULL, lty = "dotted", col = "gray")

5.3.- Histograma de ni con el tamaño muestral

hist(
  Nubosidad_N,
  breaks = cortes,                           
  right = FALSE,                             
  col = "skyblue",                           
  border = "black",                          
  main = "Gráfico N°3 : Histograma de Frecuencia absolutas de cobertura de 
  nubes para el análisis meteorológico en capitales del mundo
  Periodo: Mayo 2024 a Mayo 2026",
  sub = "Fuente: Global Weather Repository",
  xlab = "Nubosidad (%)",
  ylab = "",                                 
  yaxt = "n",                                
  ylim = c(0, 140000)                         
)

marcas_y <- seq(0, 140000, by = 30000)
axis(side = 2, at = marcas_y, labels = format(marcas_y, big.mark = ","), font = 2, las = 1)

mtext(text = "Frecuencia Absoluta (ni)", side = 2, line = 4.5, font = 2)

grid(nx = NULL, ny = NULL, lty = "dashed", col = "gray", lwd = 1)

5.4.- Histograma de Hi con 100% tamaño muestral

plot(
  h_relativo,
  col = "skyblue",                       
  border = "black",                         #
  main = "Gráfico N°4 : Histograma de Frecuencia relativa de cobertura de 
  nubes para el análisis meteorológico en capitales del mundo
  Periodo: Mayo 2024 a Mayo 2026",
  sub = "Fuente: Global Weather Repository",
  xlab = "Temperatura (°F)",
  ylab = "",                                
  yaxt = "n",                               
  ylim = c(0, 100)                          
)

marcas_y <- seq(0, 100, by = 20)
axis(side = 2, at = marcas_y, labels = paste0(marcas_y, "%"), font = 2, las = 1)

mtext(
  text = "Frecuencia Relativa (hi %)", 
  side = 2, 
  line = 4.5,                              
  font = 2
)

grid(nx = NA, ny = NULL, lty = "dotted", col = "gray")

5.5.- Poligono de frecuencia Ni

cortes <- c(Li1, Ls1[length(Ls1)])  

h_relativo <- hist(Nubosidad_N, breaks = cortes, right = FALSE, plot = FALSE)
h_relativo$counts <- Tabla_Manual$hi

marcas_clase <- MC1
marcas_poligono <- c(0, marcas_clase, 100)
hi_poligono     <- c(0, Tabla_Manual$hi, 0)


plot(
  h_relativo,
  col = "skyblue",                          
  border = "black",                         
  main = "Gráfico N°2 : Histograma de Frecuencia relativa de coberturas de 
  nubes para el análisis meteorológico en capitales del mundo
  Periodo: Mayo 2024 a Mayo 2026",
  sub = "Fuente: Global Weather Repository",
  xlab = "Nubosidad(%)",
  ylab = "",                                
  yaxt = "n",                               
  ylim = c(0, 35),
  xaxs = "i"                                 #
)

marcas_y <- seq(0, 35, by = 10)
axis(side = 2, at = marcas_y, labels = paste0(marcas_y, "%"), font = 2, las = 1)

mtext(
  text = "Frecuencia Relativa (hi %)", 
  side = 2, 
  line = 3.3,                                
  font = 2
)

grid(nx = NULL, ny = NULL, lty = "dashed", col = "lightgray", lwd = 1)

lines(
  x = marcas_poligono, 
  y = hi_poligono, 
  col = "red",            
  lwd = 3,                  
  type = "o",               
  pch = 19                  
)

5.6.- Ojivas ascendente y descendente (ni)

puntos_eje_x <- c(Li1, Ls1[length(Ls1)]) 

ni_asc_ojiva <- c(0, Tabla_Manual$Ni_asc)
ni_dsc_ojiva <- c(sum(Tabla_Manual$ni), Tabla_Manual$Ni_dsc)

limite_max_y <- 150000
marcas_y     <- seq(0, limite_max_y, by = 30000)

plot(
  1, 
  type = "n",
  main = "Gráfico N°6: Ojivas de Frecuencias Absolutas Acumuladas",
  sub = "Fuente: Global Weather Repository",
  xlab = "Nubosidad (%)",
  ylab = "",                             
  xaxt = "n",                             
  yaxt = "n",                             
  xlim = c(0, 100),                     
  ylim = c(0, limite_max_y),
  xaxs = "i"                             
)

axis(side = 1, at = puntos_eje_x, labels = puntos_eje_x, font = 2)
axis(side = 2, at = marcas_y, labels = format(marcas_y, big.mark = ","), font = 2, las = 1)

mtext(text = "Frecuencia Absoluta Acumulada (Ni)", side = 2, line = 4.5, font = 2)


grid(nx = NULL, ny = NULL, lty = "dashed", col = "lightgray", lwd = 1)

lines(
  x = puntos_eje_x, 
  y = ni_asc_ojiva, 
  col = "#2980b9",                        
  lwd = 3,                                
  type = "o",                             
  pch = 19                                
)
lines(
  x = puntos_eje_x, 
  y = ni_dsc_ojiva, 
  col = "#e74c3c",                        
  lwd = 3, 
  type = "o", 
  pch = 19
)
legend(
  "right",                                
  legend = c("Ojiva Ascendente (Ni asc)", "Ojiva Descendente (Ni dsc)"),
  col = c("#2980b9", "#e74c3c"),
  lty = 1,
  lwd = 3,
  pch = 19,
  bty = "n",                              #
  cex = 0.6,
  text.font = 2
)

5.7.- Ojivas ascendente y descendente (hi)

 puntos_eje_x <- c(Li1, Ls1[length(Ls1)]) 

hi_asc_ojiva <- c(0, Tabla_Manual$Hi_asc)
hi_dsc_ojiva <- c(100, Tabla_Manual$Hi_dsc)

limite_max_y <- 100
marcas_y     <- seq(0, 100, by = 20)

plot(
  1, 
  type = "n",
  main = "Gráfico N°7: Ojivas de Frecuencias Relativas Acumuladas",
  sub = "Fuente: Global Weather Repository",
  xlab = "Nubosidad (%)",
  ylab = "",                             
  xaxt = "n",                             
  yaxt = "n",                             
  xlim = c(0, 100),                     
  ylim = c(0, limite_max_y),
  xaxs = "i"                              
)

axis(side = 1, at = puntos_eje_x, labels = puntos_eje_x, font = 2)
axis(side = 2, at = marcas_y, labels = paste0(marcas_y, "%"), font = 2, las = 1)

mtext(text = "Frecuencia Relativa Acumulada (%)", side = 2, line = 4.5, font = 2)

grid(nx = NULL, ny = NULL, lty = "dashed", col = "lightgray", lwd = 1)

lines(
  x = puntos_eje_x, 
  y = hi_asc_ojiva, 
  col = "#2980b9",                        
  lwd = 3,                                
  type = "o",                             
  pch = 19                                
)

lines(
  x = puntos_eje_x, 
  y = hi_dsc_ojiva, 
  col = "#e74c3c",                        
  lwd = 3, 
  type = "o", 
  pch = 19
)

legend(
  "right",                                
  legend = c("Ojiva Ascendente (Hi asc)", "Ojiva Descendente (Hi dsc)"),
  col = c("#2980b9", "#e74c3c"),
  lty = 1,
  lwd = 3,
  pch = 19,
  bty = "n",                              
  cex = 0.7,
  text.font = 2
)

5.8.- Diagrama de caja y bigotes

# 1. Reconstruir la muestra estadística de nubosidad usando MC1 y ni1 de tu script
datos_nubosidad_reconst <- rep(MC1, times = ni1)

# 2. Configurar la escala para el eje horizontal (X) de 10 en 10
marcas_x_nubosidad <- seq(0, 100, by = 10)

# 3. Graficar el diagrama de caja horizontal
boxplot(
  datos_nubosidad_reconst,
  horizontal = TRUE,                      # Orientación horizontal para reporte
  col = "skyblue",                        # Mismo color celeste institucional
  border = "black",                       # Bordes negros definidos
  main = "Diagrama de Caja y Bigotes (Boxplot): Cobertura de Nubes",
  sub = "Elaborado por: Grupo 2 | Fuente: Global Weather Repository",
  xaxt = "n",                             # Desactiva el eje X automático para personalizarlo
  yaxt = "n",                             # Oculta el eje Y al ser una única variable
  lwd = 1.8,                              # Grosor de la línea de la caja y los bigotes
  outcol = "red",                         # Color rojo para identificar valores atípicos
  outpch = 19,                            # Puntos rellenos para los outliers
  outcex = 0.8,                           # Tamaño de los puntos atípicos
  xlim = c(0.7, 1.3)                      # Centra verticalmente la caja en el lienzo
)

# 4. Personalizar el eje X con el símbolo de porcentaje (%)
axis(
  side = 1, 
  at = marcas_x_nubosidad,       
  labels = paste0(marcas_x_nubosidad, "%"), 
  font = 2,            
  las = 1                              
)

# 5. Agregar el título inferior del eje X
mtext(text = "Cobertura de Nubes (Nubosidad %)", side = 1, line = 3.0, font = 2, cex = 1)

# 6. Rejilla vertical con líneas entrecortadas alineada a cada intervalo de la tabla
grid(nx = NULL, ny = NA, lty = "dashed", col = "lightgray", lwd = 1)

6.- Indicadores Estadisticos

Tendencia central

media    <- mean(Nubosidad_N, na.rm = TRUE)
mediana  <- median(Nubosidad_N, na.rm = TRUE)
moda     <- MC1[which.max(ni1)]

Medidas de Dispersión

varianza <- var(Nubosidad_N, na.rm = TRUE)
desv_est <- sd(Nubosidad_N, na.rm = TRUE)
cv       <- (desv_est / media) * 100

Medidas de Forma

asim <- skewness(Nubosidad_N, na.rm = TRUE)
kurt <- kurtosis(Nubosidad_N, na.rm = TRUE)

valores atípicos

Q1  <- quantile(Nubosidad_N, 0.25, na.rm = TRUE)
Q3  <- quantile(Nubosidad_N, 0.75, na.rm = TRUE)
RIC <- Q3 - Q1

lim_inf <- Q1 - 1.5 * RIC
lim_sup <- Q3 + 1.5 * RIC
n_atipicos <- sum(Nubosidad_N < lim_inf | Nubosidad_N > lim_sup, na.rm = TRUE)
rango_valores <- paste0("[","0", " ; ", "100", "]")

Tabla de indicadores

tabla_indicadores <- data.frame(
  Variable         = "Cobertura de nubes",
  Rango            = rango_valores,
  X                = round(media, 2),
  Me               = round(mediana, 2),
  Mo               = round(moda, 2),
  V                = round(varianza, 2),
  Sd               = round(desv_est, 2),
  CV               = paste0(round(cv, 2), "%"),
  As               = round(asim, 2),
  K                = round(kurt, 2),
  Valores_Atipicos = n_atipicos
)
kable(
  tabla_indicadores, 
  align   = "c", 
  caption = "Tabla N°3: Indicadores estadísticos descriptivos de la variable cobertura de nubes basados en la distribución de frecuencias, período 2024-2026"
) |>
  kableExtra::kable_styling(
    full_width        = FALSE, 
    position          = "center", 
    bootstrap_options = c("striped", "hover", "condensed", "responsive")
  ) |>
  kableExtra::row_spec(
    0, 
    bold = TRUE, 
    color = "white", 
    background = "#2C3E50"  
  )
Tabla N°3: Indicadores estadísticos descriptivos de la variable cobertura de nubes basados en la distribución de frecuencias, período 2024-2026
Variable Rango X Me Mo V Sd CV As K Valores_Atipicos
Cobertura de nubes [0 ; 100] 39.83 29 5 1161.45 34.08 85.56% 0.24 -1.35 0

7.- Conclusiones

El comportamiento de la concentración de la cobertura de nubes en porcentaje (\(\%\)) fluctúa en un rango de \([0\% ; 100\%]\), y sus valores giran en torno a una mediana de \(62.50\%\), con una media aritmética de \(39.83\%\). Presenta una desviación estándar de \(19.36\%\) y un coeficiente de variación de \(48.60\%\), por lo que constituye un conjunto de datos altamente heterogéneo. La distribución muestra una concentración muy alta de observaciones en los valores bajos alrededor de la moda (que se ubica en \(5.00\%\)), reflejando una curtosis fuertemente platicúrtica de \(-1.35\) y una cola extendida hacia los valores altos que genera una asimetría positiva de \(0.24\). Por todo lo anterior, el comportamiento de la nubosidad mundial durante el período 2024-2026 se caracteriza por una marcada dispersión donde predominan los días de cielos despejados o con escasa nubosidad la mayor parte del tiempo, aunque la presencia de fluctuaciones constantes genera una variabilidad notable en los datos climáticos analizados.