options(warn = -1)

Objetivo:Evaluar la contaminación por ozono en distintas regiones de California durante el año 2024, identificando tendencias temporales, zonas de alto riesgo y el impacto de la actividad urbana, con el fin de orientar posibles intervenciones ambientales.

Diccionario de Variables: El conjunto de datos contiene estadísticas diarias de calidad del aire por sitio de monitoreo. A continuación, se describen las variables clave Variable Descripción Date Fecha del registro Source Fuente de datos (AQS o AirNow) Site ID Identificador del sitio de monitoreo POC Número del monitor Daily_Max_8hour_Ozone_Concentration Máximo valor de ozono en intervalo de 8horas(ppm) Units Unidades de concentración (ppm)
Daily AQI Value Índice de calidad del aire diario (AQI) Local Site Name Nombre del sitio de monitoreo Daily Obs Count Número de observaciones del día Percent Complete Porcentaje de datos recolectados Method Code Código del método de medición CBSA Code Código del área estadística básica central CBSA Name Nombre del área estadística State FIPS Code Código FIPS del estado State Nombre del estado County FIPS Code Código FIPS del condado County Nombre del condado Site Latitude Latitud del sitio Site Longitude Longitud del sitio

como primer paso antes de importar los datos, se instalaran y habilitaran las libererias a utilizar, estas son: mice para la imputación de datos tidyverse para graficos, tablas e importación de datos readr para importar datos en formato excel

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.2     ✔ tibble    3.3.0
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(mice)
## 
## Adjuntando el paquete: 'mice'
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following objects are masked from 'package:base':
## 
##     cbind, rbind

Importando y verificando el tipo de variable

ozono <- read_delim("ozono.csv", delim = ";", escape_double = FALSE, col_types = cols(`Site ID` = col_number(), POC = col_number(), `Daily Max 8-hour Ozone Concentration` = col_number(), `Daily AQI Value` = col_number(), `Site Latitude` = col_number(), `Site Longitude` = col_number()), trim_ws = TRUE)
str(ozono)
## spc_tbl_ [54,759 × 17] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ Date                                : chr [1:54759] "/2024" "1/2/2024" "/2024" "January 04/2024" ...
##  $ Source                              : chr [1:54759] "AQS" "AQS" "AQS" "AQS" ...
##  $ Site ID                             : num [1:54759] 6e+07 6e+07 6e+07 6e+07 6e+07 ...
##  $ POC                                 : num [1:54759] 1 1 1 1 1 1 1 1 1 1 ...
##  $ Daily Max 8-hour Ozone Concentration: num [1:54759] 0.031 0.037 NA 0.026 0.027 0.031 0.03 0.027 0.034 0.036 ...
##  $ Units                               : chr [1:54759] "ppm" "ppm" "ppm" "ppm" ...
##  $ Daily AQI Value                     : num [1:54759] 29 34 30 24 25 29 28 25 31 33 ...
##  $ Local Site Name                     : chr [1:54759] "Livermore" "Livermore" "Livermore" "Livermore" ...
##  $ Daily Obs Count                     : num [1:54759] 17 17 17 17 17 17 17 17 17 17 ...
##  $ Percent Complete                    : num [1:54759] 100 100 100 100 100 100 100 100 100 100 ...
##  $ Method Code                         : num [1:54759] 47 47 47 47 47 47 47 47 47 47 ...
##  $ CBSA Code                           : num [1:54759] 41860 41860 41860 41860 41860 ...
##  $ CBSA Name                           : chr [1:54759] "San Francisco-Oakland-Hayward, CA" "San Francisco-Oakland-Hayward, CA" "San Francisco-Oakland-Hayward, CA" "San Francisco-Oakland-Hayward, CA" ...
##  $ County FIPS Code                    : num [1:54759] 1 1 1 1 1 1 1 1 1 1 ...
##  $ County                              : chr [1:54759] "Alameda" "Alameda" "Alameda" "Alameda" ...
##  $ Site Latitude                       : num [1:54759] 37.7 37.7 37.7 37.7 37.7 ...
##  $ Site Longitude                      : num [1:54759] -122 -122 -122 -122 -122 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   Date = col_character(),
##   ..   Source = col_character(),
##   ..   `Site ID` = col_number(),
##   ..   POC = col_number(),
##   ..   `Daily Max 8-hour Ozone Concentration` = col_number(),
##   ..   Units = col_character(),
##   ..   `Daily AQI Value` = col_number(),
##   ..   `Local Site Name` = col_character(),
##   ..   `Daily Obs Count` = col_double(),
##   ..   `Percent Complete` = col_double(),
##   ..   `Method Code` = col_double(),
##   ..   `CBSA Code` = col_double(),
##   ..   `CBSA Name` = col_character(),
##   ..   `County FIPS Code` = col_double(),
##   ..   County = col_character(),
##   ..   `Site Latitude` = col_number(),
##   ..   `Site Longitude` = col_number()
##   .. )
##  - attr(*, "problems")=<externalptr>

