#0. Librerias

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

1. Leer variables

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

2. Extraer y Depuración de la Variable

UV <- na.omit(variables$uv_index)

# Total de variables

n_total <- length(UV)

3. Frecuencias

##3.1 Max y Min

valor_min <- min(UV)
valor_max <- max(UV)

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: 0.9055556

##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(
      UV >= Li1[i] &
        UV <= Ls1[i]
    )
    
  } else {
    
    ni1[i] <- sum(
      UV >= Li1[i] &
        UV < Ls1[i]
    )
  }
}

# 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

##3.5. Tabla con amplitud ajustada

amplitud <- 2

# Intervalos
Li2 <- seq(
  floor(valor_min/2)*2,
  ceiling(valor_max/2)*2 - 2,
  by = 2
)

Ls2 <- Li2 + 2

#Frecuencias

ni2 <- numeric(length(Li2))

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

# Frecuencia relativa
hi2 <- (ni2 / sum(ni2)) * 100

# Acumuladas
Ni_asc2 <- cumsum(ni2)
Hi_asc2 <- cumsum(hi2)

Ni_dsc2 <- rev(cumsum(rev(ni2)))
Hi_dsc2 <- rev(cumsum(rev(hi2)))

# Marca de clase
MC2 <- (Li2 + Ls2)/2

4. Tabla de Distribución de Frecuencias

4.1. Tabla según Sturges

# Convertir a caracteres para poder mezclar números y texto

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

# Agregar fila

Tabla_Sturges2 <- rbind(Tabla_Sturges2, fila_total)


kable(
  Tabla_Sturges2,
  align = "c",
  caption = "Tabla N1: Distribución de frecuencias del índice UV 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. 
    Fuente: Global Weather Repository.",
    general_title = "Nota: ",
    footnote_as_chunk = TRUE,
    title_format = c("italic","bold")
  )
Tabla N1: Distribución de frecuencias del índice UV 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 0.91 0.45 55288 39.02 55288 39.02 141703 100
0.91 1.81 1.36 16129 11.38 71417 50.4 86415 60.98
1.81 2.72 2.26 8207 5.79 79624 56.19 70286 49.6
2.72 3.62 3.17 7094 5.01 86718 61.2 62079 43.81
3.62 4.53 4.08 7382 5.21 94100 66.41 54985 38.8
4.53 5.43 4.98 7416 5.23 101516 71.64 47603 33.59
5.43 6.34 5.89 9836 6.94 111352 78.58 40187 28.36
6.34 7.24 6.79 8698 6.14 120050 84.72 30351 21.42
7.24 8.15 7.7 6779 4.78 126829 89.5 21653 15.28
8.15 9.06 8.6 4403 3.11 131232 92.61 14874 10.5
9.06 9.96 9.51 2483 1.75 133715 94.36 10471 7.39
9.96 10.87 10.41 3045 2.15 136760 96.51 7988 5.64
10.87 11.77 11.32 1913 1.35 138673 97.86 4943 3.49
11.77 12.68 12.22 1309 0.92 139982 98.79 3030 2.14
12.68 13.58 13.13 794 0.56 140776 99.35 1721 1.21
13.58 14.49 14.04 551 0.39 141327 99.73 927 0.65
14.49 15.39 14.94 299 0.21 141626 99.95 376 0.27
15.39 16.3 15.85 77 0.05 141703 100 77 0.05
TOTAL 141703 100
Nota: Elaborado por Grupo 2.
Fuente: Global Weather Repository.

##4.2. Tabla ajustada

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

