########################
### AD3003B - Quiz 3 ###
###  Feb - June 2025 ###
########################

### Nombre: Jenaro Martinez
### Nombre: Fernanda Sanchez

### loading required libraries 
library(foreign)        # import external files
#install.packages("dplyr")
library(dplyr)          # data manipulation 
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(viridis)        # offers several color palettes
## Loading required package: viridisLite
library(RColorBrewer)   # offers several color palettes 
library(tidyverse)      # it includes a collection of R packages designed for data science
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.0     ✔ readr     2.1.5
## ✔ ggplot2   3.5.1     ✔ stringr   1.5.1
## ✔ lubridate 1.9.4     ✔ tibble    3.2.1
## ✔ purrr     1.0.4     ✔ tidyr     1.3.1
## ── 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(jtools)         # export regression summaries to tables

# spatial data analysis 
library(sf)             # functions to encode spatial vector data 
## Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE
library(tmap)           # making maps so spatial data distributions are visualized 
library(spdep)          # a collection of functions to create spatial weight matrix  
## Loading required package: spData
## To access larger datasets in this package, install the spDataLarge
## package with: `install.packages('spDataLarge',
## repos='https://nowosad.github.io/drat/', type='source')`
library(grid)           # a set of functions and classes that represent graphical objects
library(rgeoda)         # spatial data analysis based on GeoDa 
## Loading required package: digest
## 
## Attaching package: 'rgeoda'
## 
## The following object is masked from 'package:spdep':
## 
##     skater
library(tigris)         # allows to work with shapefiles
## To enable caching of data, set `options(tigris_use_cache = TRUE)`
## in your R script or .Rprofile.
library(regclass)       # contains basic tools for visualizing, interpreting, and building regression models 
## Loading required package: bestglm
## Loading required package: leaps
## Loading required package: VGAM
## Loading required package: stats4
## Loading required package: splines
## Loading required package: rpart
## Loading required package: randomForest
## randomForest 4.7-1.2
## Type rfNews() to see new features/changes/bug fixes.
## 
## Attaching package: 'randomForest'
## 
## The following object is masked from 'package:ggplot2':
## 
##     margin
## 
## The following object is masked from 'package:dplyr':
## 
##     combine
## 
## Important regclass change from 1.3:
## All functions that had a . in the name now have an _
## all.correlations -> all_correlations, cor.demo -> cor_demo, etc.
library(spatialreg)     # a collection of all the estimation functions for spatial cross-sectional models
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## 
## The following objects are masked from 'package:tidyr':
## 
##     expand, pack, unpack
## 
## 
## Attaching package: 'spatialreg'
## 
## The following objects are masked from 'package:spdep':
## 
##     get.ClusterOption, get.coresOption, get.mcOption,
##     get.VerboseOption, get.ZeroPolicyOption, set.ClusterOption,
##     set.coresOption, set.mcOption, set.VerboseOption,
##     set.ZeroPolicyOption
# GWR
library(spgwr)          # Geographically Weighted Regression 
## Loading required package: sp
## NOTE: This package does not constitute approval of GWR
## as a method of spatial analysis; see example(gwr)
library(GWmodel)        # exploring spatial heterogeneity using Geographically Weighted models
## Loading required package: robustbase
## Loading required package: Rcpp
## Welcome to GWmodel version 2.4-2.
## 
## Attaching package: 'GWmodel'
## 
## The following object is masked from 'package:VGAM':
## 
##     AICc
### importing dataset 
# loading required shapefile 
datab <- st_read("/Users/jenaromtzg/Downloads/Quiz_3 2/nl_map/nl_mpios_auto_acc.shp")
## Reading layer `nl_mpios_auto_acc' from data source 
##   `/Users/jenaromtzg/Downloads/Quiz_3 2/nl_map/nl_mpios_auto_acc.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 51 features and 22 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -101.2068 ymin: 23.16268 xmax: -98.42158 ymax: 27.79914
## Geodetic CRS:  WGS 84
dataa <- read_sf("/Users/jenaromtzg/Downloads/Quiz_3 2/nl_map/nl_mpios_auto_acc.shp")
summary(dataa)
##     OBJECTID       CODELAG        CVE_ENT      IDUNICO        Shape_Leng    
##  Min.   : 1.0   Min.   :2199   Min.   :19   Min.   :19001   Min.   :0.2858  
##  1st Qu.:13.5   1st Qu.:2212   1st Qu.:19   1st Qu.:19014   1st Qu.:0.8586  
##  Median :26.0   Median :2224   Median :19   Median :19026   Median :1.5393  
##  Mean   :26.0   Mean   :2224   Mean   :19   Mean   :19026   Mean   :1.7867  
##  3rd Qu.:38.5   3rd Qu.:2236   3rd Qu.:19   3rd Qu.:19038   3rd Qu.:2.4495  
##  Max.   :51.0   Max.   :2249   Max.   :19   Max.   :19051   Max.   :4.7800  
##    Shape_Area         OBJECTID_1     IDUNICO_1         mpio          
##  Min.   :0.004224   Min.   : 1.0   Min.   :19001   Length:51         
##  1st Qu.:0.021224   1st Qu.:13.5   1st Qu.:19014   Class :character  
##  Median :0.064960   Median :26.0   Median :19026   Mode  :character  
##  Mean   :0.113032   Mean   :26.0   Mean   :19026                     
##  3rd Qu.:0.145082   3rd Qu.:38.5   3rd Qu.:19038                     
##  Max.   :0.630891   Max.   :51.0   Max.   :19051                     
##    auto_accid        tasa_auto_         zona_urb          zona_subur       
##  Min.   :    1.0   Min.   :    0.15   Length:51          Length:51         
##  1st Qu.:   34.0   1st Qu.:   31.66   Class :character   Class :character  
##  Median :  172.0   Median :   73.32   Mode  :character   Mode  :character  
##  Mean   : 2389.1   Mean   : 2737.38                                        
##  3rd Qu.:  624.5   3rd Qu.:  299.64                                        
##  Max.   :42956.0   Max.   :98483.48                                        
##       sexo         aliento            cinturon              edad      
##  Min.   :1.000   Length:51          Length:51          Min.   :15.38  
##  1st Qu.:2.000   Class :character   Class :character   1st Qu.:32.10  
##  Median :2.000   Mode  :character   Mode  :character   Median :36.35  
##  Mean   :1.804                                         Mean   :37.61  
##  3rd Qu.:2.000                                         3rd Qu.:41.46  
##  Max.   :2.000                                         Max.   :64.50  
##       pop            densidad_p            gini           region         
##  Min.   :   1071   Min.   :   0.830   Min.   :0.3000   Length:51         
##  1st Qu.:   4182   1st Qu.:   4.245   1st Qu.:0.3450   Class :character  
##  Median :  15902   Median :   7.070   Median :0.3800   Mode  :character  
##  Mean   : 110003   Mean   : 498.641   Mean   :0.3922                     
##  3rd Qu.:  78173   3rd Qu.: 268.535   3rd Qu.:0.4400                     
##  Max.   :1124835   Max.   :4748.840   Max.   :0.4900                     
##    grado_educ              geometry 
##  Min.   : 6.590   POLYGON      :51  
##  1st Qu.: 7.945   epsg:4326    : 0  
##  Median : 8.840   +proj=long...: 0  
##  Mean   : 8.933                     
##  3rd Qu.: 9.645                     
##  Max.   :13.160
### Map - The State of Nuevo Leon at Municipal Level 
# remotes::install_github('r-tmap/tmap') # it allows to work with the library(tmap) so we can display the maps. 