La variable Date se encuentra en formato de texto y presenta múltiples estilos de fecha, esto puede generar inconsistencias en el análisis. Como primer paso, es necesario unificar su formato. Para ello, se utilizarán las librerías lubridate (para el reconocimiento y conversión de fechas) y stringr (para el manejo eficiente de cadenas de texto), asegurando así una estructura coherente y lista para análisis cronológicos precisos.

library(lubridate)
library(stringr)
#creando la variable year de la variable Date
ozono<-ozono%>%mutate(Date_Procesado=if_else(str_detect(Date,"^/\\d{4}$"),
paste0("01/01/",Date),Date))
posibles_formatos<- c(
"%B %d/%Y", # "January 04/2024" (Mes completo, día/año)
"%m/%d/%Y", # "02/02/2024" (Mes/Día/Año)
"%d/%m/%Y", # "02/02/2024" (Día/Mes/Año)
"%Y-%m-%d", # "2024-01-01" (Formato ISO)
"%Y/%m/%d", # "2024/01/01"
"%m-%d-%Y", # "01-01-2024"
"%d-%m-%Y", # "01-01-2024"
"%B %d, %Y", # "January 04, 2024" (con coma)
"%b %d, %Y", # "Jan 04, 2024" (Mes abreviado con coma)
"%b %d %Y", # "Jan 04 2024" (Mes abreviado sin coma)
"%Y",
"mdy",
"dmy",
"ymd"
)
ozono<-ozono%>%mutate(Date_formato_fecha=parse_date_time(Date_Procesado,
                    orders=posibles_formatos))
ozono<-ozono%>%mutate(year=year(Date_formato_fecha))

Se verifica nuevamente con head

head(ozono[,18:20])
## # A tibble: 6 × 3
##   Date_Procesado  Date_formato_fecha   year
##   <chr>           <dttm>              <dbl>
## 1 01/01//2024     2024-01-01 00:00:00  2024
## 2 1/2/2024        2024-01-02 00:00:00  2024
## 3 01/01//2024     2024-01-01 00:00:00  2024
## 4 January 04/2024 2024-01-04 00:00:00  2024
## 5 January 05/2024 2024-01-05 00:00:00  2024
## 6 January 06/2024 2024-01-06 00:00:00  2024

Ya que se ha creado la variable Date_formato_fecha y la variable year, la variable original Date,no sera requerida en los analisis posteriores, por tanto se elimina del data frame ozone.

ozono<-ozono%>%select(-Date)

Analisis de los NA se requiere conocer que variables presentan NA, para ello la funcion is.na() y colSums(), estas funciones son las más indicada,esta función devuelve el numero de NA por columnas.

print(as.data.frame(colSums(is.na(ozono))))
##                                      colSums(is.na(ozono))
## Source                                                   0
## Site ID                                                  0
## POC                                                      0
## Daily Max 8-hour Ozone Concentration                  2738
## Units                                                    0
## Daily AQI Value                                       2738
## Local Site Name                                          0
## Daily Obs Count                                          0
## Percent Complete                                         0
## Method Code                                           6490
## CBSA Code                                             2408
## CBSA Name                                             2408
## County FIPS Code                                         0
## County                                                   0
## Site Latitude                                            0
## Site Longitude                                           0
## Date_Procesado                                           0
## Date_formato_fecha                                       0
## year                                                     0
print(as.data.frame(colSums(is.na(ozono))))
##                                      colSums(is.na(ozono))
## Source                                                   0
## Site ID                                                  0
## POC                                                      0
## Daily Max 8-hour Ozone Concentration                  2738
## Units                                                    0
## Daily AQI Value                                       2738
## Local Site Name                                          0
## Daily Obs Count                                          0
## Percent Complete                                         0
## Method Code                                           6490
## CBSA Code                                             2408
## CBSA Name                                             2408
## County FIPS Code                                         0
## County                                                   0
## Site Latitude                                            0
## Site Longitude                                           0
## Date_Procesado                                           0
## Date_formato_fecha                                       0
## year                                                     0

