Autocorrelación espacial: método global y local
## ── 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
## Cargando paquete requerido: spData
## To access larger datasets in this package, install the spDataLarge
## package with: `install.packages('spDataLarge',
## repos='https://nowosad.github.io/drat/', type='source')`
## Cargando paquete requerido: sf
## Linking to GEOS 3.13.1, GDAL 3.11.0, PROJ 9.6.0; sf_use_s2() is TRUE
#área sobre la cual trabajo, limite de la ciudad de Lima Metropolitana - Perú (poligono para identificar el mapa del delito patrimonial incluye robos y hurtos)
lima <- st_read("C:/_ALIDE/Documentos/data_ciencia/MPP-CDD-02/data/lima_metropolitana.shp") ## Reading layer `lima_metropolitana' from data source
## `C:\_ALIDE\Documentos\data_ciencia\MPP-CDD-02\data\lima_metropolitana.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 1 feature and 1 field
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: -77.1988 ymin: -12.51993 xmax: -76.62082 ymax: -11.57241
## Geodetic CRS: SIRGAS 2000
#Cargo la base de delitos patrimoniales 2024 (con columnas longitud/latitud).
# Cada fila representa un evento puntual georreferenciado.
delitos <- read_excel("C:/_ALIDE/Documentos/data_ciencia/MPP-CDD-02/data/hurtos_lima_2024.xlsx")# Convierto delitos a sf (asegurándonos de que longitud y latitud estén bien definidos)
delitos_sf <- st_as_sf(delitos, coords = c("longitud", "latitud"), crs = 4326)
# Me aseguro que el polígono de Lima y los delitos compartan el mismo CRS (4326). Esto permite superponerlos correctamente en mapas iniciales.
lima <- st_transform(lima, 4326)
delitos_sf <- st_transform(delitos_sf, 4326)# Mapa básico para chequear la distribución de puntos dentro del polígono de Lima.
ggplot() +
geom_sf(data = lima, fill = "grey95", color = "black", linewidth = 0.3) +
geom_sf(data = delitos_sf, color = "red", size = 1, alpha = 0.6) +
labs(
title = "Ubicación de delitos patrimoniales en Lima Metropolitana",
caption = "Fuente: MINITER |Observatorio Nacional de Seguridad Ciudadana 2024"
) +
theme_minimal()## Coordinate Reference System:
## User input: EPSG:4326
## wkt:
## GEOGCRS["WGS 84",
## ENSEMBLE["World Geodetic System 1984 ensemble",
## MEMBER["World Geodetic System 1984 (Transit)"],
## MEMBER["World Geodetic System 1984 (G730)"],
## MEMBER["World Geodetic System 1984 (G873)"],
## MEMBER["World Geodetic System 1984 (G1150)"],
## MEMBER["World Geodetic System 1984 (G1674)"],
## MEMBER["World Geodetic System 1984 (G1762)"],
## MEMBER["World Geodetic System 1984 (G2139)"],
## MEMBER["World Geodetic System 1984 (G2296)"],
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]],
## ENSEMBLEACCURACY[2.0]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Horizontal component of 3D system."],
## AREA["World."],
## BBOX[-90,-180,90,180]],
## ID["EPSG",4326]]
# Para medir distancias, crear grillas y hacer estadística espacial,
# se convirtió a metros
lima_metros <- st_transform(lima, 32718)
st_crs(lima_metros)## Coordinate Reference System:
## User input: EPSG:32718
## wkt:
## PROJCRS["WGS 84 / UTM zone 18S",
## BASEGEOGCRS["WGS 84",
## ENSEMBLE["World Geodetic System 1984 ensemble",
## MEMBER["World Geodetic System 1984 (Transit)"],
## MEMBER["World Geodetic System 1984 (G730)"],
## MEMBER["World Geodetic System 1984 (G873)"],
## MEMBER["World Geodetic System 1984 (G1150)"],
## MEMBER["World Geodetic System 1984 (G1674)"],
## MEMBER["World Geodetic System 1984 (G1762)"],
## MEMBER["World Geodetic System 1984 (G2139)"],
## MEMBER["World Geodetic System 1984 (G2296)"],
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]],
## ENSEMBLEACCURACY[2.0]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## ID["EPSG",4326]],
## CONVERSION["UTM zone 18S",
## METHOD["Transverse Mercator",
## ID["EPSG",9807]],
## PARAMETER["Latitude of natural origin",0,
## ANGLEUNIT["degree",0.0174532925199433],
## ID["EPSG",8801]],
## PARAMETER["Longitude of natural origin",-75,
## ANGLEUNIT["degree",0.0174532925199433],
## ID["EPSG",8802]],
## PARAMETER["Scale factor at natural origin",0.9996,
## SCALEUNIT["unity",1],
## ID["EPSG",8805]],
## PARAMETER["False easting",500000,
## LENGTHUNIT["metre",1],
## ID["EPSG",8806]],
## PARAMETER["False northing",10000000,
## LENGTHUNIT["metre",1],
## ID["EPSG",8807]]],
## CS[Cartesian,2],
## AXIS["(E)",east,
## ORDER[1],
## LENGTHUNIT["metre",1]],
## AXIS["(N)",north,
## ORDER[2],
## LENGTHUNIT["metre",1]],
## USAGE[
## SCOPE["Navigation and medium accuracy spatial referencing."],
## AREA["Between 78°W and 72°W, southern hemisphere between 80°S and equator, onshore and offshore. Argentina. Brazil. Chile. Colombia. Ecuador. Peru."],
## BBOX[-80,-78,0,-72]],
## ID["EPSG",32718]]
# Creo una grilla de celdas (hexágonos) de ~1000 m.
# Esta grilla será la "unidad de análisis" para contar delitos.
grilla <- lima_metros %>%
st_make_grid(1000, what="polygons", square = FALSE)## [1] "sfc_POLYGON" "sfc"
#Superpongo puntos sobre la grilla para ver densidad visualmente.
ggplot()+
geom_sf(data=grilla)+
geom_sf(data=delitos_sf, alpha=0.1, size=0.5)# Transformo los delitos a metros (mismo CRS que la grilla) y
# recorto a Lima por seguridad.
delitos_metros <- st_transform(delitos_sf, 32718)
delitos_metros <- st_filter(delitos_metros, lima_metros)
# Me aseguro que la grilla tenga un ID único para indexar vecinos/conteos.
grilla <- st_sf(grilla)
if (!"ID" %in% names(grilla)) grilla$ID <- seq_len(nrow(grilla))
# Cuenta delitos por hexágono (intersección espacial)
# la idea es contar cuantos delitos caen dentro de cada hexágono usando st_intersects().
# 'idx' es una lista: para cada hex, qué puntos caen dentro; luego usamos lengths().
idx <- st_intersects(grilla, delitos_metros)
grilla$N_DELITOS <- lengths(idx) # conteo# Mapa que muestra el número de delitos por hexágono (transformación sqrt para contraste).
ggplot() +
geom_sf(data = grilla, aes(fill = N_DELITOS), color = NA) +
geom_sf(data = st_boundary(lima_metros), color = "grey30", linewidth = 0.3) +
scale_fill_viridis_c(trans = "sqrt", na.value = "grey90") +
labs(title = "Delitos patrimoniales por hexágono (1000 mts) \nLima Metropolitana, 2024",
fill = "N° delitos patrimoniales") +
theme_minimal()
``
#identificamos vecinos, la base para calcular autocorrelaciones espaciales.
vecinos <- poly2nb(pl=grilla,
row.names = grilla$ID)## [1] "nb"
## Neighbour list object:
## Number of regions: 3326
## Number of nonzero links: 19110
## Percentage nonzero weights: 0.1727493
## Average number of links: 5.74564
## [1] 3 4 3 2 3 6 4 2 6 3 5 3 4 5 5 4 6 4 4 4 6 4 6 4 6 5 6 5 3 4 6 6 4 6 6 6 5
## [38] 4 4 6 6 3 6 6 6 6 6 5 6 6 5 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 3 3 6 6 6
## [75] 6 6 6 6 6 5 4 5 6 6 6 6 6 6 6 6 6 3 6 6 6 6 6 6 6 6 6 6 4 6 6 6 6 6 6 6 6
## [112] 6 5 3 6 6 6 6 6 6 6 6 6 6 4 4 3 5 6 6 6 6 6 6 6 6 6 6 5 6 1 3 6 6 6 6 6 6
## [149] 6 6 6 6 6 6 4 2 3 3 6 6 6 6 6 6 6 6 6 6 6 6 6 4 4 5 3 5 6 6 6 6 6 6 6 6 6
## [186] 6 6 6 5 5 5 6 5 4 5 6 6 6 6 6 6 6 6 6 6 6 6 6 3 3 3 6 6 6 4 4 6 6 6 6 6 6
## [223] 6 6 6 6 6 6 6 6 6 3 4 6 6 6 6 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 3 3 5
## [260] 6 6 6 6 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 5 6 3 4 4 6 6 6 6 6 4 3 4 6
## [297] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 6 5 6 5 6 6 6 6 6 6 5 5 6 6 6 6 6 6 6 6
## [334] 6 6 6 6 6 6 6 6 6 5 3 6 6 4 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [371] 6 6 6 6 6 5 4 5 6 6 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [408] 6 6 6 4 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [445] 6 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5
## [482] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 3 6 6
## [519] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [556] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 5 6 6 6 6 6 6
## [593] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 4 6 6 6 6 6 6 6 6
## [630] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 6 6 6 6 6 6 6
## [667] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 6 6 6 6 6 6 6 3 3 3 2 3 6 6 6 6 6 6 6 6
## [704] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 4 6 6 6 6 6 6 6 4 3 5 5 6 6 6 6 6 6 6
## [741] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 5 6 6 5 6 6 6 5 6 6 5 3 5 6 6 6 6 6
## [778] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 5 4 4 6 6 6 5 6 6 5 5 6 6 6 6 6
## [815] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 2 3 3 4 6 6 3 3 6 6 6 6 6 6 6 6 6
## [852] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 4 6 5 6 6 6 6 6 6 6 6 6 6 6 6 6
## [889] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 4 6 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [926] 6 6 6 6 6 6 6 6 6 6 6 6 4 3 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [963] 6 6 6 6 6 6 6 4 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1000] 6 6 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 6
## [1037] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 6 6 6 6 6 6 6 6 6
## [1074] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1111] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1148] 6 6 6 6 6 6 6 6 6 3 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1185] 6 6 6 6 6 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1222] 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6
## [1259] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 6 6 6 6 6
## [1296] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 6 6 6 6 6 6 6 6 6 6 6
## [1333] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1370] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1407] 6 6 6 5 6 6 6 6 6 6 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 4
## [1444] 6 6 6 6 6 6 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 6 6
## [1481] 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 4 6 6 6 6 6 5 6 6 6 6
## [1518] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 6 6 6 5 6 6 6 6 5 4 6 6 6 6 6 6 6 6 6 6
## [1555] 6 6 6 6 6 6 6 6 6 4 4 5 6 6 5 6 6 6 6 6 4 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1592] 6 6 6 6 5 3 4 5 6 3 4 6 6 6 6 6 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1629] 3 5 6 6 5 6 6 6 6 3 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 4 3 4 4 6
## [1666] 6 6 6 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 6 3 5 6 6 6 4 6 6 6 6 6
## [1703] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 4 3 6 6 6 6 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1740] 6 6 6 6 6 6 3 5 6 6 6 4 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 3 6 6
## [1777] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 6 6 6 6 3 5 6 6 6 6 6 6 6
## [1814] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 4 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1851] 6 6 6 6 4 6 6 6 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 5 6
## [1888] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 6 6 4 3 6 6 6 6 6 6 6 6 6 6 6
## [1925] 6 6 6 6 6 6 6 6 6 6 6 3 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [1962] 6 6 6 6 6 4 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 3 6 6 6 4 6 6
## [1999] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 2 4 6 6 4 4 6 6 6 6 6 6 6 6 6 6
## [2036] 6 6 6 6 6 6 6 6 6 6 6 6 6 5 4 6 6 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2073] 6 6 6 6 6 5 6 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 6 4
## [2110] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 4 6 4 3 6 6 6 6 6 6 6
## [2147] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2184] 6 6 6 6 6 6 6 6 6 6 5 3 6 3 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2221] 6 6 6 6 3 4 5 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6
## [2258] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 2 2 3 3 2 5 6 6 6 6
## [2295] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 4 5 6 6 6 6 6 6 6 6 6 6
## [2332] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 5 6 6 4 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2369] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 5 6 6 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2406] 6 6 6 6 6 6 6 6 6 6 6 5 4 5 6 6 4 3 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2443] 6 6 6 6 6 6 6 6 6 6 6 3 2 6 6 6 4 4 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2480] 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6 6 6 5 6 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2517] 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2554] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 2 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2591] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2628] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 6 5 6 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2665] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 4 4 4 4 3 5 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2702] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 3 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2739] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2776] 6 6 6 6 6 6 6 6 6 6 6 5 2 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2813] 6 6 6 6 6 6 6 6 4 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2850] 6 6 6 6 6 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [2887] 6 6 2 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4
## [2924] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 3 6 6 6
## [2961] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 6 6 6 6 6 5 6 6 6 6 6 6 5 5 6 6 6 6 6 6 6
## [2998] 6 6 6 6 6 6 6 6 6 6 4 5 6 6 6 6 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [3035] 6 6 6 6 5 6 6 6 6 4 5 6 6 6 6 6 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 6
## [3072] 6 6 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 3 6 6 6 4 4 6 6 6 6 6
## [3109] 3 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 4 6 6 5 6 6 6 6 6 4 6 6 6 6 6 6 6 6
## [3146] 6 6 6 6 6 6 6 5 5 6 6 6 4 6 6 6 6 4 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 4 4 3 6
## [3183] 6 3 6 6 6 6 5 4 6 5 5 6 6 6 6 6 6 6 6 6 6 4 2 4 5 4 3 6 6 6 6 4 4 3 4 6 6
## [3220] 6 6 6 6 6 6 6 5 3 3 5 6 6 6 3 3 4 6 6 6 6 6 6 6 6 6 6 6 6 4 5 6 6 6 6 6 6
## [3257] 6 6 3 3 6 6 4 6 6 6 6 6 6 6 6 4 5 6 4 3 5 6 6 6 6 6 6 4 6 5 3 5 6 6 6 6 6
## [3294] 4 3 5 6 6 6 6 6 4 3 2 3 6 6 6 6 4 4 6 6 6 4 4 6 6 5 4 5 6 3 4 3 3
# Se agrega a la grilla la cantidad de vecinos para visualizar variación
grilla <- grilla %>%
mutate(N_VECINOS=card(vecinos))# Mapa del número de vecinos
ggplot()+
geom_sf(data=grilla, aes(fill=N_VECINOS))+
scale_fill_viridis_c(direction=-1)MATRIZ DE PESOS ESPACIALES
# Se crea la matriz de pesos espaciales (estilo W: cada fila suma 1).
# zero.policy=TRUE evita errores cuando alguna celda no tiene vecinos.
pesos_vecinos <- nb2listw(vecinos,
style="W",
zero.policy=TRUE)INDICADOR GLOBAL MORAN
# Se reemplaza NAs en N_DELITOS por 0 (hexágonos sin delitos).
grilla <- grilla %>%
mutate(N_DELITOS=if_else(is.na(N_DELITOS), 0, N_DELITOS))# Valor de I: >0 indica clustering positivo (zonas similares se agrupan)
i_moran <- moran(x=grilla$N_DELITOS,
listw=pesos_vecinos,
n=nrow(grilla),
S0=Szero(pesos_vecinos))## [1] 0.2157629
Prueba de hipotesis
#Opcion de p-value con el moran test
moran_test <- moran.test(x=grilla$N_DELITOS,
listw=pesos_vecinos)##
## Moran I test under randomisation
##
## data: grilla$N_DELITOS
## weights: pesos_vecinos
##
## Moran I statistic standard deviate = 22.907, p-value <
## 0.00000000000000022
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic Expectation Variance
## 0.21576287122 -0.00030075188 0.00008896932
#Especie de Regresion
#Gráfico: N_DELITOS vs. su rezago espacial (promedio de vecinos).
moran.plot(x=grilla$N_DELITOS,
listw = pesos_vecinos,
zero.policy=TRUE)ggplot()+
geom_point(data=grilla, aes(x=N_DELITOS, y=lag_DELITOS))+
geom_smooth(data=grilla, aes(x=N_DELITOS, y=lag_DELITOS), method="lm")## `geom_smooth()` using formula = 'y ~ x'
# Calculamos LISA para identificar "dónde" hay clustering y de qué tipo (HH, LL, HL, LH).
# La idea es buscar los puntos locales, las zonas calientes y zonas frías
moran_local <- localmoran(x=grilla$N_DELITOS,
listw = pesos_vecinos)## [1] 3326
#Pegar los resultados de LISA a la grilla y renombramos p-value para claridad.
grilla <- grilla %>%
cbind(moran_local)#Exploro Cuántas celdas son estadísticamente significativas (p<0.05)
grilla %>%
filter(p_valor<0.05) %>%
count()# Mapa binario de significancia
ggplot()+
geom_sf(data=grilla %>%
mutate(significativo=if_else(p_valor<0.05, "Si", "No")), aes(fill=significativo))# Se normaliza las variables para clasificar cuadrantes (alto/bajo contra vecinos).
# Si en la turquesa es significativo me dice donde es mas peligroso
#Primero tenemos que normalizar la información, para definir que números son hot, frios...
grilla <- grilla %>%
mutate(z_DELITOS= (N_DELITOS-mean(N_DELITOS))/sd(N_DELITOS),
z_lag_DELITOS= (lag_DELITOS-mean(lag_DELITOS))/sd(lag_DELITOS))# Se asigna al cuadrante LISA clásico (solo significado, la significancia se filtra al graficar)
grilla <- grilla %>%
mutate(cuadrante=case_when(z_DELITOS>0 & z_lag_DELITOS>0 ~ "H-H: Alto-Alto",
z_DELITOS<0 & z_lag_DELITOS<0 ~ "L-L: Bajo-Bajo",
z_DELITOS>0 & z_lag_DELITOS<0 ~ "H-L: Alto-Bajo",
z_DELITOS<0 & z_lag_DELITOS>0 ~ "L-H: Bajo-Alto"))# Mapas LISA: sólo las celdas significativas (p<0.05) y coloreadas por cuadrante.
ggplot()+
geom_sf(data=grilla %>% filter(p_valor<0.05), aes(fill=cuadrante))ggplot()+
geom_sf(data=grilla) +
geom_sf(data=grilla %>% filter(p_valor<0.05), aes(fill=cuadrante))+
scale_fill_manual(values=c("H-H: Alto-Alto"="red",
"H-L: Alto-Bajo"="pink",
"L-L: Bajo-Bajo"="blue",
"L-H: Bajo-Alto"="lightskyblue"))grilla %>%
st_transform(4326) %>%
filter(p_valor<0.05) %>%
leaflet() %>%
addTiles() %>%
addPolygons(
fillColor = ~case_when(
cuadrante == "H-H: Alto-Alto" ~ "red",
cuadrante == "H-L: Alto-Bajo" ~ "pink",
cuadrante == "L-L: Bajo-Bajo" ~ "blue",
cuadrante == "L-H: Bajo-Alto" ~ "lightskyblue",
cuadrante == "No Significativo" ~ "white",
TRUE ~ "grey80"),
color = "#333333",
weight = 0.3,
fillOpacity = 0.5,
popup = ~paste0("<b>Cuadrante:</b> ", cuadrante)) %>%
addLegend(
"bottomright",
colors = c("red", "pink", "blue", "lightskyblue", "white"),
labels = c("H-H: Alto-Alto", "H-L: Alto-Bajo", "L-L: Bajo-Bajo",
"L-H: Bajo-Alto", "No Significativo"),
title = "Clúster LISA") %>%
addMiniMap()# Relacionar delitos con accesibilidad a la infraestructura policial.
comisarias <- read_excel("C:/_ALIDE/Documentos/data_ciencia/MPP-CDD-02/data/comisaria_lima.xlsx")# quitar filas sin coordenadas
comisarias <- comisarias[!is.na(comisarias$longitud) & !is.na(comisarias$latitud), ]
#Llevado a metros llevar a metros y recortar a Lima, igual a lo hecho con delitos.
comisarias <- st_as_sf(comisarias, coords = c("longitud", "latitud"), crs = 4326)
comisarias_metros <- st_transform(comisarias, 32718)
# por seguridad, recortar al polígono de Lima
comisarias_metros <- st_filter(comisarias_metros, lima_metros)# distancia mínima a comisaría más cercana por hexágono.
# Usamos el centroide del hexágono como referencia.
cent_hex <- st_centroid(grilla)## Warning: st_centroid assumes attributes are constant over geometries
dist_mat <- st_distance(cent_hex, comisarias_metros)
# si no hay comisarías dentro, evitar error
if (ncol(dist_mat) == 0) stop("No hay comisarías dentro del área de Lima. Revisa la base comisaria_lima.xlsx.")
# Guardamos la distancia mínima (en metros) por hexágono.
grilla$DIST_COMISARIA_M <- apply(dist_mat, 1, min)
summary(grilla$DIST_COMISARIA_M)## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 38.67 1914.84 4165.65 6427.21 9424.64 25921.60
# Moran global sobre la variable de distancia a comisaría.
moran_dist <- moran.test(x = grilla$DIST_COMISARIA_M,
listw = pesos_vecinos,
zero.policy = TRUE)
# Verifica si hay patrón espacial en accesibilidad policial
moran_dist ##
## Moran I test under randomisation
##
## data: grilla$DIST_COMISARIA_M
## weights: pesos_vecinos
##
## Moran I statistic standard deviate = 96.238, p-value <
## 0.00000000000000022
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic Expectation Variance
## 0.9931590509 -0.0003007519 0.0001065639
# para distancia a comisarías (identifica clústeres de alta/baja distancia).
moran_local_dist <- localmoran(x = grilla$DIST_COMISARIA_M,
listw = pesos_vecinos,
zero.policy = TRUE)# se pega resultados y calculamos z-scores para clasificar cuadrantes.
grilla$Ii_dist <- moran_local_dist[, "Ii"]
grilla$Z_Ii_d <- moran_local_dist[, "Z.Ii"]
grilla$p_dist <- moran_local_dist[, "Pr(z != E(Ii))"]
lag_dist <- lag.listw(pesos_vecinos, grilla$DIST_COMISARIA_M, zero.policy = TRUE)
z_x <- (grilla$DIST_COMISARIA_M - mean(grilla$DIST_COMISARIA_M, na.rm = TRUE)) /
sd(grilla$DIST_COMISARIA_M, na.rm = TRUE)
z_lx <- (lag_dist - mean(lag_dist, na.rm = TRUE)) /
sd(lag_dist, na.rm = TRUE)
grilla$cuadrante_dist <- ifelse(grilla$p_dist < 0.05,
ifelse(z_x > 0 & z_lx > 0, "HH: Distancia alta",
ifelse(z_x < 0 & z_lx < 0, "LL: Distancia baja",
ifelse(z_x > 0 & z_lx < 0, "HL: Alta-Bajas vecinas",
ifelse(z_x < 0 & z_lx > 0, "LH: Baja-Altas vecinas", NA)))),
"No sig.")#
# MAPA: distancia mínima a comisaría (sqrt para mejorar contraste).
ggplot() +
geom_sf(data = grilla, aes(fill = DIST_COMISARIA_M), color = NA) +
geom_sf(data = st_boundary(lima_metros), color = "grey10", linewidth = 0.4) +
scale_fill_gradientn(
colours = c("#ffffcc", "#ffcc00", "#ff6600", "#cc0000", "#330000"),
trans = "sqrt",
name = "Dist. a comisaría (m)"
) +
labs(title = "Distancia mínima a comisaría — Zonas críticas en rojo oscuro") +
theme_minimal()# MAPA: clústeres LISA de distancia (dónde hay déficit/exceso relativo de proximidad).
ggplot() +
geom_sf(data = grilla, aes(fill = cuadrante_dist), color = NA) +
geom_sf(data = st_boundary(lima_metros), color = "grey30", linewidth = 0.3) +
scale_fill_manual(values = c("HH: Distancia alta" = "red",
"LL: Distancia baja" = "blue",
"HL: Alta-Bajas vecinas" = "pink",
"LH: Baja-Altas vecinas" = "lightskyblue",
"No sig." = "grey90"),
drop = FALSE, name = "LISA distancia (p<0.05)") +
labs(title = "Clústeres LISA — Distancia a comisarías (hexágonos 1 km)") +
theme_minimal()# Porcentaje de hexágonos donde la LISA fue significativa (p<0.05).
prop_sig_dist <- mean(grilla$p_dist < 0.05, na.rm = TRUE)
prop_sig_dist## [1] 0.4046903
grilla %>%
st_transform(4326) %>%
filter(p_dist < 0.05) %>% # solo clústeres significativos
leaflet() %>%
addTiles() %>%
addPolygons(
fillColor = ~case_when(
cuadrante_dist == "HH: Distancia alta" ~ "darkred",
cuadrante_dist == "LL: Distancia baja" ~ "darkgreen",
cuadrante_dist == "HL: Alta-Bajas vecinas" ~ "orange",
cuadrante_dist == "LH: Baja-Altas vecinas" ~ "lightblue",
cuadrante_dist == "No sig." ~ "white",
TRUE ~ "grey80"
),
color = "#333333",
weight = 0.3,
fillOpacity = 0.6,
popup = ~paste0(
"<b>Clúster:</b> ", cuadrante_dist, "<br>",
"<b>Dist. mín. a comisaría (m):</b> ", round(DIST_COMISARIA_M, 1)
)
) %>%
addLegend(
"bottomright",
colors = c("darkred", "orange", "darkgreen", "lightblue", "white"),
labels = c(
"HH: Distancia alta",
"HL: Alta - Vecinas bajas",
"LL: Distancia baja",
"LH: Baja - Vecinas altas",
"No significativo"
),
title = "Clúster LISA (distancia)"
) %>%
addMiniMap()