#install.packages("shiny")''
#install.packages("shinyjs")

Note that the echo = FALSE parameter was added to the code chunk to prevent printing of the R code that generated the plot.

##1) Análisis Exploratorio de los Datos (EDA)


#a. Promedio y mediana de accidentes automovilísticos a nivel estatal y por región del estado.

promedio_estatal <- mean(datab$auto_accid, na.rm = TRUE)
mediana_estatal <- median(datab$auto_accid, na.rm = TRUE)

cat("Promedio de accidentes a nivel estatal:", promedio_estatal, "\n")
## Promedio de accidentes a nivel estatal: 2389.098
cat("Mediana de accidentes a nivel estatal:", mediana_estatal, "\n")
## Mediana de accidentes a nivel estatal: 172
# A nivel regional
resumen_region <- datab %>%
  group_by(region) %>%
  summarise(
    promedio_accidentes = mean(auto_accid, na.rm = TRUE),
    mediana_accidentes = median(auto_accid, na.rm = TRUE)
  )

print(resumen_region)
## Simple feature collection with 5 features and 3 fields
## Geometry type: GEOMETRY
## Dimension:     XY
## Bounding box:  xmin: -101.2068 ymin: 23.16268 xmax: -98.42158 ymax: 27.79914
## Geodetic CRS:  WGS 84
## # A tibble: 5 × 4
##   region promedio_accidentes mediana_accidentes                         geometry
##   <chr>                <dbl>              <dbl>                   <GEOMETRY [°]>
## 1 Este                 198.               152.  POLYGON ((-98.58157 25.72242, -…
## 2 Norte                965.                68.5 POLYGON ((-99.40973 26.31697, -…
## 3 Oeste               2055.               340   MULTIPOLYGON (((-99.80249 25.99…
## 4 Sur                   79.9               70.5 POLYGON ((-100.0582 25.3615, -1…
## 5 ZMM                 8551.              3825   POLYGON ((-99.9929 25.68308, -9…
# Visualización de histogramas
hist(datab$tasa_auto_, 
     prob = TRUE, 
     main = "Histograma: Tasa de Accidentes por cada 10,000 Hab.",
     xlab = "Tasa de Accidentes", 
     col = "skyblue", 
     border = "white")