Se identificaron cinco variables que presentan valores faltantes (NA). Entre ellas, dos son variables numéricas: Daily Max 8-hour Ozone Concentration Daily AQI Value Estas serán tratadas posteriormente, ya que su ausencia puede estar relacionada con condiciones específicas de medición o disponibilidad de datos. Por otro lado, las variables Method Code y CBSA Code, aunque numéricas, representan códigos categóricos. La presencia de NA en estas columnas podría deberse a errores de tipeo o a la falta de registro en ciertas observaciones. Para comprender mejor su comportamiento, se imprimirá una tabla con los valores únicos y su frecuencia. Finalmente, se prestará especial atención a la variable CBSA Name, de tipo carácter, ya que su ausencia puede afectar directamente la identificación geográfica de los datos. Se realizará un análisis detallado de los NA en esta columna como primer paso.

table(ozono$`CBSA Name`)
## 
##                               Bakersfield, CA 
##                                          2878 
##                                    Bishop, CA 
##                                          1009 
##                                     Chico, CA 
##                                           719 
##                                 Clearlake, CA 
##                                           360 
##                                 El Centro, CA 
##                                          1204 
##                     Eureka-Arcata-Fortuna, CA 
##                                           344 
##                                    Fresno, CA 
##                                          2541 
##                          Hanford-Corcoran, CA 
##                                           363 
##            Los Angeles-Long Beach-Anaheim, CA 
##                                          5044 
##                                    Madera, CA 
##                                           725 
##                                    Merced, CA 
##                                           375 
##                                   Modesto, CA 
##                                           730 
##              Oxnard-Thousand Oaks-Ventura, CA 
##                                          1833 
##                                 Red Bluff, CA 
##                                           583 
##                                   Redding, CA 
##                                           976 
##          Riverside-San Bernardino-Ontario, CA 
##                                          7188 
##       Sacramento--Roseville--Arden-Arcade, CA 
##                                          5048 
##                                   Salinas, CA 
##                                          1100 
##                        San Diego-Carlsbad, CA 
##                                          3227 
##             San Francisco-Oakland-Hayward, CA 
##                                          3508 
##            San Jose-Sunnyvale-Santa Clara, CA 
##                                          1835 
## San Luis Obispo-Paso Robles-Arroyo Grande, CA 
##                                          2181 
##                    Santa Cruz-Watsonville, CA 
##                                           371 
##                 Santa Maria-Santa Barbara, CA 
##                                          3198 
##                                Santa Rosa, CA 
##                                           276 
##                                    Sonora, CA 
##                                           365 
##                             Stockton-Lodi, CA 
##                                           716 
##                      Truckee-Grass Valley, CA 
##                                           361 
##                                     Ukiah, CA 
##                                           446 
##                         Vallejo-Fairfield, CA 
##                                           956 
##                       Visalia-Porterville, CA 
##                                          1306 
##                                 Yuba City, CA 
##                                           585

Esta variable corresponde a los nombre de las ciudades del estado de California. los valores faltantes (NAs) seran reemplazados por ‘No CBSA’.

ozono<- ozono%>%mutate(`CBSA Name` = if_else(is.na(`CBSA Name`), "No CBSA", `CBSA Name`))

se imprimen las tablas para las variables Method Code y CBSA Code

table(ozono$`Method Code`)
## 
##    47    53    87   199 
##  8545   392 35277  4055
table(ozono$`CBSA Code`)
## 
## 12540 13860 17020 17340 20940 21700 23420 25260 31080 31460 32900 33700 37100 
##  2878  1009   719   360  1204   344  2541   363  5044   725   375   730  1833 
## 39780 39820 40140 40900 41500 41740 41860 41940 42020 42100 42200 42220 43760 
##   583   976  7188  5048  1100  3227  3508  1835  2181   371  3198   276   365 
## 44700 46020 46380 46700 47300 49700 
##   716   361   446   956  1306   585

para las variables CBSA Code Y Method Code, dado que son identificadores discretos, se precede a sustituir por NA=1000 en el caso de CBSA Code y Method Code los NA=100.

ozono<- ozono %>%mutate(
`CBSA Code` = as.numeric(`CBSA Code`),
`CBSA Code` = if_else(is.na(`CBSA Code`), 10000, `CBSA Code`),
`Method Code` = as.numeric(`Method Code`),
`Method Code` = if_else(is.na(`Method Code`), 100, `Method Code`))
print(as.data.frame(colSums(is.na(ozono))))
##                                      colSums(is.na(ozono))
## Source                                                   0
## Site ID                                                  0
## POC                                                      0
## Daily Max 8-hour Ozone Concentration                  2738
## Units                                                    0
## Daily AQI Value                                       2738
## Local Site Name                                          0
## Daily Obs Count                                          0
## Percent Complete                                         0
## Method Code                                              0
## CBSA Code                                                0
## CBSA Name                                                0
## County FIPS Code                                         0
## County                                                   0
## Site Latitude                                            0
## Site Longitude                                           0
## Date_Procesado                                           0
## Date_formato_fecha                                       0
## year                                                     0

