Solucion Taller 3 - Modelo lineal Generalizado (GLM) de la Delincuencia y datos sociodemográficos de Cincinnati Estados Unidos en 2008

Autor: Gilbert Fabian Rodriguez Rodriguez
Fecha: 12/12/2025

1. Descripción de la base de datos y las variables de la base

El conjunto de datos utilizado comprende 457 unidades espaciales, correspondientes a bloques censales de los vecindarios Clifton, Walnut Hills, Evanston y Avondale en Cincinnati, Ohio, durante los últimos seis meses de 2008. Reúne 13 variables con información detallada sobre las características sociodemográficas y de vivienda de cada bloque, incluyendo identificadores espaciales, tamaño y área del polígono, total de población, distribución por sexo y grupos de edad, composición racial desagregada y ajustada, así como indicadores sobre hogares, número y tipo de unidades habitacionales, ocupación, tamaño promedio del hogar y densidad poblacional.

Adicionalmente, el dataset incorpora variables de criminalidad para tres tipos de delitos: burglary, assault y theft, expresadas tanto como conteos absolutos como mediante variables dummy que indican la presencia o ausencia de incidentes. Este conjunto de información permite realizar análisis espaciales avanzados, entre ellos el cálculo del índice de Moran, para evaluar la autocorrelación espacial de los delitos y explorar su relación con las características sociodemográficas y del entorno urbano.

Los datos provienen de cuatro vecindarios de la ciudad de Cincinnati —Clifton, Walnut Hills, Evanston y Avondale— ubicados en el condado de Hamilton, Ohio (Estados Unidos). Las 457 observaciones corresponden a bloques censales individuales dentro de estas áreas y contienen información sociodemográfica y delictiva registrada durante los últimos seis meses de 2008. Cada registro representa un bloque censal específico en el cual se midieron variables asociadas a población, vivienda y criminalidad.

Variable Unidades Nº de muestras Descripción Tipo de variable
POPULATION Habitantes 457 Población total del bloque Independiente (numérica)
MALE Habitantes 457 Población masculina del bloque Independiente (numérica)
FEMALE Habitantes 457 Población femenina del bloque Independiente (numérica)
AGE_X_Y Habitantes 457 Población según rango de edad de X a Y años Independiente (numérica)
MEDIAN_AGE Años 457 Edad mediana del bloque Independiente (numérica)
AGE_X Habitantes 457 Población con edad mayor o igual a X años Independiente (numérica)
MALE_X Habitantes 457 Hombres con edad mayor o igual a X años Independiente (numérica)
FEMALE_X Habitantes 457 Mujeres con edad mayor o igual a X años Independiente (numérica)
F1_RACE Habitantes 457 Personas que declararon al menos una raza Independiente (numérica)
BURGLARY Conteos 457 Número de robos tipo burglary Dependiente (conteo)
ASSAULT Conteos 457 Número de agresiones Independiente (conteo)
THEFT Conteos 457 Número de hurtos Independiente (conteo)
BURG_D 0/1 457 Indicador de robo (1 si ocurrió ≥1 incidente) Independiente (binaria)
ASSALT_D 0/1 457 Indicador de agresión (1 si ocurrió ≥1 incidente) Independiente (binaria)

2. Análisis exploratorio con base en correlaciones y/o gráficas que ilustre relación entre la variable respuesta y cada variable explicativa

El análisis de correlaciones de Spearman entre BURGLARY y el conjunto de covariables evidencia que casi todas las asociaciones resultan estadísticamente significativas, principalmente debido al tamaño de la muestra espacial. Por ello, la interpretación debe centrarse en la magnitud de las correlaciones. La única relación extremadamente alta se observa con BURG_D, una variable derivada directamente de BURGLARY, lo que refleja colinealidad perfecta y la excluye de cualquier modelo explicativo.

El patrón general muestra correlaciones moderadas con variables demográficas, residenciales y criminológicas. Entre ellas se destacan el tamaño de la población, la estructura de hogares, la proporción de población joven, ciertos grupos raciales, la presencia de viviendas vacías y la incidencia de otros delitos (p. ej., THEFT y ASSAULT). Estas asociaciones indican que los sectores con mayores tasas de BURGLARY tienden a presentar mayor densidad poblacional, mayor presencia de viviendas y hogares, mayor diversidad racial y una concentración espacial de criminalidad, lo cual coincide con teorías urbanas y de desorganización social.

Tabla de correlacion entre Robos y las covariables