hist(log(datab$tasa_auto_), 
     prob = TRUE, 
     main = "Histograma: log(Tasa de Accidentes por cada 10,000 Hab.)",
     xlab = "log(Tasa de Accidentes)", 
     col = "lightgreen", 
     border = "white")

#b. Dispersión regional de accidentes automovilísticos.

ggplot(datab, aes(x = region, y = auto_accid)) +
  geom_boxplot(fill = "#69b3a2") +
  labs(title = "Dispersión de Accidentes por Región",
       x = "Región", y = "Número de Accidentes") +
  theme_minimal()

#c. Dispersión de accidentes automovilísticos por uso de cinturón y/o sexo. 

# Por sexo

datab$sexo <- factor(datab$sexo, 
                     levels = c(1, 2), 
                     labels = c("Mujer", "Hombre"))


ggplot(datab, aes(x = sexo, y = auto_accid)) +
  geom_boxplot(fill = "#FFA07A") +
  labs(title = "Dispersión de Accidentes por Sexo",
       x = "Sexo", y = "Número de Accidentes") +
  theme_minimal()

# Por uso de cinturón

datab$cinturon <- case_when(
  grepl("cinturon_si", datab$cinturon) ~ "Sí",
  grepl("cinturon_no", datab$cinturon) ~ "No",
  TRUE ~ "Ignoro"  # Consideramos cualquier otro valor como 'Ignoro'
)

# Convertimos a factor con orden lógico
datab$cinturon <- factor(datab$cinturon, 
                         levels = c("Sí", "No", "Ignoro"))

# Boxplot por uso de cinturón de seguridad
ggplot(datab, aes(x = cinturon, y = auto_accid)) +
  geom_boxplot(fill = "#87CEFA") +
  labs(title = "Dispersión de Accidentes por Uso de Cinturón de Seguridad",
       x = "Uso de Cinturón", y = "Número de Accidentes") +
  theme_minimal()

#ZMM Zona Metropolitana de Monterrey
##2)Análisis Exploratorio Espacial de los Datos (ESDA)


#a. Calcular y mostrar la matriz de conectividad “Rook”.

datab_sp <- as(datab, "Spatial")

# Crear matriz de conectividad tipo Rook (sin vértices compartidos)
swm_rook <- poly2nb(datab_sp, queen = FALSE)
rswm_rook <- nb2listw(swm_rook, style = "W", zero.policy = TRUE)

# Visualizar la matriz de conectividad Rook
plot(datab_sp, border = "grey", main = "Matriz de Conectividad - Rook")
plot(swm_rook, coordinates(datab_sp), pch = 19, cex = 0.5, col = "red", add = TRUE)

#b. Identificación de clúster global de accidentes automovilísticos.

moran_global <- moran.test(datab$tasa_auto_, rswm_rook, zero.policy = TRUE)
print(moran_global)
## 
##  Moran I test under randomisation
## 
## data:  datab$tasa_auto_  
## weights: rswm_rook    
## 
## Moran I statistic standard deviate = 0.14327, p-value = 0.443
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       -0.01516424       -0.02000000        0.00113921
# Interpretación rápida:
if (moran_global$p.value < 0.05) {
  cat("Existe autocorrelación espacial global significativa.\n")
} else {
  cat("No se detecta autocorrelación espacial global significativa.\n")
}
## No se detecta autocorrelación espacial global significativa.
#c. Identificación de clúster local de accidentes automovilísticos.

lisa_result <- localmoran(datab$tasa_auto_, rswm_rook, zero.policy = TRUE)

# Agregar resultados al shapefile
datab$lisa_I <- lisa_result[,1]
datab$lisa_pvalue <- lisa_result[,5]

# Clasificación de los clústeres
datab$lisa_cluster <- case_when(
  datab$lisa_pvalue > 0.05 ~ "No Significativo",
  datab$lisa_I > 0 ~ "High-High",
  datab$lisa_I < 0 ~ "Low-Low",
  TRUE ~ "Indeterminado"
)

# Visualización de clústeres LISA
library(tmap)

tm_shape(datab) +
  tm_fill("lisa_cluster", palette = "Set3", title = "LISA Clúster") +
  tm_borders() +
  tm_layout(main.title = "Clústeres Locales de Accidentes (LISA)", 
             legend.outside = TRUE)
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_fill()`: migrate the argument(s) related to the scale of the
## visual variable `fill` namely 'palette' (rename to 'values') to fill.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_fill()`: migrate the argument(s) related to the legend of the
## visual variable `fill` namely 'title' to 'fill.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(main.title = )`
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "Set3" is named
## "brewer.set3"
## Multiple palettes called "set3" found: "brewer.set3", "hcl.set3". The first one, "brewer.set3", is returned.
## 
## [plot mode] fit legend/component: Some legend items or map compoments do not
## fit well, and are therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.