Antes de decidir el método de imputación más adecuado para las variables numéricas con valores faltantes, se explorará la presencia de posibles valores atípicos (outliers). Esta evaluación es crucial, ya que la existencia de outliers puede sesgar la media, haciendo que la mediana sea una opción más robusta para la imputación. El análisis permitirá tomar una decisión informada entre imputar con la media o la mediana, según el comportamiento de los datos.

par(mfrow = c(1,2))
vars_con_na <- names(ozono)[sapply(ozono, anyNA)]
print(vars_con_na)
## [1] "Daily Max 8-hour Ozone Concentration"
## [2] "Daily AQI Value"
sapply(ozono[vars_con_na], class)
## Daily Max 8-hour Ozone Concentration                      Daily AQI Value 
##                            "numeric"                            "numeric"
for( var in vars_con_na){
boxplot(ozono[[var]],main=paste("Boxplot de",var))
}

Ambas variables numéricas presentan valores atípicos, los cuales, en este contexto, no deben eliminarse, ya que podrían representar picos reales de contaminación y, por tanto, contienen información valiosa para el análisis ambiental. Dado esto, se optará por una estrategia de imputación que preserve la estructura y variabilidad de los datos. Para ello, se utilizará la librería mice (Multivariate Imputation by Chained Equations), aplicando el método Predictive Mean Matching (pmm). Este enfoque permite imputar valores faltantes de forma robusta, seleccionando valores observados similares en lugar de generar estimaciones puramente estadísticas, lo que ayuda a mantener la coherencia con la distribución original de los datos.

ozono_na<-ozono%>%select(`Daily Max 8-hour Ozone Concentration` ,`Daily AQI Value`)
summary(ozono_na)
##  Daily Max 8-hour Ozone Concentration Daily AQI Value 
##  Min.   :0.0000                       Min.   :  0.00  
##  1st Qu.:0.0340                       1st Qu.: 31.00  
##  Median :0.0410                       Median : 38.00  
##  Mean   :0.0435                       Mean   : 45.28  
##  3rd Qu.:0.0520                       3rd Qu.: 48.00  
##  Max.   :0.1390                       Max.   :236.00  
##  NA's   :2738                         NA's   :2738
imputado<-mice(ozono_na,m=5,maxit=10,method = "pmm",seed = 123)
## 
##  iter imp variable
##   1   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   1   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   1   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   1   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   1   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   2   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   2   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   2   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   2   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   2   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   3   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   3   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   3   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   3   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   3   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   4   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   4   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   4   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   4   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   4   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   5   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   5   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   5   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   5   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   5   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   6   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   6   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   6   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   6   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   6   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   7   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   7   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   7   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   7   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   7   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   8   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   8   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   8   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   8   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   8   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   9   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   9   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   9   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   9   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   9   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   10   1  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   10   2  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   10   3  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   10   4  Daily Max 8-hour Ozone Concentration  Daily AQI Value
##   10   5  Daily Max 8-hour Ozone Concentration  Daily AQI Value
ozono_imputado<-complete(imputado)

Verificandi los NAs

print(as.data.frame(colSums(is.na(ozono_imputado))))
##                                      colSums(is.na(ozono_imputado))
## Daily Max 8-hour Ozone Concentration                              0
## Daily AQI Value                                                   0

La imputación de los NA se ha realizado, el siguiente paso es eliminar las variables del date frame ozone para reemplazar con estas variables ya imputadas. Esto se realizara usando el comando select y mutate.

ozono<-ozono%>%mutate(Daily_Max_8hour_Ozone_Concentration=ozono_imputado$`Daily Max 8-hour Ozone Concentration`,Daily_AQI_Value=ozono_imputado$`Daily AQI Value`)
ozono<-ozono%>%select(-`Daily Max 8-hour Ozone Concentration`,-`Daily AQI Value`)

Revisando los NAs

print(sum(is.na(ozono)))
## [1] 0

La suma de los NAs es cero, esto implica que no exiten valores nulos dentro del data frame. ¿Cómo varía la concentración máxima diaria de ozono de 8 horas con el tiempo y las regiones? Para responder a la pregunta se creara la variable month, esto con el fin de observar la variacion mensual durante el ano 2024

ozono<-ozono%>%mutate(month=month(Date_formato_fecha))
print(table(ozono$month))
## 
##     1     2     3     4     5     6     7     8     9    10    11    12 
## 13016  3571  3681  3672  3853  3804  3957  3905  3851  3945  3690  3814

