Bivariate Moran's I between two attributes at the same polygons
Source:R/tps_spatial_advanced.R
morie_tps_bivariate_moran.RdGeneralises morie_tps_polygon_morans_i to two
attributes: measures the cross-correlation between attribute X at
location i and attribute Y at neighbouring locations j.
Usage
morie_tps_bivariate_moran(
polygons,
x_col,
y_col,
ds_name = "NeighbourhoodCrimeRates",
k_neighbours = 5L,
centroid_lat_col = "lat",
centroid_lon_col = "lon"
)Details
$$I_{xy} = \frac{n}{S_0}\,\frac{\sum_i \sum_j w_{ij}\, z^x_i\, z^y_j}{\sqrt{\sum_i (z^x_i)^2 \cdot \sum_i (z^y_i)^2}}$$
Polygon centroids and k-NN weights are constructed exactly as in
morie_tps_polygon_morans_i; distances use the
haversine formula for parity with the Python source.
Examples
set.seed(2026)
polys <- data.frame(
HOOD_ID = letters[1:16],
lat = rep(43.6 + (0:3) * 0.02, 4),
lon = rep(-79.4 + (0:3) * 0.02, each = 4),
ASSAULT_RATE_2024 = rpois(16, 30),
HOMICIDE_RATE_2024 = rpois(16, 2)
)
morie_tps_bivariate_moran(polys,
x_col = "ASSAULT_RATE_2024",
y_col = "HOMICIDE_RATE_2024",
centroid_lat_col = "lat", centroid_lon_col = "lon")
#> Bivariate Moran's I -- ASSAULT_RATE_2024 vs HOMICIDE_RATE_2024
#> ==============================================================
#> Call: morie_tps_bivariate_moran(x=ASSAULT_RATE_2024, y=HOMICIDE_RATE_2024, k=5)
#>
#> X column ASSAULT_RATE_2024
#> Y column HOMICIDE_RATE_2024
#> Polygons 16
#> k-NN 5
#> Bivariate I_xy 0.04427
#>
#> Bivariate Moran's I_xy between 'ASSAULT_RATE_2024' and 'HOMICIDE_RATE_2024' across 16 polygons (k=5-NN haversine weights): I_xy = +0.044. Positive => high X at i tends to occur near high Y at neighbours j; negative => spatial mismatch between the two attributes.