##              variable    spearman        pvalue
## BURG_D         BURG_D  0.98303240 2.997627e-281
## POPULATION POPULATION  0.45666525  5.017353e-21
## F1_RACE       F1_RACE  0.45625438  5.493512e-21
## MALE             MALE  0.45578554  6.091394e-21
## FEMALE         FEMALE  0.44821364  3.160877e-20
## THEFT           THEFT  0.38869397  3.439550e-15
## ASSAULT       ASSAULT  0.33426799  2.130152e-11
## THEFT_D       THEFT_D  0.32507727  7.934775e-11
## ASSALT_D     ASSALT_D  0.29765363  3.109318e-09
## MEDIAN_AGE MEDIAN_AGE -0.06938072  1.765556e-01

Los resultados muestran que las variables más relacionadas con los casos de BURGLARY son aquellas que describen directamente el delito y el tamaño de la población. La variable BURG_D presenta la relación más fuerte, como era de esperarse, porque indica si ocurrió o no al menos un robo en cada zona. Además, POPULATION, F1_RACE, MALE y FEMALE muestran correlaciones positivas moderadas, lo que significa que los lugares con más habitantes, tanto hombres como mujeres, tienden a registrar más robos. También se observan relaciones positivas, aunque más débiles, con otros delitos como THEFT y ASSAULT, lo que sugiere que los sectores con mayor criminalidad general también suelen presentar más casos de BURGLARY. Finalmente, la única correlación negativa aparece en la variable MEDIAN_AGE, aunque es muy baja. Esto indica que, en general, las zonas con población más adulta o envejecida tienden a tener ligeramente menos robos.

3. Estimación de un modelo adecuado

## 
## Call:
## glm(formula = BURGLARY ~ F1_RACE, family = poisson(link = "log"), 
##     data = datos2, offset = log(POPULATION))
## 
## Coefficients:
##               Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -5.0299944  0.0922386 -54.532   <2e-16 ***
## F1_RACE     -0.0006416  0.0002697  -2.379   0.0173 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for poisson family taken to be 1)
## 
##     Null deviance: 423.01  on 380  degrees of freedom
## Residual deviance: 416.36  on 379  degrees of freedom
## AIC: 694.65
## 
## Number of Fisher Scoring iterations: 5

Ecuacion matematica del modelo de Poisson

\[ \log(\mu_i) = \log(\text{Population}_i) - 5.0299944 - 0.0006416\,(\text{F1_Race}_i) \]

4. Interpretación del modelo estimado

El modelo que se ajustó es un modelo de Poisson con enlace log y con un offset basado en el logaritmo de la población. Esto significa que en lugar de modelar directamente el número total de robos (burglary), el modelo analiza la tasa de robos por habitante. El valor del intercepto (−5.0299944) indica cuál sería la tasa esperada de robos por persona cuando la variable F1_RACE vale cero. Si se transforma ese valor, se obtiene una tasa aproximada de 0.0065 robos por persona, lo que equivale a unos 6.5 robos por cada 1.000 habitantes. Este número simplemente sirve como punto de partida para entender cómo la variable F1_RACE modifica esa tasa.

El coeficiente asociado a F1_RACE es de −0.0006416 y su valor p muestra que es estadísticamente significativo. En palabras simples, esto quiere decir que, a medida que aumenta el valor de F1_RACE, la tasa de robos tiende a disminuir un poco. Aunque el cambio por cada unidad es muy pequeño (una reducción cercana al 0.064%), cuando el aumento en F1_RACE es mayor, por ejemplo de 100 unidades, el efecto se vuelve más notorio y puede representar alrededor de un 6% menos en la tasa de robos. El resultado indica una relación negativa, pero débil en tamaño, entre F1_RACE y los niveles de burglary.

En cuanto al ajuste general del modelo, la diferencia entre la devianza del modelo nulo y la devianza del modelo final es pequeña, lo que indica que incluir F1_RACE apenas mejora el modelo. Además, el cociente entre la devianza y los grados de libertad (aproximadamente 1.10) sugiere una ligera sobredispersión, pero nada grave. El AIC del modelo sirve para compararlo con otros posibles modelos, siendo un indicador del equilibrio entre simplicidad y buen ajuste. Finalmente, aunque el efecto encontrado es significativo, se recomienda interpretarlo con cuidado y considerar modelos más completos que incluyan otras variables, así como revisar posibles problemas en los residuos o autocorrelación espacial para asegurar que las conclusiones sean fiables.

5. Calcular alguna predicción

##   F1_RACE POPULATION Prediccion_Burglary_Esperado
## 1     100        500                     3.066236
## 2     300       1200                     6.472705
## 3     800       2500                     9.784011