El objetivo es analizar cómo varía el promedio de contaminación a lo largo de los meses del año 2024. Para visualizar esta evolución temporal de manera clara y efectiva, el tipo de gráfico más adecuado es un gráfico de líneas, ya que permite identificar tendencias, patrones estacionales y posibles picos de contaminación mes a mes.

ozono_media_mensual<-ozono%>%group_by(month)%>%summarise(avg_ozone=mean(Daily_Max_8hour_Ozone_Concentration))
head(ozono_media_mensual)
## # A tibble: 6 × 2
##   month avg_ozone
##   <dbl>     <dbl>
## 1     1    0.0399
## 2     2    0.0363
## 3     3    0.0407
## 4     4    0.0464
## 5     5    0.0484
## 6     6    0.0499

Con el fin de visualizar mejor esta distribución, se hara uso del grafico de linea.

ggplot(ozono_media_mensual, aes(x = factor(month, levels = 1:12), y = avg_ozone, group = 1)) +
geom_line(color = "darkgreen", size = 1) +
geom_point(color = "darkgreen", size = 3) +
labs(title = "Tendencia Mensual de Concentración de Ozono Año 2024",
x = "Mes",
y = "Concentración Promedio de Ozono (ppm)") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

El gráfico muestra una clara tendencia estacional en la concentración promedio de ozono a lo largo del año 2024. Las concentraciones son notablemente bajas al inicio y final del año, indicando menores niveles de ozono en los meses más fríos, esto coincide con las estaciones de invierno y otoño. Se observa un aumento constante desde finales de febrero y principios de marzo hasta alcanzar un pico máximo alrededor de finales de junio y principios de julio. Este pico en los meses de verano es consistente con el conocimiento de que la formación de ozono troposférico se ve favorecida por altas temperaturas y mayor radiación solar. A partir del pico de verano, la concentración promedio de ozono comienza un descenso progresivo hacia los últimos meses del año. Del grafico anterior surge la pregunta, Que región presenta la mayor cantidad promedio de ozono? Para obtener el promedio de ozono por región, se creara un resumen del mismo

Avg_regiones<-ozono%>%mutate(Region=as.factor(ozono$`CBSA Name`))%>%group_by(Region)%>%summarise(Promedio_region=mean(Daily_Max_8hour_Ozone_Concentration),Mediana_region=median(Daily_Max_8hour_Ozone_Concentration),                                                                                            Desviacion_estandar=sd(Daily_Max_8hour_Ozone_Concentration),
                                                                                                Coeficiente_variacion=Desviacion_estandar*100/
Promedio_region)%>%arrange(desc(Promedio_region))
head(Avg_regiones,20)
## # A tibble: 20 × 5
##    Region                     Promedio_region Mediana_region Desviacion_estandar
##    <fct>                                <dbl>          <dbl>               <dbl>
##  1 Riverside-San Bernardino-…          0.0535          0.05              0.0169 
##  2 Visalia-Porterville, CA             0.0520          0.052             0.0188 
##  3 El Centro, CA                       0.0498          0.049             0.0119 
##  4 Bakersfield, CA                     0.0492          0.048             0.0163 
##  5 Los Angeles-Long Beach-An…          0.0475          0.045             0.0156 
##  6 Merced, CA                          0.0462          0.044             0.0158 
##  7 Fresno, CA                          0.0458          0.044             0.0169 
##  8 Hanford-Corcoran, CA                0.0457          0.046             0.0176 
##  9 Yuba City, CA                       0.0453          0.046             0.0114 
## 10 Madera, CA                          0.0452          0.044             0.0150 
## 11 Bishop, CA                          0.0450          0.044             0.00936
## 12 San Diego-Carlsbad, CA              0.0448          0.045             0.0116 
## 13 Modesto, CA                         0.0445          0.043             0.0152 
## 14 Oxnard-Thousand Oaks-Vent…          0.0442          0.043             0.00919
## 15 Sonora, CA                          0.0439          0.043             0.0116 
## 16 No CBSA                             0.0430          0.043             0.0112 
## 17 Truckee-Grass Valley, CA            0.0429          0.041             0.0121 
## 18 Chico, CA                           0.0429          0.042             0.00992
## 19 Redding, CA                         0.0421          0.042             0.0111 
## 20 Sacramento--Roseville--Ar…          0.0413          0.041             0.0125 
## # ℹ 1 more variable: Coeficiente_variacion <dbl>
head(Avg_regiones,20)
## # A tibble: 20 × 5
##    Region                     Promedio_region Mediana_region Desviacion_estandar
##    <fct>                                <dbl>          <dbl>               <dbl>
##  1 Riverside-San Bernardino-…          0.0535          0.05              0.0169 
##  2 Visalia-Porterville, CA             0.0520          0.052             0.0188 
##  3 El Centro, CA                       0.0498          0.049             0.0119 
##  4 Bakersfield, CA                     0.0492          0.048             0.0163 
##  5 Los Angeles-Long Beach-An…          0.0475          0.045             0.0156 
##  6 Merced, CA                          0.0462          0.044             0.0158 
##  7 Fresno, CA                          0.0458          0.044             0.0169 
##  8 Hanford-Corcoran, CA                0.0457          0.046             0.0176 
##  9 Yuba City, CA                       0.0453          0.046             0.0114 
## 10 Madera, CA                          0.0452          0.044             0.0150 
## 11 Bishop, CA                          0.0450          0.044             0.00936
## 12 San Diego-Carlsbad, CA              0.0448          0.045             0.0116 
## 13 Modesto, CA                         0.0445          0.043             0.0152 
## 14 Oxnard-Thousand Oaks-Vent…          0.0442          0.043             0.00919
## 15 Sonora, CA                          0.0439          0.043             0.0116 
## 16 No CBSA                             0.0430          0.043             0.0112 
## 17 Truckee-Grass Valley, CA            0.0429          0.041             0.0121 
## 18 Chico, CA                           0.0429          0.042             0.00992
## 19 Redding, CA                         0.0421          0.042             0.0111 
## 20 Sacramento--Roseville--Ar…          0.0413          0.041             0.0125 
## # ℹ 1 more variable: Coeficiente_variacion <dbl>