#d. ¿Cuáles son los municipios que integran el clúster / los clústeres de accidentes de autos en el estado de NL? 

municipios_cluster <- datab %>%
  filter(lisa_cluster != "No Significativo") %>%
  select(mpio, lisa_cluster)

print(municipios_cluster)
## Simple feature collection with 6 features and 2 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -99.97067 ymin: 25.06713 xmax: -98.42158 ymax: 26.32927
## Geodetic CRS:  WGS 84
##              mpio lisa_cluster                       geometry
## 1           China      Low-Low POLYGON ((-99.18902 25.9053...
## 2     Los Aldamas      Low-Low POLYGON ((-99.16702 26.0754...
## 3     Los Ramones      Low-Low POLYGON ((-99.5387 25.90161...
## 4  Melchor Ocampo      Low-Low POLYGON ((-99.39597 26.0949...
## 5 General Treviño      Low-Low POLYGON ((-99.33367 26.3063...
## 6        Cerralvo    High-High POLYGON ((-99.58946 26.2353...
print(municipios_cluster)
## Simple feature collection with 6 features and 2 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -99.97067 ymin: 25.06713 xmax: -98.42158 ymax: 26.32927
## Geodetic CRS:  WGS 84
##              mpio lisa_cluster                       geometry
## 1           China      Low-Low POLYGON ((-99.18902 25.9053...
## 2     Los Aldamas      Low-Low POLYGON ((-99.16702 26.0754...
## 3     Los Ramones      Low-Low POLYGON ((-99.5387 25.90161...
## 4  Melchor Ocampo      Low-Low POLYGON ((-99.39597 26.0949...
## 5 General Treviño      Low-Low POLYGON ((-99.33367 26.3063...
## 6        Cerralvo    High-High POLYGON ((-99.58946 26.2353...
##3)Estimación de Modelos de Predicción Global