Las predicciones muestran cuántos robos (burglary) se espera que ocurran en un área, según el tamaño de su población y el valor de F1_RACE. Por ejemplo, en una zona con 500 habitantes y 100 personas registradas en F1_RACE, el modelo espera aproximadamente 3 robos. En un área más grande, con 1.200 habitantes y 300 personas en F1_RACE, se esperan alrededor de 6.47 robos. Finalmente, en una zona de 2.500 habitantes y 800 personas en F1_RACE, el modelo predice cerca de 9.78 robos. En general, estas predicciones muestran que, aunque F1_RACE tiene un efecto negativo muy pequeño sobre la tasa, el factor que más influye en el número esperado de robos es la población: a mayor población, mayor número esperado de incidentes.

6. Códigos Utilizados en R

library(sf)
library(spdep)
library(terra)
library(ggplot2)
library(FNN)  
library(adespatial)

shp <- st_read("D:/15.UNAL_Estadistica/EstadisticaEspacialAplicada/Datos_Lattice/walnuthills_updated/cincinnati.shp")
shp_wgs84 <- st_transform(shp, 4326)

ggplot() +
  geom_sf(data = shp_wgs84, fill = "lightblue", color = "gray20") +
  theme_minimal() +
  labs(
    title = "Shapefile en coordenadas geográficas WGS84",
  )

datos <- st_drop_geometry(shp)
datos <- as.data.frame(datos)

shp2   <- shp[shp$POPULATION > 0, ]
datos2 <- subset(datos, POPULATION > 0)

datos2 <- st_drop_geometry(shp2)
datos2 <- as.data.frame(datos2)

plot(datos2$BURGLARY ~ datos2$MSA); abline(lm(BURGLARY ~ MSA, data=datos2), col="blue", lwd=2); lines(lowess(datos2$MSA, datos2$BURGLARY), col="red", lwd=2)
plot(datos2$BURGLARY ~ datos2$POPULATION); abline(lm(BURGLARY ~ POPULATION, data=datos2), col="blue", lwd=2); lines(lowess(datos2$POPULATION, datos2$BURGLARY), col="red", lwd=2)
plot(datos2$BURGLARY ~ datos2$MALE); abline(lm(BURGLARY ~ MALE, data=datos2), col="blue", lwd=2); lines(lowess(datos2$MALE, datos2$BURGLARY), col="red", lwd=2)
plot(datos2$BURGLARY ~ datos2$FEMALE); abline(lm(BURGLARY ~ FEMALE, data=datos2), col="blue", lwd=2); lines(lowess(datos2$FEMALE, datos2$BURGLARY), col="red", lwd=2)
# ---- Grupo: Raza ----
plot(datos2$BURGLARY ~ datos2$F1_RACE); abline(lm(BURGLARY ~ F1_RACE, data=datos2), col="blue", lwd=2); lines(lowess(datos2$F1_RACE, datos2$BURGLARY), col="red", lwd=2)
plot(datos2$BURGLARY ~ datos2$WHITE); abline(lm(BURGLARY ~ WHITE, data=datos2), col="blue", lwd=2); lines(lowess(datos2$WHITE, datos2$BURGLARY), col="red", lwd=2)

covars_tabla <- c(
  "POPULATION", "MALE", "FEMALE",
  "AGE_X_Y", "MEDIAN_AGE", "AGE_X",
  "MALE_X", "FEMALE_X",
  "F1_RACE",
  "ASSAULT", "THEFT",
  "BURG_D", "ASSALT_D", "THEFT_D"
)

vars_validas <- covars_tabla[covars_tabla %in% names(datos2)]

covars_numeric <- vars_validas[sapply(datos2[vars_validas], is.numeric)]

resultados <- data.frame(
  variable = covars_numeric,
  spearman = sapply(covars_numeric, function(v)
    cor(datos2$BURGLARY, datos2[[v]], method = "spearman")
  ),
  pvalue = sapply(covars_numeric, function(v)
    cor.test(datos2$BURGLARY, datos2[[v]], method = "spearman")$p.value
  )
)
resultados_ordenados <- resultados[order(-abs(resultados$spearman)), ]

print(resultados_ordenados)

modelo1 <- glm(
  BURGLARY ~ F1_RACE,
  family = poisson(link = "log"),
  offset = log(POPULATION),
  data   = datos2
)
summary(modelo1)
nuevos_datos <- data.frame(
  F1_RACE    = c(100, 300, 800),
  POPULATION = c(500, 1200, 2500)
)
predicciones <- predict(
  modelo1,
  newdata = nuevos_datos,
  type = "response"
)

data.frame(nuevos_datos, Prediccion_Burglary_Esperado = predicciones)