De la tabla de métricas por región, se extraen conclusiones significativas sobre la concentración de ozono, las ciudades de Riverside-San Bernardino-Ontario y Visalia-Porterville tienen un promedio de contaminación por ozono superior a 0.05 ppm,este umbral es crucial, ya que indica niveles de contaminación potencialmente perjudiciales para la salud pública, otro punto a recalcar es que todas las ciudades del estado de california tienen un coeficiente de variación por encima del 20%, esto indica una alta dispersión de los datos lo que se podria atribuir a las estaciones, ya que la contaminacion en verano es mucho mayor que en las demas estaciones a como se observo en el grafico de lineas anterior.

Avg_regiones%>%head(7)%>%ggplot(aes(x = reorder(Region, Promedio_region), y = Promedio_region)) +
geom_bar(stat = "identity", fill = "steelblue") +
coord_flip() +
labs(title = "Top Regiones con Mayor Concentración Promedio de Ozono",
x = "Región (CBSA Name)",
y = "Concentración Promedio de Ozono (ppm)") +
theme_minimal() +
theme(axis.text.y = element_text(size = 8))

El gráfico de barras horizontal revela que las regiones con las concentraciones promedio de ozono más altas se encuentran predominantemente en California. Regiones como El Centro, Riverside-San Bernardino-Ontario y Visalia-Porterville , exhiben los niveles más elevados, esto se debe que este estado tiene temperauras altas y una gran cantidad de luz solar, lo que favorece la formación de ozono a partir de contaminantes de diversas areas. ¿Existen áreas que muestren consistentemente altas concentraciones de ozono? ¿Los diferentes métodos reportan distintos niveles de ozono? Para poder responder esta pregunta, se efectura el mismo analisis para la variable Method Code

Avg_metodos<-ozono%>%mutate(Metodo=as.factor(ozono$`Method Code`))%>%group_by(Metodo)%>%summarise(Promedio_metodo=mean(Daily_Max_8hour_Ozone_Concentration),Desviacion_estandar=sqrt(var(Daily_Max_8hour_Ozone_Concentration)),
                                                                                              Coeficiente_variacion=Desviacion_estandar*100/Promedio_metodo)%>%arrange(desc(Promedio_metodo))
head(Avg_metodos,5)
## # A tibble: 5 × 4
##   Metodo Promedio_metodo Desviacion_estandar Coeficiente_variacion
##   <fct>            <dbl>               <dbl>                 <dbl>
## 1 53              0.0603              0.0181                  30.1
## 2 199             0.0455              0.0164                  36.0
## 3 87              0.0450              0.0149                  33.0
## 4 47              0.0417              0.0119                  28.5
## 5 100             0.0356              0.0114                  32.0

De la tabla de estadisticos por metodo se extraen algunas conclusiones, el coeficiente de variacion es superior a 25%, lo que indica una alta dispersión o variabilidad inherente en los datos de ozono independientemente del método de recolección, aunque el metodo con codido 47 presenta la menor dispersión de todos , se podria considerar que es el metodo mas preciso, sin embargo el metodo 53 presenta un promedio de 0.0603 la cual es muy elevada, esta tabla nos hace pensar que los metodos de recoleccion de datos se aplicaron en distintas estaciones durante el 2024.

