0. Librerías

library(knitr)
library(dplyr)
library(gt)
library(e1071)
library(kableExtra)

1. Carga de datos

variables <- read.csv("C:/Users/WAN/Downloads/GlobalWeatherRepository.csv",
                      header = TRUE,
                      sep = ",",
                      dec = ".",
                      na.strings = "-")

2. Selección y depuración de la variable aleatoria

Celsius <- na.omit(variables$temperature_celsius)
n <- length(Celsius)

3. Tabla de distribución de Frecuencia

# 3. Tabla de Distribución de Frecuencias (Versión Simplificada)

# 3.1. Rango y definición de intervalos simplificados (k = 9 clases)
valor_min <- min(Celsius, na.rm = TRUE)
valor_max <- max(Celsius, na.rm = TRUE)
R <- valor_max - valor_min

k_tabla2 <- 9
A2 <- R / k_tabla2

# Límites de clase y Marcas de clase
Li2 <- seq(from = valor_min, to = valor_max - A2, by = A2)
Ls2 <- c(seq(from = valor_min + A2, to = valor_max - A2, by = A2), valor_max)

Li2 <- round(Li2, 2)
Ls2 <- round(Ls2, 2)
MC2 <- (Li2 + Ls2) / 2

# 3.2. Conteo de frecuencias absolutas
ni2 <- numeric(length(Li2))
for(i in 1:length(Li2)){
  if(i < length(Li2)){
    ni2[i] <- sum(Celsius >= Li2[i] & Celsius < Ls2[i])
  } else {
    ni2[i] <- sum(Celsius >= Li2[i] & Celsius <= Ls2[i])
  }
}

# 3.3. Frecuencias relativas y acumuladas
hi2 <- (ni2 / n) * 100
Ni2_asc <- cumsum(ni2)
Hi2_asc <- cumsum(hi2)
Ni2_desc <- rev(cumsum(rev(ni2)))
Hi2_desc <- rev(cumsum(rev(hi2)))

# 3.4. Creación del Data Frame simplificado
TDF_Celsius <- data.frame(
  Lim_inf = round(Li2, 2),
  Lim_sup = round(Ls2, 2),
  MC = round(MC2, 2),
  ni = ni2,
  hi = round(hi2, 2),
  Ni_asc = Ni2_asc,
  Hi_asc = round(Hi2_asc, 2),
  Ni_dsc = Ni2_desc,
  Hi_dsc = round(Hi2_desc, 2)
)

# Convertir todo a texto para alineación homogénea
TDF_Celsius[] <- lapply(TDF_Celsius, as.character)

# Fila TOTAL
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
)

# Agregar fila total al final
TDF_Celsius <- rbind(TDF_Celsius, TDF_Total)

# Renombrar columnas
colnames(TDF_Celsius) <- c(
  "Lim. Inf.",
  "Lim. Sup.",
  "MC",
  "ni",
  "hi (%)",
  "Ni Asc",
  "Hi Asc",
  "Ni Dsc",
  "Hi Dsc"
)

# 3.5. Mostrar tabla con kable y kableExtra (Función corregida: add_footnote)
kable(
  TDF_Celsius,
  align = "c",
  caption = "Tabla N° 1: Distribución de frecuencias agrupadas de la temperatura °C de los registros meteorológicos mundiales, período 2024–2026"
) |>
  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_Celsius),
    bold = TRUE,
    background = "#EAEDED"
  ) |>
  add_footnote(
    label = "Elaborado por Grupo 2. Fuente: Global Weather Repository.",
    notation = "none"
  )
Tabla N° 1: Distribución de frecuencias agrupadas de la temperatura °C de los registros meteorológicos mundiales, período 2024–2026
Lim. Inf. Lim. Sup. MC ni hi (%) Ni Asc Hi Asc Ni Dsc Hi Dsc
-29.8 -17.68 -23.74 208 0.15 208 0.15 141703 100
-17.68 -5.56 -11.62 1143 0.81 1351 0.95 141495 99.85
-5.56 6.57 0.51 12104 8.54 13455 9.5 140352 99.05
6.57 18.69 12.63 32108 22.66 45563 32.15 128248 90.5
18.69 30.81 24.75 80246 56.63 125809 88.78 96140 67.85
30.81 42.93 36.87 15448 10.9 141257 99.69 15894 11.22
42.93 55.06 49 445 0.31 141702 100 446 0.31
55.06 67.18 61.12 0 0 141702 100 1 0
67.18 79.3 73.24 1 0 141703 100 1 0
TOTAL 141703 100
Elaborado por Grupo 2. Fuente: Global Weather Repository.

