Se inició usando el paquete pacman para poder gestionar mejor las librerias al momento de cargas los paquetes. Este paquete resultó ser una herramienta esencial para mantener un sistema actualizado de manera eficiente y sencilla.
if (!require("pacman")) install.packages("pacman")
pacman::p_load(
# estos son usados en la manipulación de datos
dplyr, tidyr, purrr, data.table,
# los paquetes para Visualizar los datos
ggplot2, corrplot, visdat, naniar, patchwork,
# análisis
outliers, EnvStats, moments,
# imputación
mice, VIM,
# lectura de datos
readr, httr
)
Para descargar y procesar los datos de temperatura global
directamente de la NASA y asegurando una completa compatibilidad ante
posibles cambios en el formato, se definió la base de datos como una
función y utilizando el comando (tryCatch)
se manejaron los
errores.
get_nasa_temp_data <- function() {
url <- "https://data.giss.nasa.gov/gistemp/tabledata_v4/T_AIRS/GLB.Ts+dSST.txt"
tryCatch({
temp_file <- tempfile()
download.file(url, temp_file, mode = "wb", quiet = TRUE)
all_lines <- readLines(temp_file)
data_lines <- all_lines[grep("^\\s*[0-9]{4}", all_lines)]
temp_data <- data.table::fread(
text = paste(data_lines, collapse = "\n"),
header = FALSE,
na.strings = c("****", "***", "NA", ""),
colClasses = list(character = 1)
)
month_names <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
if (ncol(temp_data) == 1) {
names(temp_data) <- "Year"
} else if (ncol(temp_data) <= 13) {
names(temp_data) <- c("Year", month_names[1:(ncol(temp_data)-1)])
} else {
names(temp_data) <- c("Year", month_names, paste0("V", 14:ncol(temp_data)))
}
temp_data <- as.data.frame(temp_data) %>%
select(-starts_with("V")) %>%
mutate(Year = as.integer(Year)) %>%
filter(!is.na(Year)) %>%
select(where(~!all(is.na(.))))
return(temp_data)
}, error = function(e) {
message("Error en método principal: ", e$message)
message("Intentando alternativa...")
tryCatch({
response <- httr::GET(url)
content <- httr::content(response, "text", encoding = "UTF-8")
lines <- unlist(strsplit(content, "\n"))
data_lines <- lines[grepl("^\\s*[0-9]{4}", lines)]
temp_data <- read_table(
paste(data_lines, collapse = "\n"),
col_names = FALSE,
na = c("****", "***", "NA", ""),
col_types = cols(X1 = col_integer(), .default = col_double())
)
names(temp_data) <- c("Year", month.abb[1:(ncol(temp_data)-1)])
return(temp_data)
}, error = function(e) {
message("Error en método alternativo: ", e$message)
return(data.frame(Year = integer()))
})
})
}
Se tienen que comprobar que los datos hayan cargado correctamente y que el rango y columnas sean coherentes.
(nrow(temp_data) > 0)
cat("Cargando datos de la NASA")
## Cargando datos de la NASA
temp_data <- get_nasa_temp_data()
if (nrow(temp_data) == 0) {
stop("No se pudieron cargar los datos. Verifique conexión o formato.")
}
cat(" Datos fueron cargados correctamente")
## Datos fueron cargados correctamente
cat("Periodo:", range(temp_data$Year), "\n")
## Periodo: 2002 2025
cat("Columnas:", names(temp_data), "\n\n")
## Columnas: Year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
El objetivo de este analisis exploratorio es obtener una visión mas generalizada de la distribución de temperaturas por mes, para esto se realizó lo siguiente:
Cálculo de media, desviación estándar, mediana, mínimo, máximo,
asimetría (skewness)
y cantidad de valores faltantes (NA)
por mes.
Uso de summarise(across(...))
para aplicar las
métricas a todas las columnas de temperatura.
desc_stats <- temp_data %>%
select(-Year) %>%
summarise(across(
everything(),
list(
Mean = ~mean(., na.rm = TRUE),
SD = ~sd(., na.rm = TRUE),
Median = ~median(., na.rm = TRUE),
Min = ~min(., na.rm = TRUE),
Max = ~max(., na.rm = TRUE),
Skew = ~moments::skewness(., na.rm = TRUE),
NAs = ~sum(is.na(.))
),
.names = "{col}_{fn}"
))
print(t(desc_stats))
## [,1]
## Jan_Mean 10.2714286
## Jan_SD 21.6379440
## Jan_Median 10.0000000
## Jan_Min -43.0000000
## Jan_Max 64.0000000
## Jan_Skew -0.1099284
## Jan_NAs 2.0000000
## Feb_Mean 12.5000000
## Feb_SD 25.2367055
## Feb_Median 12.0000000
## Feb_Min -34.0000000
## Feb_Max 76.0000000
## Feb_Skew 0.3879957
## Feb_NAs 2.0000000
## Mar_Mean 11.5571429
## Mar_SD 23.9405276
## Mar_Median 9.0000000
## Mar_Min -40.0000000
## Mar_Max 60.0000000
## Mar_Skew 0.2900997
## Mar_NAs 2.0000000
## Apr_Mean 6.9714286
## Apr_SD 19.1386788
## Apr_Median 7.0000000
## Apr_Min -27.0000000
## Apr_Max 57.0000000
## Apr_Skew 0.4306791
## Apr_NAs 2.0000000
## May_Mean 3.8571429
## May_SD 17.6645766
## May_Median 5.5000000
## May_Min -45.0000000
## May_Max 43.0000000
## May_Skew -0.2055614
## May_NAs 2.0000000
## Jun_Mean 7.0857143
## Jun_SD 17.2280046
## Jun_Median 3.0000000
## Jun_Min -25.0000000
## Jun_Max 53.0000000
## Jun_Skew 0.4446120
## Jun_NAs 2.0000000
## Jul_Mean 6.8571429
## Jul_SD 19.8452606
## Jul_Median 3.0000000
## Jul_Min -40.0000000
## Jul_Max 54.0000000
## Jul_Skew 0.3169704
## Jul_NAs 2.0000000
## Aug_Mean 4.7164179
## Aug_SD 18.6870608
## Aug_Median 3.0000000
## Aug_Min -33.0000000
## Aug_Max 58.0000000
## Aug_Skew 0.5365766
## Aug_NAs 5.0000000
## Sep_Mean 5.9275362
## Sep_SD 19.4318711
## Sep_Median 2.0000000
## Sep_Min -25.0000000
## Sep_Max 76.0000000
## Sep_Skew 1.1149175
## Sep_NAs 3.0000000
## Oct_Mean 6.5507246
## Oct_SD 18.1355486
## Oct_Median 7.0000000
## Oct_Min -24.0000000
## Oct_Max 59.0000000
## Oct_Skew 0.7130196
## Oct_NAs 3.0000000
## Nov_Mean 2.0724638
## Nov_SD 20.8455940
## Nov_Median 0.0000000
## Nov_Min -58.0000000
## Nov_Max 64.0000000
## Nov_Skew 0.2054810
## Nov_NAs 3.0000000
## Dec_Mean 7.4057971
## Dec_SD 21.1467692
## Dec_Median 7.0000000
## Dec_Min -25.0000000
## Dec_Max 69.0000000
## Dec_Skew 0.6798749
## Dec_NAs 3.0000000
En esta sección se identifican los valores ausentes:
vis_miss()
para generar un gráfico que muestra
la distribución de NA por variable y observación.vis_miss(temp_data) +
ggtitle("Distribución de Valores Faltantes") +
theme(plot.title = element_text(hjust = 0.5))
Se observa la forma de distribución de anomalias de temperatura por mes:
(geom_density)
clasificados por
mes para comparar las distribuciones.temp_data %>%
pivot_longer(-Year, names_to = "Month", values_to = "Temp") %>%
ggplot(aes(x = Temp, fill = Month)) +
geom_density(alpha = 0.6) +
facet_wrap(~Month) +
labs(title = "Distribución de Temperaturas por Mes",
x = "Anomalía de Temperatura (°C)") +
theme_minimal() +
theme(legend.position = "none")
En esta sección se detectan los posibles outliers o registros extremos que puedan influir en el analisis realizando:
detect_outliers()
que:
Aplica test de Grubbs para detectar un outlier extremo.
Calcula límites de Hampel para detectar valores fuera de rango (±3 MAD).
Registra el número y porcentaje de valores fuera de estos límites.
detect_outliers <- function(data) {
outliers_list <- list()
for (col in names(data)[-1]) {
x <- data[[col]]
x <- x[!is.na(x)]
grubbs_test <- tryCatch(grubbs.test(x), error = function(e) NULL)
hampel_lim <- median(x) + 3 * mad(x) * c(-1, 1)
outliers <- x < hampel_lim[1] | x > hampel_lim[2]
outliers_list[[col]] <- list(
Grubbs = grubbs_test,
Hampel_Limits = hampel_lim,
Outlier_Count = sum(outliers),
Outlier_Pct = mean(outliers) * 100
)
}
return(outliers_list)
}
outliers_analysis <- detect_outliers(temp_data)
walk(names(outliers_analysis), ~{
cat(.x, ":\n")
print(outliers_analysis[[.x]][1:3])
cat("\n")
})
## Jan :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.48307, U = 0.90935, p-value = 0.3961
## alternative hypothesis: highest value 64 is an outlier
##
##
## $Hampel_Limits
## [1] -38.9258 58.9258
##
## $Outlier_Count
## [1] 3
##
##
## Feb :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.51618, U = 0.90691, p-value = 0.3578
## alternative hypothesis: highest value 76 is an outlier
##
##
## $Hampel_Limits
## [1] -61.3887 85.3887
##
## $Outlier_Count
## [1] 0
##
##
## Mar :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.15355, U = 0.93181, p-value = 1
## alternative hypothesis: lowest value -40 is an outlier
##
##
## $Hampel_Limits
## [1] -75.5082 93.5082
##
## $Outlier_Count
## [1] 0
##
##
## Apr :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.61400, U = 0.89954, p-value = 0.2628
## alternative hypothesis: highest value 57 is an outlier
##
##
## $Hampel_Limits
## [1] -59.717 73.717
##
## $Outlier_Count
## [1] 0
##
##
## May :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.76583, U = 0.88753, p-value = 0.1589
## alternative hypothesis: lowest value -45 is an outlier
##
##
## $Hampel_Limits
## [1] -52.3214 63.3214
##
## $Outlier_Count
## [1] 0
##
##
## Jun :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.66510, U = 0.89557, p-value = 0.2226
## alternative hypothesis: highest value 53 is an outlier
##
##
## $Hampel_Limits
## [1] -32.5824 38.5824
##
## $Outlier_Count
## [1] 4
##
##
## Jul :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.37552, U = 0.91703, p-value = 0.5461
## alternative hypothesis: highest value 54 is an outlier
##
##
## $Hampel_Limits
## [1] -57.0453 63.0453
##
## $Outlier_Count
## [1] 0
##
##
## Aug :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.85136, U = 0.87495, p-value = 0.1115
## alternative hypothesis: highest value 58 is an outlier
##
##
## $Hampel_Limits
## [1] -41.478 47.478
##
## $Outlier_Count
## [1] 1
##
##
## Sep :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 3.60606, U = 0.80596, p-value = 0.005242
## alternative hypothesis: highest value 76 is an outlier
##
##
## $Hampel_Limits
## [1] -51.3736 55.3736
##
## $Outlier_Count
## [1] 2
##
##
## Oct :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.89207, U = 0.87519, p-value = 0.1002
## alternative hypothesis: highest value 59 is an outlier
##
##
## $Hampel_Limits
## [1] -55.2692 69.2692
##
## $Outlier_Count
## [1] 0
##
##
## Nov :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.9708, U = 0.8683, p-value = 0.0752
## alternative hypothesis: highest value 64 is an outlier
##
##
## $Hampel_Limits
## [1] -44.478 44.478
##
## $Outlier_Count
## [1] 3
##
##
## Dec :
## $Grubbs
##
## Grubbs test for one outlier
##
## data: x
## G = 2.9127, U = 0.8734, p-value = 0.09302
## alternative hypothesis: highest value 69 is an outlier
##
##
## $Hampel_Limits
## [1] -55.2692 69.2692
##
## $Outlier_Count
## [1] 0
Este paso se hace para completar los datos ausentes para poder hacer un mejor analisis:
(pmm, norm.predict, mean)
con mice.if (sum(is.na(temp_data)) > 0) {
methods <- c("pmm", "norm.predict", "mean")
imputed_data <- map(methods, ~{
imp <- mice(temp_data, method = .x, m = 1, maxit = 5, seed = 123)
complete(imp)
})
map2(imputed_data, methods, ~{
.x %>%
pivot_longer(-Year, names_to = "Month", values_to = "Temp") %>%
ggplot(aes(x = Temp)) +
geom_histogram(bins = 30, fill = "steelblue") +
facet_wrap(~Month, scales = "free") +
ggtitle(paste("Distribución después de imputación -", .y)) +
theme_minimal()
})
}
##
## iter imp variable
## 1 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 2 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 3 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 4 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 5 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
##
## iter imp variable
## 1 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 2 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 3 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 4 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 5 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
##
## iter imp variable
## 1 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 2 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 3 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 4 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 5 1 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## [[1]]
##
## [[2]]
##
## [[3]]
Analizar la evoución de la T media anual a lo largo del tiempo, con:
(rowMeans)
(geom_line)
con ajuste de
suavizado LOESS (geom_smooth)
annual_data <- temp_data %>%
mutate(Annual = rowMeans(select(., -Year), na.rm = TRUE))
ggplot(annual_data, aes(x = Year, y = Annual)) +
geom_line(color = "red3", size = 1) +
geom_smooth(method = "loess", color = "blue", se = FALSE) +
labs(title = "Evolución de la Temperatura Global Anual",
y = "Anomalía de Temperatura (°C)",
caption = "Datos: NASA GISTEMP") +
theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_smooth()` using formula = 'y ~ x'
Esta matriz se realizó con la finalidad de analizar la relación entre las anomalias de temperatura de diferentes meses:
Cálculo de matriz de correlaciones (cor)
ignorando
valores faltantes.
Visualización con corrplot mostrando coeficientes y color.
cor_matrix <- cor(temp_data[, -1], use = "complete.obs")
corrplot(cor_matrix, method = "color", type = "upper",
tl.col = "black", addCoef.col = "black",
number.cex = 0.7, title = "Correlación entre Meses")
Los resultados seran exportados en un archivo “nasa_global_temps_clean.csv” de manera que puedan ser utilizados en futuros analisis.
write_csv(temp_data, "nasa_global_temps_clean.csv")
write_csv(desc_stats %>% t() %>% as.data.frame(), "nasa_temp_stats.csv")
cat("ANÁLISIS COMPLETADO")
## ANÁLISIS COMPLETADO