Skip to contents

Generalises 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"
)

Arguments

polygons

An sf object, or a data.frame with centroid columns.

x_col, y_col

The two attributes (column names).

ds_name

Tag for the result title.

k_neighbours

k for the k-NN weights graph.

centroid_lat_col, centroid_lon_col

Names of centroid columns when polygons is a plain data.frame.

Value

A named list with I_xy, n, x_col, y_col.

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.