# Convertir todo a texto
TDF_UV[] <- lapply(TDF_UV, 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
TDF_UV <- rbind(TDF_UV, TDF_Total)

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

# Mostrar tabla

kable(
  TDF_UV,
  align = "c",
  caption = "Tabla N°4:Distribución de frecuencias relativa del índice UV 
  de los registros meteorológicos mundiales en 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_UV),
    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°4:Distribución de frecuencias relativa del índice UV de los registros meteorológicos mundiales en período 2024–2026
Lim. Inf. Lim. Sup. MC ni hi (%) Ni Asc Hi Asc Ni Dsc Hi Dsc
0 2 1 72442 51.12 72442 51.12 141703 100
2 4 3 16133 11.39 88575 62.51 69261 48.88
4 6 5 15137 10.68 103712 73.19 53128 37.49
6 8 7 18611 13.13 122323 86.32 37991 26.81
8 10 9 11392 8.04 133715 94.36 19380 13.68
10 12 11 5301 3.74 139016 98.1 7988 5.64
12 14 13 2043 1.44 141059 99.55 2687 1.9
14 16 15 635 0.45 141694 99.99 644 0.45
16 18 17 9 0.01 141703 100 9 0.01
TOTAL 141703 100
Nota: Elaborado por Grupo 2.
Fuente: Global Weather Repository.

5. Gráficos de Distribución de Frecuencias

5.1. Histograma Original (ni)

hist(
  UV,
  
  breaks = c(Li2, max(Ls2)),
  
  freq = TRUE,
  
  main = "Gráfico N°2. Histograma de frecuencias absolutas de la UV\nRegistros meteorológicos mundiales, período 2024-2026",
  
  xlab = "UV (%)",
  
  ylab = "Frecuencia absoluta (ni)",
  
  col = "lightgreen",
  
  border = "black",
  
  xaxt = "n"
)

# Crear marcas del eje X exactamente en los límites de clase
axis(
  1,
  at = c(Li2, max(Ls2)),
  labels = c(Li2, max(Ls2))
)

grid()

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

hist(
  UV,
  
  breaks = c(Li2, max(Ls2)),
  
  ylim = c(0, n_total),
  
  main = "Gráfico N°2: Histograma Global de UV del año 2024 al 2026",
  
  xlab = "UV",
  
  ylab = "Frecuencia",
  
  col = "lightgreen",
  
  border = "black"
)

grid()

5.3. Histograma original (hi)

# Crear una ventana vacía
plot(
  NA,
  xlim = c(min(Li2), max(Ls2)),
  ylim = c(0, max(hi2) * 1.1),
  main = "Gráfico N°5: Histograma Local de Frecuencia Relativa del
  año 2024 al 2026",
  xlab = "UV (%)",
  ylab = "Frecuencia Relativa (%)"
)

# Dibujar barras del histograma
rect(
  Li2,
  0,
  Ls2,
  hi2,
  col = "skyblue",
  border = "black"
)

grid()

5.4. Histograma con relacion a todo (hi)

plot(
  NA,
  xlim = c(min(Li2), max(Ls2)),
  ylim = c(0, 100),
  main = "Gráfico N°6: Histograma Global de Frecuencia Relativa del 
  año 2024 al 2026",
  xlab = "UV (%)",
  ylab = "Frecuencia Relativa (%)"
)

rect(
  Li2,
  0,
  Ls2,
  hi2,
  col = "lightgreen",
  border = "black"
)

grid()

5.5. Polígono de frecuencias (ni)

hist(
  UV,
  breaks = c(Li2, max(Ls2)),
  freq = TRUE,
  xlim = c(-5, 105),
  main = "Gráfico N°7: Histograma y Polígono de Frecuencias Absolutas del
  año 2024 al 2026",
  xlab = "UV (%)",
  ylab = "Frecuencia Absoluta (ni)",
  col = "lightblue",
  border = "black",
  xaxt = "n"
)

# Colocar marcas del eje X cada 10 unidades
axis(
  1,
  at = seq(0, 100, by = 10),
  labels = seq(0, 100, by = 10)
)

# Coordenadas del polígono cerrado
x_pol <- c(0, MC2, 100)
y_pol <- c(0, ni2, 0)

# Dibujar polígono de frecuencias

lines(
  x_pol,
  y_pol,
  type = "l",
  lwd = 2,
  col = "red"
)

# Agregar cuadrícula
grid()

length(ni2)
## [1] 9

5.6. Polígono de frecuencias (hi)

plot(
  NA,
  xlim = c(min(Li2), max(Ls2)),
  ylim = c(0, max(hi2) * 1.2),
  main = "Gráfico N°7: Histograma y Polígono de Frecuencia Relativa
  de los años 2024 al 2026",
  xlab = "UV (%)",
  ylab = "Frecuencia Relativa (%)"
)

# Histograma
rect(
  Li2,
  0,
  Ls2,
  hi2,
  col = "lightgreen",
  border = "black"
)

# Coordenadas del polígono cerrado
x_pol <- c(MC2[1] - amplitud/2, MC2, MC2[length(MC2)] + amplitud/2)

y_pol <- c(0, hi2, 0)

lines(
  x_pol,
  y_pol,
  type = "o",
  pch = 16,
  lwd = 2,
  col = "red"
)

# Polígono de frecuencia
lines(
  MC2,
  hi2,
  type = "o",
  pch = 16,
  lwd = 2,
  col = "red"
)

grid()

5.7. Ojiva ascendente y descendente (ni)

plot(
  Ls2,
  Ni_asc2,
  
  type = "o",
  
  pch = 16,
  
  lwd = 2,
  
  col = "blue",
  
  ylim = c(0, max(Ni_asc2)),
  
  main = "Gráfico N°9: Ojivas de Frecuencia Absoluta meteorológica mundial con en el período 2024–2026",
  
  xlab = "UV",
  
  ylab = "Frecuencia Acumulada (Ni)"
)

lines(
  Li2,
  Ni_dsc2,
  
  type = "o",
  
  pch = 17,
  
  lwd = 2,
  
  col = "red"
)

legend(
  "right",
  
  legend = c(
    "Ojiva Ascendente",
    "Ojiva Descendente"
  ),
  
  col = c(
    "blue",
    "red"
  ),
  
  pch = c(
    16,
    17
  ),
  
  lwd = 2,
  
  bty = "n"
)

grid()

5.8. Ojiva ascentende y descendente (hi)

plot(
  Ls2,
  Hi_asc2,
  type = "o",
  pch = 16,
  lwd = 2,
  col = "blue",
  ylim = c(0,100),
  main = "Ojivas de Frecuencia Relativa Acumulada meteorológica
  mundial con en el período 2024–2026",
  xlab = "UV",
  ylab = "Frecuencia Acumulada (%)"
)

lines(
  Li2,
  Hi_dsc2,
  type = "o",
  pch = 17,
  lwd = 2,
  col = "red"
)

legend(
  "right",
  legend = c(
    "Ascendente",
    "Descendente"
  ),
  col = c("blue","red"),
  pch = c(16,17),
  lwd = 2,
  bty = "n"
)

grid()

5.9. Bloxplot

Q1 <- quantile(UV, 0.25)

Q3 <- quantile(UV, 0.75)

RIC <- Q3 - Q1

Lim_inf <- Q1 - 1.5 * RIC

Lim_sup <- Q3 + 1.5 * RIC
bp <- boxplot(
  UV,
  horizontal = TRUE,
  outline = FALSE,
  main = "Gráfico N°6: Boxplot de UV desde el año 2024 al 2026",
  xlab = "UV",
  col = "lightblue"
)

atipicos <- UV[
  UV < Lim_inf |
    UV > Lim_sup
]

points(
  atipicos,
  rep(1, length(atipicos)),
  col = "red",
  pch = 19,
  cex = 0.8
)

abline(v = Lim_inf, col = "blue", lwd = 2, lty = 2)
abline(v = Lim_sup, col = "blue", lwd = 2, lty = 2)

#Outliers

Lim_inf2 <- Q1 - 1.0 * RIC
Lim_sup2 <- Q3 + 1.0 * RIC

atipicos2 <- UV[
  UV < Lim_inf2 |
    UV > Lim_sup2
]

length(atipicos2)
## [1] 2687
legend(
  "topright",
  legend = c(
    "Atípicos",
    "Límites de Tukey"
  ),
  col = c("red", "blue"),
  pch = c(19, NA),
  lty = c(NA, 2),
  lwd = c(NA, 2),
  bty = "n"
)

grid()

6. Indicadores Estadísticos

6.1. Tendencia central

media <- mean(UV)
mediana <- median(UV)

# Moda aproximada usando la clase modal
tabla_moda <- TDF_UV[TDF_UV$`Lim. Inf.` != "TOTAL", ] # <-- CORREGIDO CON COMILLAS INVERTIDAS
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(UV)

desv_est <- sd(UV)

cv <- (desv_est / media) * 100

6.3. Forma

asimetria <- skewness(UV)

curtosis <- kurtosis(UV)

6.4. Valores atípicos

Q1 <- quantile(UV, 0.25)

Q3 <- quantile(UV, 0.75)

RIC <- Q3 - Q1

lim_inf <- Q1 - 1.5 * RIC

lim_sup <- Q3 + 1.5 * RIC

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

n_atipicos <- length(atipicos)

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

# Rango

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

6.5. Tabla de indicadores

tabla_indicadores <- data.frame(
  
  Variable = "UV",
  
  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°5. Indicadores estadísticos de la variable UV desde año 2024 a 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°5. Indicadores estadísticos de la variable UV desde año 2024 a 2026
Variable Rango Media Mediana Moda Varianza Desv_Est CV Asimetria Curtosis Limite_Atipicos N_Atipicos
UV [0; 16.3] 3.27 1.8 1 12.51 3.54 108.1 0.93 -0.11 [-8.75; 14.85] 222

7. Conclusiones

El comportamiento de la radiación UV se describe de la siguiente manera: fluctúa entre el valor mínimo y el valor máximo registrados, y sus valores giran en torno a la mediana debido a la presencia de valores atípicos, con una desviación estándar que define si es un conjunto de datos homogéneo, heterogéneo o muy heterogéneo. El conjunto de valores se concentra según su curtosis en la parte baja, alta o media de la distribución de acuerdo a su asimetría. Por todo lo anterior, el comportamiento de la variable es perjudicial.