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

Fahrenheit <- variables$temperature_fahrenheit

3.- Frecuencias

Min y max

n_total <- length(Fahrenheit)

valor_min <- min(Fahrenheit, na.rm = TRUE)
valor_max <- max(Fahrenheit, na.rm = TRUE)
rango <- valor_max - valor_min

Regla de sturges

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

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(
      Fahrenheit >= Li1[i] &
        Fahrenheit <= Ls1[i],
      na.rm = TRUE
    )
  } else {
    ni1[i] <- sum(
      Fahrenheit >= Li1[i] &
        Fahrenheit < 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ó 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 Fahrenheit 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 Fahrenheit 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
-21.6 -10.69 -16.15 29 0.02 29 0.02 141703 100
-10.69 0.21 -5.24 179 0.13 208 0.15 141674 99.98
0.21 11.12 5.66 338 0.24 546 0.39 141495 99.85
11.12 22.02 16.57 806 0.57 1352 0.95 141157 99.61
22.02 32.93 27.47 3262 2.3 4614 3.26 140351 99.05
32.93 43.83 38.38 8853 6.25 13467 9.5 137089 96.74
43.83 54.74 49.29 13949 9.84 27416 19.35 128236 90.5
54.74 65.64 60.19 18195 12.84 45611 32.19 114287 80.65
65.64 76.55 71.1 33090 23.35 78701 55.54 96092 67.81
76.55 87.46 82 47057 33.21 125758 88.75 63002 44.46
87.46 98.36 92.91 12891 9.1 138649 97.84 15945 11.25
98.36 109.27 103.81 2604 1.84 141253 99.68 3054 2.16
109.27 120.17 114.72 446 0.31 141699 100 450 0.32
120.17 131.08 125.62 3 0 141702 100 4 0
131.08 141.98 136.53 0 0 141702 100 1 0
141.98 152.89 147.44 0 0 141702 100 1 0
152.89 163.79 158.34 0 0 141702 100 1 0
163.79 174.7 169.25 1 0 141703 100 1 0
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

Fahrenheit_t<- variables$temperature_fahrenheit
Li1 <- seq(-25, 150, by = 25)  # Empieza en -25 y el último límite inferior es 150
Ls1 <- seq(0, 175, by = 25)   # 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(Fahrenheit_t >= Li1[i] & Fahrenheit_t <= Ls1[i], na.rm = TRUE)
  } else {
    ni1[i] <- sum(Fahrenheit_t>= Li1[i] & Fahrenheit_t < 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 Fahrenheit en intervalos de 25 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 Fahrenheit en intervalos de 25 unidades, período 2024-2026
Lim_inf Lim_sup MC ni hi Ni_asc Hi_asc Ni_dsc Hi_dsc
-25 0 -12.5 186 0.13 186 0.13 141703 100
0 25 12.5 1492 1.05 1678 1.18 141517 99.87
25 50 37.5 18183 12.83 19861 14.02 140025 98.82
50 75 62.5 51269 36.18 71130 50.2 121842 85.98
75 100 87.5 68224 48.15 139354 98.34 70573 49.8
100 125 112.5 2348 1.66 141702 100 2349 1.66
125 150 137.5 0 0 141702 100 1 0
150 175 162.5 1 0 141703 100 1 0
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(-25, 175, by = 25)

hist(
  Fahrenheit,
  breaks = cortes,                           
  right = FALSE,                             
  col = "skyblue",                           
  border = "black",                          
  main = "Gráfico N°1 : Histograma de Frecuencia absolutas de temperatura 
  en Fahrenheit 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 = "",                                 
  las = 1                                    
)
mtext(
  text = "Frecuencia Absoluta (ni)", 
  side = 2, 
  line = 3.4,                                
  font = 2
)
grid(nx = NA, ny = NULL, lty = "dotted", col = "gray")

## 5.2.- Histograma Hi

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

h_relativo <- hist(Fahrenheit_t, 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 temperatura 
  en Fahrenheit 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, 50)                           
)
marcas_y <- seq(0, 50, by = 10)
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.3.- Histograma de ni con el tamaño muestral

hist(
  Fahrenheit_t,
  breaks = cortes,                           
  right = FALSE,                             
  col = "skyblue",                           
  border = "black",                          
  main = "Gráfico N°1 : Histograma de Frecuencia absolutas de temperatura 
  en Fahrenheit para el análisis meteorológico en capitales del mundo
  Periodo: Mayo 2024 a Mayo 2026",
  sub = "Elaborado por: Grupo 2 | Fuente: Global Weather Repository",
  xlab = "Temperatura (°F)",
  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 el tamaño muestral

cortes <- c(Li1, Ls1[length(Ls1)]) 
h_relativo <- hist(Fahrenheit_t, breaks = cortes, right = FALSE, plot = FALSE)
h_relativo$counts <- Tabla_Manual$hi

plot(
  h_relativo,
  col = "skyblue",                       
  border = "black",                         #
  main = "Gráfico N°4 : Histograma de Frecuencia relativa de temperatura 
  en Fahrenheit 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)])  
marcas_clase <- MC1                

marcas_poligono <- c(marcas_clase[1] - 25, marcas_clase, marcas_clase[length(marcas_clase)] + 25)
ni_poligono     <- c(0, Tabla_Manual$ni, 0)

hist(
  Fahrenheit_t,
  breaks = cortes,                           
  right = FALSE,                             
  col = "skyblue",                           
  border = "black",                          
  main = "Gráfico N°5 : Poligono de frecuencias, temperatura 
  en Fahrenheit 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, 80000)                         
)