ggplot(ozono, aes(x = as.factor(ozono$`Method Code`), y =Daily_Max_8hour_Ozone_Concentration , fill = as.factor(ozono$`Method Code`))) +geom_violin(alpha = 0.7) + 
scale_fill_brewer(palette = "Set2", name = "Método") +
labs(title = "Distribución de Concentración de Ozono por Método de Medición",
x = "Código de Método",
y = "Concentración de Ozono (ppm)") +
theme_minimal() +theme(axis.text.x = element_text(angle = 45, hjust = 1))

Este grafico viene a reforzar lo antes mencionado en la tabla de estadistico por metodo, es evidente que el metodo empleado tiene un impacto directo en los nives de ozono registrados. El método 100 (que corresponde a los valores imputados de NA) presenta una distribución más concentrada en valores más bajos de ozono, y su violín es más estrecho en la parte superior. Esto sugiere que la imputación tiende a producir valores en el rango más bajo de la escala de ozono, y con menos variabilidad extrema hacia arriba, en comparación con los métodos de medición reales. En cambio los metodos 47, 87 y 199 tienen una distribución de ozono similares entre si, todos los metodos a excepción del 100, presentan una cola superior lo que es consistente con la presecia de eventos de alta concentracion de ozono. Este gráfico viene a fortalecer la idea de que no siempre es bueno eliminar los NA, tambien el metodo empleado influye en los datos obtenidos.

Considera si la actividad urbana (fin de semana vs. día de semana) tiene algún efecto en los niveles de ozono a lo largo de los diferentes días. responder a esta pregunta, podemos crear una variable dia a partir de la variable Date_formato_fecha, luego recodificar esta variable donde tome el valor de weekday para valores de 2 a 6 (corresponde a los dias lunes a viernes) y weekend para valores de 6 y 7 (corresponde a los dias sabado y domingo).

ozono <- ozono %>%
mutate(
dia_semana_num = wday(Date_formato_fecha, week_start = 1),
Tipo_Dia = case_when(
dia_semana_num %in% c(2,3,4,5,6) ~ "Weekday",
TRUE ~ "Weekend"
))
head(ozono[,20:22],5)
## # A tibble: 5 × 3
##   month dia_semana_num Tipo_Dia
##   <dbl>          <dbl> <chr>   
## 1     1              1 Weekend 
## 2     1              2 Weekday 
## 3     1              1 Weekend 
## 4     1              4 Weekday 
## 5     1              5 Weekday

Se desea ver si existe diferencia en la variabilidad en la concentración de ozone en dias de semana y fin de semana,el gráfico más adecuado para responder a esta pregunta es un boxplot.

ggplot(ozono, aes(x = Tipo_Dia, y =Daily_Max_8hour_Ozone_Concentration , fill = (Tipo_Dia))) +
geom_boxplot(alpha = 0.7) + 
scale_fill_brewer(palette = "Set2", name = "Tipo de Dia") +
labs(title = "Distribución de Concentración de Ozono por dia de la semana",
x = "Tipo de dia de la semana",
y = "Concentración de Ozono (ppm)") +
theme_minimal() +theme(axis.text.x = element_text(angle = 45, hjust = 1))

Avg_tipo_dia<-
ozono%>%group_by(Tipo_Dia)%>%summarise(Promedio=mean(Daily_Max_8hour_Ozone_Concentration),
Mediana=median(Daily_Max_8hour_Ozone_Concentration),
Desviacion_estandar=sd(Daily_Max_8hour_Ozone_Concentration),
coeficiente_variacion=Desviacion_estandar*100/Promedio)
head(Avg_tipo_dia)
## # A tibble: 2 × 5
##   Tipo_Dia Promedio Mediana Desviacion_estandar coeficiente_variacion
##   <chr>       <dbl>   <dbl>               <dbl>                 <dbl>
## 1 Weekday    0.0438   0.041              0.0150                  34.3
## 2 Weekend    0.0432   0.041              0.0140                  32.5

El gráfico e caja y bigote y la tabla de estadisticos indican que no existe una diferencia significativa entre los niveles de ozono en dia de semana o fin de semana, esto podria atribuirse a que en las grandes ciudades muchos personas trabajan fin de semana o salen con su familiares, esto conlleva el uso de vehiculo, lo cual impacta de forma directa en los niveles de ozono. Gráfico Geoespacial sobre la concentración de ozono en California

library(maps)
## 
## Adjuntando el paquete: 'maps'
## The following object is masked from 'package:purrr':
## 
##     map
library(mapproj)