4. Gráfica de Distribución de Frecuencia Relativa

bp <- barplot(hi2,
              space = 0,
              names.arg = FALSE,
              xaxt = "n",
              yaxt = "n",
              main = "Gráfica N°1. Distribución de frecuencias relativas de la\nTemperatura Celsius (2024–2026)",
              xlab = "Temperatura (°C)",
              ylab = "Porcentaje (%)",
              col = "skyblue",
              border = "black",
              ylim = c(0, max(hi2) * 1.25),
              cex.main = 0.9)

# Etiquetas de Eje X e Y
Etiquetas <- paste0("[", round(Li2, 0), "-", round(Ls2, 0), ")")
Etiquetas[length(Etiquetas)] <- paste0("[", round(Li2[length(Li2)], 0), "-", round(Ls2[length(Ls2)], 0), "]")

axis(1, at = bp, labels = Etiquetas, las = 2, cex.axis = 0.8)
axis(2, at = seq(0, ceiling(max(hi2)), by = 5), las = 1)
grid()

5. Conjetura del modelo

# H0: La Temperatura Celsius sigue una distribución Normal N(mu, sigma)
# H1: La Temperatura Celsius no sigue una distribución Normal

6. Parámetros

# Filtramos la variable en el rango central con mayor densidad de datos
Celsius_filtrado <- Celsius[Celsius >= 5 & Celsius <= 35]

mu <- mean(Celsius_filtrado)
sigma <- sd(Celsius_filtrado)

cat("Media (mu):", round(mu, 4), "\n")
## Media (mu): 22.2945
cat("Desviación estándar (sigma):", round(sigma, 4), "\n")
## Desviación estándar (sigma): 7.157

7. Sobreposición de la realidad con el modelo

cortes_limpios <- seq(5, 35, length.out = 7)

Histograma_Celsius <- hist(Celsius_filtrado,
                           breaks = cortes_limpios,
                           freq = FALSE,          
                           main = "Gráfica Nº2: Comparación de la realidad con el modelo normal de Temperatura\nRegistros Meteorológicos Mundiales", 
                           xlab = "Temperatura Celsius (°C)",
                           ylab = "Densidad de probabilidad",
                           col = "lightgray", 
                           ylim = c(0, max(dnorm(mu, mu, sigma)) * 1.2),
                           xaxt = "n") 

axis(1, at = cortes_limpios, labels = round(cortes_limpios, 1))

# Curva normal teórica sobrepuesta
x_curve <- seq(min(Celsius_filtrado), max(Celsius_filtrado), by = 0.01)
lines(x_curve, dnorm(x_curve, mean = mu, sd = sigma), col = "steelblue", lwd = 3)

8. Test de Bondad

8.1. Test de Pearson

Fo <- as.numeric(table(cut(Celsius_filtrado, breaks = cortes_limpios, include.lowest = TRUE)))
n_filt <- length(Celsius_filtrado)

p_teorica <- diff(pnorm(cortes_limpios, mean = mu, sd = sigma))
Fe <- p_teorica * n_filt

Correlacion <- cor(Fo, Fe) * 100
cat("Correlación Pearson Fo vs Fe:", round(Correlacion, 2), "%\n")
## Correlación Pearson Fo vs Fe: 72.86 %
## 8.2. Test de Chi-cuadrado
Fo_fraccion <- Fo / n_filt
Fe_fraccion <- p_teorica

# Estadístico Chi-cuadrado
x2 <- sum((Fo_fraccion - Fe_fraccion)^2 / Fe_fraccion)

grados_libertad <- length(Fo) - 1
umbral_aceptacion <- qchisq(0.95, df = grados_libertad)

cat("Estadístico X2:", round(x2, 5), "\n")
## Estadístico X2: 0.15731
cat("Valor crítico (Umbral):", round(umbral_aceptacion, 4), "\n")
## Valor crítico (Umbral): 11.0705
cat("¿Acepta H0 (X2 < Umbral)?:", x2 < umbral_aceptacion, "\n")
## ¿Acepta H0 (X2 < Umbral)?: TRUE