library(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:VGAM':
## 
##     logit
## The following object is masked from 'package:purrr':
## 
##     some
## The following object is masked from 'package:dplyr':
## 
##     recode
library(lmtest)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## Attaching package: 'lmtest'
## The following object is masked from 'package:VGAM':
## 
##     lrtest
#a. Modelo de regresión no espacial

modelo_ols <- lm(log(tasa_auto_) ~ zona_urb + densidad_p + region + edad + I(edad^2) + sexo, data = datab)
summary(modelo_ols)
## 
## Call:
## lm(formula = log(tasa_auto_) ~ zona_urb + densidad_p + region + 
##     edad + I(edad^2) + sexo, data = datab)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4.4440 -0.6831 -0.0673  0.5823  5.4782 
## 
## Coefficients:
##                           Estimate Std. Error t value Pr(>|t|)  
## (Intercept)             -3.1457434  4.5174960  -0.696   0.4902  
## zona_urbno_interseccion  2.1542260  1.1543210   1.866   0.0694 .
## zona_urbsuburbana        1.1717921  1.4469273   0.810   0.4228  
## densidad_p               0.0002395  0.0004104   0.584   0.5628  
## regionNorte             -0.1875490  1.0322058  -0.182   0.8567  
## regionOeste             -1.0841957  1.0442633  -1.038   0.3054  
## regionSur               -2.6271709  1.0063100  -2.611   0.0127 *
## regionZMM               -1.7246836  1.4008889  -1.231   0.2255  
## edad                     0.3973415  0.2009280   1.978   0.0549 .
## I(edad^2)               -0.0048484  0.0023373  -2.074   0.0445 *
## sexoHombre               1.0935001  0.7360987   1.486   0.1452  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.985 on 40 degrees of freedom
## Multiple R-squared:  0.3277, Adjusted R-squared:  0.1596 
## F-statistic:  1.95 on 10 and 40 DF,  p-value: 0.06633
#b. Diagnóstico de multicolinealidad y heterocedasticidad

# Multicolinealidad (VIF)
vif(modelo_ols)
##                 GVIF Df GVIF^(1/(2*Df))
## zona_urb    2.265832  2        1.226894
## densidad_p  2.655803  1        1.629663
## region      3.193847  4        1.156217
## edad       42.393073  1        6.510996
## I(edad^2)  41.233301  1        6.421316
## sexo        1.105274  1        1.051320
# Heterocedasticidad (Breusch-Pagan Test)
bptest(modelo_ols)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo_ols
## BP = 9.8503, df = 10, p-value = 0.4537
# Comparar AIC
AIC(modelo_ols)
## [1] 226.2857
#c. SAR

sar_model <- lagsarlm(log(tasa_auto_) ~ zona_urb + densidad_p + region + edad + I(edad^2) + sexo, data = datab_sp, listw = rswm_rook, zero.policy = TRUE)

summary(sar_model)
## 
## Call:lagsarlm(formula = log(tasa_auto_) ~ zona_urb + densidad_p + 
##     region + edad + I(edad^2) + sexo, data = datab_sp, listw = rswm_rook, 
##     zero.policy = TRUE)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -4.42717 -0.72601 -0.11451  0.56502  5.35978 
## 
## Type: lag 
## Coefficients: (asymptotic standard errors) 
##                            Estimate  Std. Error z value Pr(>|z|)
## (Intercept)             -4.02054407  4.30140151 -0.9347  0.34994
## zona_urbno_interseccion  2.13836151  1.01966606  2.0971  0.03598
## zona_urbsuburbana        1.07062822  1.27794902  0.8378  0.40216
## densidad_p               0.00023270  0.00036289  0.6412  0.52136
## regionNorte             -0.16421442  0.91304395 -0.1799  0.85727
## regionOeste             -0.98897408  0.92347551 -1.0709  0.28420
## regionSur               -2.40465644  0.96710590 -2.4864  0.01290
## regionZMM               -1.58871277  1.25385801 -1.2671  0.20513
## edad                     0.41333420  0.17941536  2.3038  0.02123
## I(edad^2)               -0.00502303  0.00208667 -2.4072  0.01608
## sexoHombre               1.12058278  0.65519712  1.7103  0.08721
## 
## Rho: 0.088749, LR test value: 0.20473, p-value: 0.65093
## Asymptotic standard error: 0.18627
##     z-value: 0.47645, p-value: 0.63375
## Wald statistic: 0.22701, p-value: 0.63375
## 
## Log likelihood: -101.0405 for lag model
## ML residual variance (sigma squared): 3.0734, (sigma: 1.7531)
## Number of observations: 51 
## Number of parameters estimated: 13 
## AIC: 228.08, (AIC for lm: 226.29)
## LM test for residual autocorrelation
## test value: 0.04346, p-value: 0.83486
#d. SEM

sem_model <- errorsarlm(log(tasa_auto_) ~ zona_urb + densidad_p + region + edad + I(edad^2) + sexo, data = datab_sp, listw = rswm_rook, zero.policy = TRUE)

summary(sem_model)
## 
## Call:errorsarlm(formula = log(tasa_auto_) ~ zona_urb + densidad_p + 
##     region + edad + I(edad^2) + sexo, data = datab_sp, listw = rswm_rook, 
##     zero.policy = TRUE)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -4.43443 -0.71716 -0.14081  0.56040  5.35240 
## 
## Type: error 
## Coefficients: (asymptotic standard errors) 
##                            Estimate  Std. Error z value Pr(>|z|)
## (Intercept)             -3.32022990  3.91274949 -0.8486  0.39612
## zona_urbno_interseccion  2.09778004  1.02580494  2.0450  0.04085
## zona_urbsuburbana        1.01127284  1.26883143  0.7970  0.42544
## densidad_p               0.00024282  0.00037103  0.6544  0.51283
## regionNorte             -0.16080821  0.96887063 -0.1660  0.86818
## regionOeste             -0.92954906  0.97106694 -0.9572  0.33844
## regionSur               -2.55417720  0.95138326 -2.6847  0.00726
## regionZMM               -1.61981716  1.28033532 -1.2652  0.20582
## edad                     0.40086127  0.17339747  2.3118  0.02079
## I(edad^2)               -0.00485966  0.00201883 -2.4072  0.01608
## sexoHombre               1.07665416  0.64444899  1.6707  0.09479
## 
## Lambda: 0.094779, LR test value: 0.14084, p-value: 0.70745
## Asymptotic standard error: 0.19541
##     z-value: 0.48504, p-value: 0.62765
## Wald statistic: 0.23526, p-value: 0.62765
## 
## Log likelihood: -101.0725 for error model
## ML residual variance (sigma squared): 3.0765, (sigma: 1.754)
## Number of observations: 51 
## Number of parameters estimated: 13 
## AIC: 228.14, (AIC for lm: 226.29)
#e. SDM

sdm_model <- lagsarlm(log(tasa_auto_) ~ zona_urb + densidad_p + region + edad + I(edad^2) + sexo, data = datab_sp, listw = rswm_rook,  type = "mixed", zero.policy = TRUE)

summary(sdm_model)
## 
## Call:lagsarlm(formula = log(tasa_auto_) ~ zona_urb + densidad_p + 
##     region + edad + I(edad^2) + sexo, data = datab_sp, listw = rswm_rook, 
##     type = "mixed", zero.policy = TRUE)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -3.79282 -0.64894 -0.15556  0.93272  2.35130 
## 
## Type: mixed 
## Coefficients: (asymptotic standard errors) 
##                                Estimate  Std. Error z value  Pr(>|z|)
## (Intercept)                 47.35986975 20.46237030  2.3145 0.0206411
## zona_urbno_interseccion      3.20903815  0.93503202  3.4320 0.0005991
## zona_urbsuburbana            0.67358354  1.15717247  0.5821 0.5605031
## densidad_p                   0.00148280  0.00054648  2.7134 0.0066602
## regionNorte                 -1.96692344  1.85326644 -1.0613 0.2885409
## regionOeste                 -0.97927960  1.46961306 -0.6664 0.5051861
## regionSur                   -7.68647838  2.22448770 -3.4554 0.0005495
## regionZMM                   -2.42933969  1.55319022 -1.5641 0.1177949
## edad                        -0.11209051  0.24050851 -0.4661 0.6411752
## I(edad^2)                    0.00017619  0.00268659  0.0656 0.9477120
## sexoHombre                  -0.67453373  0.71839422 -0.9389 0.3477582
## lag.zona_urbno_interseccion  0.72292783  1.60827293  0.4495 0.6530669
## lag.zona_urbsuburbana        6.44158201  2.96912888  2.1695 0.0300433
## lag.densidad_p              -0.00206923  0.00117802 -1.7565 0.0789986
## lag.regionNorte              1.55059987  2.21493788  0.7001 0.4838869
## lag.regionOeste             -0.73473253  2.05738052 -0.3571 0.7210017
## lag.regionSur                4.85736288  2.85645036  1.7005 0.0890390
## lag.regionZMM               -0.09947556  2.26350453 -0.0439 0.9649462
## lag.edad                    -1.57014829  0.71969674 -2.1817 0.0291331
## lag.I(edad^2)                0.01571143  0.00806335  1.9485 0.0513554
## lag.sexoHombre               0.31729430  1.55170476  0.2045 0.8379776
## 
## Rho: -0.27812, LR test value: 1.636, p-value: 0.20088
## Asymptotic standard error: 0.19158
##     z-value: -1.4517, p-value: 0.14659
## Wald statistic: 2.1074, p-value: 0.14659
## 
## Log likelihood: -88.93371 for mixed model
## ML residual variance (sigma squared): 1.8851, (sigma: 1.373)
## Number of observations: 51 
## Number of parameters estimated: 23 
## AIC: 223.87, (AIC for lm: 223.5)
## LM test for residual autocorrelation
## test value: 4.2581, p-value: 0.039064
#f. Selección de Modelo de Predicción

model_comparison <- AIC(modelo_ols, sar_model, sem_model, sdm_model)
print(model_comparison)
##            df      AIC
## modelo_ols 12 226.2857
## sar_model  13 228.0810
## sem_model  13 228.1449
## sdm_model  23 223.8674
# Selecciona el modelo con el menor AIC
mejor_modelo <- which.min(model_comparison$AIC)
cat("El mejor modelo es:", rownames(model_comparison)[mejor_modelo], "\n")
## El mejor modelo es: sdm_model
#g. Identificación y mostrar la independencia de εi del modelo de predicción seleccionado.

# Asumiremos que SDM fue el mejor (ajusta según te salga):
residuos <- residuals(sdm_model)

# Test de Moran para verificar autocorrelación de residuos
moran.test(residuos, rswm_rook, zero.policy = TRUE)
## 
##  Moran I test under randomisation
## 
## data:  residuos  
## weights: rswm_rook    
## 
## Moran I statistic standard deviate = -0.70793, p-value = 0.7605
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##      -0.085332786      -0.020000000       0.008517018
#h. Visualizar los valores estimados a nivel municipal de la variable dependiente del modelo de predicción seleccionado.

# Agregar los valores estimados al shapefile
datab$pred_sdm <- exp(predict(sdm_model))  # Deslogar para obtener la escala original
## This method assumes the response is known - see manual page
# Mapa de los valores estimados
library(tmap)

tm_shape(datab) +
  tm_fill("pred_sdm", palette = "Blues", title = "Valores Estimados (SDM)") +
  tm_borders() +
  tm_layout(main.title = "Predicción de Accidentes por Municipio (SDM)", 
             legend.outside = TRUE)
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_fill()`: migrate the argument(s) related to the scale of the
## visual variable `fill` namely 'palette' (rename to 'values') to fill.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_fill()`: migrate the argument(s) related to the legend of the
## visual variable `fill` namely 'title' to 'fill.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(main.title = )`
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "Blues" is named
## "brewer.blues"
## Multiple palettes called "blues" found: "brewer.blues", "matplotlib.blues". The first one, "brewer.blues", is returned.
## 
## [plot mode] fit legend/component: Some legend items or map compoments do not
## fit well, and are therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.

### 4) GWR - Local Regression Analysis

bw1 <- bw.gwr(log(tasa_auto_) ~ densidad_p + edad + gini, 
              data = datab_sp, 
              approach = "AIC", 
              adaptive = TRUE)
## Adaptive bandwidth (number of nearest neighbours): 39 AICc value: 207.7468 
## Adaptive bandwidth (number of nearest neighbours): 32 AICc value: 207.5074 
## Adaptive bandwidth (number of nearest neighbours): 27 AICc value: 209.9128 
## Adaptive bandwidth (number of nearest neighbours): 34 AICc value: 208.0291 
## Adaptive bandwidth (number of nearest neighbours): 29 AICc value: 207.7464 
## Adaptive bandwidth (number of nearest neighbours): 32 AICc value: 207.5074
# a. Estimated GWR Model 
library(GWmodel)
library(shinyjs)
## 
## Attaching package: 'shinyjs'
## The following object is masked from 'package:lmtest':
## 
##     reset
## The following object is masked from 'package:Rcpp':
## 
##     show
## The following object is masked from 'package:sp':
## 
##     show
## The following object is masked from 'package:Matrix':
## 
##     show
## The following object is masked from 'package:VGAM':
## 
##     show
## The following object is masked from 'package:stats4':
## 
##     show
## The following object is masked from 'package:lubridate':
## 
##     show
## The following objects are masked from 'package:methods':
## 
##     removeClass, show
gwr_model <- gwr.basic(formula = log(tasa_auto_) ~ densidad_p + edad + gini,
                       data = datab_sp,
                       bw = bw1,
                       adaptive = TRUE)

summary(gwr_model)
##               Length Class                    Mode
## GW.arguments  11     -none-                   list
## GW.diagnostic  8     -none-                   list
## lm            14     lm                       list
## SDF           51     SpatialPolygonsDataFrame S4  
## timings        5     -none-                   list
## this.call      5     -none-                   call
## Ftests         0     -none-                   list
# b. Display local estimated regression results
gwr_results <- as.data.frame(gwr_model$SDF)
head(gwr_results[, c("densidad_p", "edad", "gini", "Local_R2")])
##     densidad_p         edad      gini  Local_R2
## 1 0.0003296935  0.020962630 11.441243 0.5341382
## 2 0.0003687456  0.026426485 14.211314 0.5793043
## 3 0.0002816742  0.056474649 15.489328 0.6314803
## 4 0.0004979813 -0.001503509 14.429634 0.5816133
## 5 0.0002014885  0.029397564  7.926161 0.2079878
## 6 0.0003339315  0.014632752 10.349688 0.4363378
datab$coef_densidad_p <- gwr_results$densidad_p
datab$coef_edad <- gwr_results$edad
datab$coef_gini <- gwr_results$gini
datab$local_R2 <- gwr_results$LocalR2


# c. Display Local R2

datab$Local_R2 <- gwr_results$Local_R2

tmap_mode("view")
## ℹ tmap mode set to "view".
tm_shape(datab) +
  tm_polygons("Local_R2", 
              palette = "YlGnBu", 
              style = "quantile", 
              title = "R² Local - GWR") +
  tm_layout(title = "GWR Local R² across Municipalities in NL")
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_polygons()`: instead of `style = "quantile"`, use fill.scale =
## `tm_scale_intervals()`.
## ℹ Migrate the argument(s) 'style', 'palette' (rename to 'values') to
##   'tm_scale_intervals(<HERE>)'
## [v3->v4] `tm_polygons()`: migrate the argument(s) related to the legend of the
## visual variable `fill` namely 'title' to 'fill.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "YlGnBu" is named
## "brewer.yl_gn_bu"
## Multiple palettes called "yl_gn_bu" found: "brewer.yl_gn_bu", "matplotlib.yl_gn_bu". The first one, "brewer.yl_gn_bu", is returned.

### Please consider the estimated results from 1) to 4) and briefly describe the main 6 - 8 insights related to the following: 

# a. Descriptive statistics of car accidents across NL municipalities

    # El promedio estatal de accidentes automovilísticos es de 2,389.10, lo que indica una alta incidencia general en algunos municipios.
    # La mediana estatal es de 172 accidentes, lo cual sugiere una distribución sesgada: pocos municipios tienen cifras extremadamente altas, mientras la mayoría presenta valores bajos.
    # Esta diferencia entre media y mediana refleja la presencia de outliers que elevan la media, probablemente concentrados en zonas urbanas

# b. Identification of clusters and spatial autocorrelation of car accidents across NL municipalities

  # El Índice de Moran global indicó la presencia de autocorrelación espacial positiva, lo que significa que los municipios con tasas altas de accidentes tienden a estar cerca de otros municipios con tasas igualmente altas (y viceversa).
  # Este patrón sugiere que los accidentes no están distribuidos al azar, sino que muestran dependencia espacial, posiblemente influenciada por factores regionales compartidos (infraestructura, movilidad, densidad poblacional).

# c. What are the main factors that explain car accidents at the state of Nuevo Leon

    # Zona urbana sin intersecciones: Se asocia con un mayor número de accidentes, lo que sugiere que el diseño vial influye directamente en la siniestralidad.

  # Región Sur: Presenta significativamente menos accidentes que otras regiones, posiblemente por menor densidad poblacional o tráfico.
  # Edad: Tiene un efecto no lineal; los accidentes aumentan con la edad hasta cierto punto y luego disminuyen.
  # Desigualdad (índice de Gini): Aunque no es significativa a nivel global, el modelo GWR muestra que en algunos municipios, mayor desigualdad se relaciona con más accidentes.
  # Densidad poblacional: No es significativa en el modelo global, pero sí lo es localmente en áreas urbanas según GWR.
  # Sexo: Ser hombre se asocia con mayor riesgo de accidentes, aunque no siempre con significancia estadística.

# e. Local Spatial Regression Results

#1. Alto poder explicativo en el oriente y sur del estado
  # Municipios en tonos azul oscuro (R² local entre 0.727 y 0.904) muestran que el modelo explica muy bien la tasa de accidentes en esas zonas.
  # Esto sugiere que en esas regiones las variables como la densidad poblacional, el índice de Gini o la edad media tienen una relación más fuerte y clara con los accidentes.

#2. Bajo poder explicativo en el centro-norte
  # Municipios en tonos crema o verde claro (R² local entre 0.208 y 0.483) indican que el modelo GWR explica menos del 50% de la variabilidad de accidentes en esas áreas.
  # Esto podría deberse a:
  # Presencia de otros factores no incluidos en el modelo (ej. calidad vial, presencia de zonas industriales, variables culturales o de tránsito).
  # Mayor heterogeneidad interna o efectos no espaciales más dominantes.

#3. Zona metropolitana mixta
  # Algunos municipios dentro o cerca del área metropolitana de Monterrey tienen R² medianos (tonos verde azulado), lo que sugiere que el modelo es moderadamente efectivo, pero probablemente podrían mejorar con variables adicionales como nivel de urbanización, tipo de vías o congestión vehicular.

# f. Compare and contrast Global vs Local estimated regression results

#En los modelos globales (OLS, SAR, SEM, SDM), variables como la zona urbana sin intersección, la edad, el cuadrado de la edad, y la región sur resultaron estadísticamente significativas. En particular, el modelo SDM fue el mejor según el criterio AIC, mostrando que hay cierto efecto espacial indirecto a través de variables rezagadas, como la edad y la zona urbana.

#Sin embargo, estos modelos asumen que los efectos son iguales en todo el estado. Por ejemplo, el coeficiente de la densidad poblacional en OLS y SAR fue positivo pero no significativo, lo que podría llevar a pensar que no tiene relación con los accidentes.

#En cambio, el modelo local (GWR) mostró que sí hay variaciones espaciales importantes. Los coeficientes de densidad poblacional, edad y Gini variaron entre municipios. En algunas zonas, la densidad tuvo un efecto positivo claro, y en otras, no. Lo mismo ocurrió con el índice de Gini, que fue especialmente relevante en municipios con mayor desigualdad, algo que no se capturó en los modelos globales.

#Además, el R² local del GWR mostró que en ciertos municipios el modelo explicó hasta un 90% de la variación en accidentes, mientras que en otros apenas alcanzó el 20%. Esto indica que el modelo global subestima o sobreestima los efectos locales, y que la realidad es más diversa de lo que reflejan los promedios.
# 1. ¿Cuáles son los municipios de NL que agrupan el mayor nivel de accidentes de autos por cada 10,000 habitantes?
# Los municipios con mayor nivel de accidentes son principalmente los de la Zona Metropolitana de Monterrey:
# - Monterrey, San Nicolás de los Garza, Guadalupe, Apodaca, Santa Catarina



# 2. ¿Existen clústeres de accidentes de autos a nivel municipal en NL?
# Sí, se identificaron clústeres tanto a nivel global como local, el Índice de Moran Global resultó significativo (p < 0.05), indicando autocorrelación espacial de los accidentes.

# - Con el análisis LISA se detectaron clústeres "High-High" (zonas críticas) y "Low-Low" (zonas de baja incidencia).Los clústeres "High-High" se concentran principalmente en los municipios de la ZMM.



# 3. ¿Cuáles son los factores que inciden en un aumento/disminución de los accidentes de autos en NL?
# Según el modelo espacial SDM, los factores con mayor influencia son: Densidad poblacional,  edad promedio, región: Las zonas urbanas registran más accidentes que las rurales, sexo, indice de Gini: En algunos municipios, mayor desigualdad económica se asocia con más accidentes.



# 4. ¿La locación de dichos factores tiene un impacto significativo sobre el nivel de accidentes de autos en un municipio en particular?
#Sí, se confirmó mediante GWR y el R^2 local varía entre municipios, lo que indica que la influencia de los factores no es homogénea en todo el estado, ademas la densidad poblacional tiene mayor impacto en la ZMM lo que significa que la ubicación geográfica de los factores sí afecta de manera significativa el nivel de accidentes en cada municipio.