Para crear el gráfico se requiere las variables Local Site Name, Site Latitude, Site Longitude y Daily_Max_8hour_Ozone_Concentration.

grafico<-ozono%>%select(Local_site_name=`Local Site Name`,Latitude=`Site Latitude`,Longitude=`Site Longitude`,Daily_Max_8hour_Ozone_Concentration)
head(grafico)
## # A tibble: 6 × 4
##   Local_site_name Latitude Longitude Daily_Max_8hour_Ozone_Concentration
##   <chr>              <dbl>     <dbl>                               <dbl>
## 1 Livermore           37.7     -122.                               0.031
## 2 Livermore           37.7     -122.                               0.037
## 3 Livermore           37.7     -122.                               0.032
## 4 Livermore           37.7     -122.                               0.026
## 5 Livermore           37.7     -122.                               0.027
## 6 Livermore           37.7     -122.                               0.031

Calculamos el promedio de ozono por cada ubicación única (latitud, longitud).Esto es crucial para un mapa de calor/puntos coloreados por ubicación.

ozone_location_avg <- grafico %>%
group_by(Latitude, Longitude, Local_site_name) %>%
summarise(
Promedio_Ozono = mean(Daily_Max_8hour_Ozone_Concentration, na.rm = TRUE),
.groups = 'drop'
) %>%filter(!is.na(Latitude) & !is.na(Longitude))

Para construir el mapa se requiere extraer los estados de USA, esta data frame se guardara con el nombre us_estados

us_estados<- map_data("state")
head(us_estados)
##        long      lat group order  region subregion
## 1 -87.46201 30.38968     1     1 alabama      <NA>
## 2 -87.48493 30.37249     1     2 alabama      <NA>
## 3 -87.52503 30.37249     1     3 alabama      <NA>
## 4 -87.53076 30.33239     1     4 alabama      <NA>
## 5 -87.57087 30.32665     1     5 alabama      <NA>
## 6 -87.58806 30.32665     1     6 alabama      <NA>

Crea el mapa de calor geoespacial usando geom_polygon y geom_point.

ggplot() +
  geom_polygon(data = us_estados, aes(x = long, y = lat, group = group),
               fill = "lightgray", color = "white", linewidth = 0.3) +
  
  coord_map(
    xlim = range(ozone_location_avg$Longitude, na.rm = TRUE),
    ylim = range(ozone_location_avg$Latitude, na.rm = TRUE)
  ) +
  geom_point(
    data = ozone_location_avg,
    aes(x = Longitude, y = Latitude, color = Promedio_Ozono, size = Promedio_Ozono),
    alpha = 0.8,
    shape = 16
  ) +
  scale_color_viridis_c(option = "magma", direction = -1, name = "Ozono Promedio (ppm)") +
  #tamano de puntos
  scale_size_continuous(range = c(1, 6), guide = "none") +
  labs(
    title = "Concentración Promedio de Ozono por Ubicación (Mapa Básico)",
    subtitle = "Identificación de Zonas de Alta Concentración",
    x = "Longitud",
    y = "Latitud"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    legend.position = "right",)

El mapa de calor para la concentración de ozono nos muestra los lugares con mayor contaminación, como es de esperarse las zonas mas al sur son las que presentan mayor contaminación promedio debido al ozono, esto es lo esperado dado el analisis anterior que se ha hecho y teniendo en cuenta que al sur de california esta el valle de la muerte y hay zonas mas deserticas.

Principales Hallazgos. Las concentraciones más altas se registran en verano (junio-julio), y las más bajas en invierno, lo cual es consistente con la influencia de la radiación solar en la formación de ozono. Regiones con Mayor Contaminación. Las zonas más afectadas incluyen: Riverside–San Bernardino–Ontario Visalia–Porterville El Centro Todas superan el umbral de 0.05 ppm, considerado perjudicial para la salud. Impacto del Método de Medición Se observaron diferencias significativas entre métodos. El método 53 reporta los niveles más altos, mientras que el método 100 (valores imputados) muestra menor variabilidad. Actividad Urbana: Semana vs. Fin de Semana No se encontraron diferencias significativas en los niveles de ozono entre días laborables y fines de semana, lo que sugiere una actividad urbana constante. Mapa Geoespacial Las zonas del sur de California presentan mayores concentraciones promedio de ozono, alineado con condiciones climáticas más cálidas y secas. Recomendaciones. Monitoreo Intensivo en regiones críticas como Riverside y Visalia. Revisión de Métodos de Medición para estandarizar y mejorar la precisión de los datos. Campañas de Concientización en zonas urbanas con alta actividad vehicular. Políticas Estacionales que refuercen controles durante los meses de verano.