Funció de verificació prèvia per assegurar que un dataframe és segur
abans d’utilitzar openair. Ara amb autofix integrat.
openair_preflight() amb Autofix
openair_preflight <- function(
df,
key = c("date","pollutant"),
tz = "UTC",
min_days = 21,
autofix = TRUE,
verbose = TRUE
) {
library(dplyr)
library(lubridate)
report <- list()
# 1️⃣ Columnes bàsiques
required_cols <- c("date", "pollutant", "value")
missing_cols <- setdiff(required_cols, names(df))
if(length(missing_cols) > 0) stop("❌ Falten columnes: ", paste(missing_cols, collapse = ", "))
report$columns <- "OK"
# 2️⃣ Tipus de dades
if(!inherits(df$date,"POSIXct")) {
if(verbose) message("⚠️ 'date' no és POSIXct → convertint")
df$date <- as.POSIXct(df$date, tz=tz)
}
df$pollutant <- as.factor(df$pollutant)
df$value <- as.numeric(df$value)
report$types <- "OK"
# 3️⃣ NA crítics
na_rows <- sum(is.na(df$date) | is.na(df$pollutant) | is.na(df$value))
report$na_rows <- na_rows
if(na_rows>0 & verbose) message("⚠️ Files amb NA crítics: ", na_rows)
# 4️⃣ Autofix segur
if(autofix) {
# elimina NA crítics
df <- df %>% filter(!is.na(date), !is.na(pollutant), !is.na(value))
# ordena dates
if(is.unsorted(df$date)) {
df <- df[order(df$date),]
if(verbose) message("🔧 Dates ordenades")
}
# factors nets
df$pollutant <- droplevels(df$pollutant)
# duplicats exactes
dup <- df %>% count(across(all_of(key))) %>% filter(n>1)
if(nrow(dup)>0) {
if(verbose) message("🔧 Duplicats exactes detectats: ", nrow(dup), " → col·lapsant")
df <- df %>% group_by(across(all_of(key))) %>%
summarise(value = mean(value), .groups="drop")
}
}
# 5️⃣ Duplicats reals
dup_check <- df %>% count(across(all_of(key))) %>% filter(n>1)
report$duplicate_groups <- nrow(dup_check)
if(nrow(dup_check)>0 & verbose) warning("❌ Duplicats reals detectats (clau: ", paste(key, collapse="+"), ")")
# 6️⃣ Cobertura temporal
coverage <- df %>% group_by(pollutant) %>%
summarise(ndays=n_distinct(as.Date(date)), .groups="drop")
report$coverage <- coverage
if(any(coverage$ndays < min_days) & verbose) message("⚠️ Pollutants amb poca cobertura temporal")
# 7️⃣ Informe final
if(verbose) {
message("✅ Preflight complet")
message(" Files finals: ", nrow(df))
message(" Pollutants: ", paste(levels(df$pollutant), collapse=", "))
}
return(list(data=df, report=report))
}
# 1️⃣ Executa preflight amb autofix
pf <- openair_preflight(df, autofix = TRUE)
# 2️⃣ Agafa dades netes
df_ok <- pf$data
# 3️⃣ Consulta report
pf$report
# 4️⃣ Crida openair amb seguretat
timeVariation(mydata = df_ok, pollutant = "NO2")