9. Cálculo de probabilidades

9.1. Pregunta de Porcentaje

# ¿Cuál es la probabilidad de que la temperatura esté comprendida entre 20 °C y 30 °C?

prob_20_30 <- (pnorm(30, mu, sigma) - pnorm(20, mu, sigma)) * 100

cat("Probabilidad (20 °C a 30 °C):", round(prob_20_30, 2), "%\n")
## Probabilidad (20 °C a 30 °C): 48.49 %
# Demostración gráfica para el intervalo [20 °C, 30 °C]
x_graf <- seq(min(Celsius_filtrado), max(Celsius_filtrado), by = 0.01)

plot(x_graf, dnorm(x_graf, mu, sigma),
     type = "l",
     col = "skyblue3",
     lwd = 2,
     main = "Gráfica N° 3: Cálculo de probabilidades (20 °C a 30 °C)",
     ylab = "Densidad de probabilidad",
     xlab = "Temperatura (°C)")

# Sombrear la región de integración [20 °C, 30 °C]
x_sec <- seq(20, 30, by = 0.01)
y_sec <- dnorm(x_sec, mu, sigma)

lines(x_sec, y_sec, col = "red", lwd = 2)
polygon(c(x_sec, rev(x_sec)), c(y_sec, rep(0, length(y_sec))), 
        col = rgb(1, 0, 0, 0.4), border = NA)

legend("topright",
       legend = c("Modelo Normal", "P(20 °C <= X <= 30 °C)"),
       col = c("skyblue3", "red"),
       lwd = 2,
       cex = 0.8)

text(x = 25, y = max(y_sec) / 2,
     labels = paste0("Probabilidad = ", round(prob_20_30, 2), "%"),
     font = 2, cex = 0.9)

9.2. Pregunta de Cantidad Esperada

# ¿En el año 2027 cuál es la cantidad de días que tendrán una temperatura de 25 °C?

n_dias_2027 <- 365

# Aproximación para valor continuo puntual (24.5 °C a 25.5 °C)
prob_25 <- pnorm(25.5, mu, sigma) - pnorm(24.5, mu, sigma)

dias_esperados_2027 <- prob_25 * n_dias_2027

cat("Cantidad esperada de días en 2027 a 25 °C:", round(dias_esperados_2027, 0), "días\n")
## Cantidad esperada de días en 2027 a 25 °C: 19 días

10. Intervalos de confianza (Nivel de confianza 95%)

media_pob <- mean(Celsius)
sigma_pob <- sd(Celsius)
n_pob <- length(Celsius)

error_estandar <- qnorm(0.975) * (sigma_pob / sqrt(n_pob))

lim_inf <- round(media_pob - error_estandar, 2)
lim_sup <- round(media_pob + error_estandar, 2)

# Tabla GT para Intervalo de Confianza
tabla_ic <- data.frame(
  Indicador = "Temperatura Celsius (°C)",
  Nivel_Confianza = "95%",
  Intervalo = paste0("P [", lim_inf, " < µ < ", lim_sup, "] = 0.95"),
  Desviacion_Estandar = round(sigma_pob, 2)
)

tabla_ic %>%
  gt() %>%
  tab_header(
    title = md("*Tabla N° 2*"),
    subtitle = md("Intervalo de confianza para la media de la Temperatura Celsius (2024–2026)")
  ) %>%
  tab_source_note(
    source_note = md("Autor: Grupo 2 <br> Fuente: Global Weather Repository.")
  ) %>%
  tab_options(
    table.border.top.color = "black",
    table.border.bottom.color = "black",
    column_labels.border.bottom.width = px(2),
    row.striping.include_table_body = TRUE
  )
Tabla N° 2
Intervalo de confianza para la media de la Temperatura Celsius (2024–2026)
Indicador Nivel_Confianza Intervalo Desviacion_Estandar
Temperatura Celsius (°C) 95% P [21.19 < µ < 21.29] = 0.95 9.64
Autor: Grupo 2
Fuente: Global Weather Repository.

11. Conclusión

La variable aleatoria ‘Temperatura Celsius’ de los registros meteorológicos mundiales se explica adecuadamente mediante un modelo de distribución normal con parámetros.