marcas_y <- seq(0, 80000, by = 20000)
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 = "lightgray", lwd = 1)

lines(
  x = marcas_poligono, 
  y = ni_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 = " Temperatura (°F)",
  ylab = "",                             
  xaxt = "n",                             
  yaxt = "n",                             
  xlim = c(-25, 175),                     
  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 = "Temperatura (°F)",
  ylab = "",                             
  xaxt = "n",                             
  yaxt = "n",                             
  xlim = c(-25, 175),                     
  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

datos_reconstruidos <- rep(MC1, times = ni1)

marcas_x <- seq(-25, 175, by = 25)

boxplot(
  datos_reconstruidos,
  horizontal = TRUE,                      
  col = "skyblue",                        
  border = "black",                      
  main = "Gráfico N°8: Diagrama de Caja y Bigotes (Boxplot)",
  sub = "Fuente: Global Weather Repository",
  xaxt = "n",                             
  yaxt = "n",                             
  lwd = 1.8,                              
  outcol = "red",                         
  outpch = 19,                            
  outcex = 0.8                            
)
axis(
  side = 1, 
  at = marcas_x,       
  labels = paste0(marcas_x, "°F"), 
  font = 2,            
  las = 1                              
)

mtext(text = "Temperatura Fahrenheit (°F)", side = 1, line = 3.0, font = 2, cex = 1)

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

6.- Indicadores Estadisticos

Tendencia central

Fahrenheit_reconst <- rep(MC1, times = ni1)

media    <- mean(Fahrenheit_reconst)
mediana  <- median(Fahrenheit_reconst)
moda     <- MC1[which.max(ni1)]             # Marca de clase con mayor frecuencia absoluto (Clase Modal)

Medidas de Dispersión

varianza <- var(Fahrenheit_reconst)
desv_est <- sd(Fahrenheit_reconst)
cv       <- (desv_est / media) * 100

Medidas de Forma

asim <- skewness(Fahrenheit_reconst)
kurt <- kurtosis(Fahrenheit_reconst)

valores atípicos

Q1  <- quantile(Fahrenheit_reconst, 0.25)
Q3  <- quantile(Fahrenheit_reconst, 0.75)
RIC <- Q3 - Q1

lim_inf <- Q1 - 1.5 * RIC
lim_sup <- Q3 + 1.5 * RIC

# Conteo automatizado de observaciones que caen fuera de los bigotes
n_atipicos <- sum(Fahrenheit_reconst < lim_inf | Fahrenheit_reconst > lim_sup)

# Formatear el rango de las marcas de clase como texto descriptivo
rango_valores <- paste0("[","-21.6", " ; ", "174.7", "]")

Tabla de indicadores

tabla_indicadores <- data.frame(
  Variable         = "Temperatura Fahrenheit",
  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 Temperatura Fahrenheit 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 Temperatura Fahrenheit basados en la distribución de frecuencias, período 2024-2026
Variable Rango X Me Mo V Sd CV As K Valores_Atipicos
Temperatura Fahrenheit [-21.6 ; 174.7] 71.53 62.5 87.5 374.72 19.36 27.06% -0.71 0.18 1679

7.- Conclusiones

El comportamiento de la temperatura en grados Fahrenheit (\(\text{°F}\)) fluctúa entre \(-21.6\text{ °F}\) y \(174.7\text{ °F}\), y sus valores giran en torno a la mediana de \(62.50\text{ °F}\), debido a la presencia de \(1,679\) valores atípicos que influyen notablemente en la media aritmética de \(71.53\text{ °F}\). Presenta una desviación estándar de \(19.36\text{ °F}\) y un coeficiente de variación de \(27.06\%\), por lo que constituye un conjunto de datos moderadamente homogéneo. La distribución muestra una concentración moderada de los datos alrededor de la moda (curtosis de \(0.18\), lo que indica un comportamiento mesocúrtica o ligeramente leptocúrtica) y una mayor acumulación de observaciones en los valores altos de temperatura, con una cola extendida hacia los valores bajos que genera una asimetría negativa de \(-0.71\). Por todo lo anterior, el comportamiento de la variable meteorológica mundial durante el período 2024-2026 se caracteriza por una predominancia de ambientes templados a cálidos la mayor parte del tiempo, aunque existen registros extremos y críticos de frío que generan una dispersión y variabilidad bien definida en los datos analizados.