Moran's I vs Geary's C: Which to Use

TL;DR: Use esda.moran.Moran(y, w) for Moran’s I when you want a single, correlation-like summary of global spatial covariation, and esda.geary.Geary(y, w) for Geary’s C when you care about local, short-range differences between neighbours. The two are inversely related: high Moran’s I means low Geary’s C. Compute both on the same row-standardized weights, report Moran’s I as the headline, and reach for Geary’s C when fine-scale contrast matters.

Why This Matters

Both statistics answer the same broad question — is my variable spatially autocorrelated? — but they weight the evidence differently, and choosing the wrong one can hide the pattern you most need to see. Moran’s I measures how attribute values co-vary around the global mean, so it is tuned to broad, contiguous patterns. Geary’s C measures the squared difference between neighbouring values, so it is tuned to abrupt local transitions. Getting this choice right is fundamental to the spatial autocorrelation metrics you rely on before regression or interpolation, and it sits at the heart of the broader Core Concepts of Spatial Statistics & Geostatistics toolkit. Report a single number without understanding its bias and you may conclude “no structure” when short-range clustering is present, or vice versa.

Both indices are built from the same ingredients: an attribute vector and a spatial weight matrix wijw_{ij}. The difference is entirely in the numerator.

Moran’s I compares each value’s deviation from the mean with its neighbours’ deviations:

I=nijwijijwij(xixˉ)(xjxˉ)i(xixˉ)2I = \frac{n}{\sum_i \sum_j w_{ij}} \cdot \frac{\sum_i \sum_j w_{ij}(x_i - \bar{x})(x_j - \bar{x})}{\sum_i (x_i - \bar{x})^2}

Geary’s C instead sums the squared differences between neighbouring pairs:

C=(n1)2ijwijijwij(xixj)2i(xixˉ)2C = \frac{(n-1)}{2 \sum_i \sum_j w_{ij}} \cdot \frac{\sum_i \sum_j w_{ij}(x_i - x_j)^2}{\sum_i (x_i - \bar{x})^2}

The cross-product (xixˉ)(xjxˉ)(x_i - \bar{x})(x_j - \bar{x}) in Moran’s I is a global device: every pair is judged against the overall mean, so smooth broad gradients register strongly. The squared difference (xixj)2(x_i - x_j)^2 in Geary’s C is local: it never references the global mean, so it responds to how sharply adjacent values differ, regardless of where they sit relative to the average.

What Each Statistic Measures

Property Moran’s I Geary’s C
Core quantity Cross-product of mean deviations Squared difference of neighbour pairs
Sensitivity Broad, global covariation Local, short-range differences
Expected value (randomness) 1/(n1)-1/(n-1) (≈ 0 for large nn) 11
Typical range [1,1]\approx [-1, 1] (row-standardized) [0,2][0, \approx 2]
Positive autocorrelation I>E[I]I > E[I] (toward +1+1) C<1C < 1 (toward 00)
Negative autocorrelation I<E[I]I < E[I] (toward 1-1) C>1C > 1 (toward 22)
Interpretation scale Correlation-like, intuitive Distance-like, less intuitive
Driven most by Regional trends, large clusters Local outliers, sharp edges

The single most important fact is the inverse relationship: positive spatial autocorrelation pushes Moran’s I up toward +1+1 and Geary’s C down toward 00. They are not identical rescalings of one another, though — Moran’s I is a global product-moment measure while Geary’s C is a local sum-of-squares measure, so they can rank two datasets differently when autocorrelation is concentrated at short lags.

Choosing between Moran's I and Geary's C A decision guide: broad regional patterns and a need for an interpretable headline favour Moran's I; short-range local differences and local outlier sensitivity favour Geary's C; reporting both is recommended when in doubt. What scale is the pattern? deciding which index to trust broad / regional local / short-range Moran's I global covariation interpretable headline number high I when clusters are large Geary's C squared neighbour differences sensitive to local outliers low C when edges are sharp Unsure? Report both agreement strengthens the conclusion

Environment and Version Pinning

Both statistics live in esda, and both consume a libpysal weights object built from a geopandas GeoDataFrame. No extra dependencies are required.

bash
pip install "geopandas>=1.0" "libpysal>=4.9.0" "esda>=2.5.0" "numpy>=1.23" "scipy>=1.9"
python
import geopandas as gpd
import numpy as np
import libpysal
from esda.moran import Moran
from esda.geary import Geary
from shapely.geometry import box

Computing Both Side by Side

The most reliable way to choose is to run both diagnostics on identical data and weights, then compare what they say. Because they share the same denominator (total variance) and the same weights, any divergence is attributable to the numerator — global covariation versus local differencing.

Build a shared dataset and weights matrix

python
# Synthetic 10x10 grid with a smooth diagonal gradient plus noise —
# this produces genuine positive spatial autocorrelation.
cells = [box(x, y, x + 1, y + 1) for y in range(10) for x in range(10)]
gdf = gpd.GeoDataFrame(geometry=cells, crs="EPSG:32618").reset_index(drop=True)

rng = np.random.default_rng(7)
cx = gdf.geometry.centroid.x.values
cy = gdf.geometry.centroid.y.values
gdf["pm25"] = 8.0 + 0.6 * (cx + cy) + rng.normal(0, 1.5, size=len(gdf))

w = libpysal.weights.Queen.from_dataframe(gdf)
w.transform = "R"          # row-standardize once, use for both statistics
y = gdf["pm25"].values

Run Moran’s I and Geary’s C on the same inputs

python
mi = Moran(y, w, permutations=999)
gc = Geary(y, w, permutations=999)

print(f"Moran's I : {mi.I:.4f}  (E[I] = {mi.EI:.4f}, p_sim = {mi.p_sim:.4f})")
print(f"Geary's C : {gc.C:.4f}  (E[C] = {gc.EC:.4f}, p_sim = {gc.p_sim:.4f})")

Typical output for this construction:

text
Moran's I : 0.6203  (E[I] = -0.0101, p_sim = 0.0010)
Geary's C : 0.3915  (E[C] = 1.0000, p_sim = 0.0010)

Interpreting the Output

Read the two numbers together. mi.I of about 0.62 sits well above its expected value of roughly 0 and confirms strong positive global autocorrelation. gc.C of about 0.39 sits well below its expected value of 1.0, confirming the same positive autocorrelation from the local-difference angle. The pseudo p-values (p_sim) from permutation inference are both significant, so the pattern is not an artefact of randomness.

The direction always agrees under the inverse relationship: II up, CC down for positive autocorrelation. What you learn from running both is the shape of the dependence. When Moran’s I is high but Geary’s C is only mildly below 1, the structure is a broad smooth gradient. When Geary’s C is very low (near 0) while Moran’s I is only moderate, neighbours are nearly identical at short range — a sign of fine-scale clumping or duplicated measurements that the global index dilutes.

gc.EC is always exactly 1.0 because that is the theoretical expectation under spatial randomness, independent of nn. mi.EI is -1/(n-1), which for n=100n = 100 is about -0.0101. Comparing each statistic to its own expected value — not to zero, and not to each other’s scale — is the correct significance check.

Critical Best Practices

Anchor each statistic to its own expected value

The rookie error is treating 1.0 as neutral for Moran’s I or 0 as neutral for Geary’s C. Neutral for Moran’s I is 1/(n1)-1/(n-1); neutral for Geary’s C is exactly 1. Always compare mi.I against mi.EI and gc.C against gc.EC, and lean on the permutation p_sim rather than eyeballing the raw value.

Use identical, row-standardized weights for a fair comparison

If you build one weights object for Moran and a different one for Geary, any divergence is confounded by the weights, not the statistics. Construct w once, set w.transform = "R", and pass the same object to both. Row-standardization keeps both indices on their conventional scales and prevents high-degree units from dominating.

Prefer Geary’s C when local outliers matter

Because Geary’s C squares neighbour differences, it is disproportionately sensitive to a handful of sharp local contrasts — exactly the situation where a global mean-referenced index like Moran’s I washes the signal out. For edge detection, boundary analysis, or spotting isolated anomalies, Geary’s C is the more responsive diagnostic.

Report Moran’s I as the default headline

Moran’s I is more widely recognised, sits on an intuitive correlation-like scale, and is directly comparable across studies and datasets. Unless your question is specifically about short-range contrast, lead with Moran’s I and cite Geary’s C as corroboration. When both point the same way, the conclusion is robust.

Escalate to local statistics when the global answer hides heterogeneity

Neither global index tells you where the autocorrelation lives. If the global result is significant, decompose it with local indicators — see Computing Local Moran’s I (LISA) in Python to map high-high clusters, low-low clusters, and spatial outliers unit by unit.

Troubleshooting

Symptom Likely cause Fix
Geary’s C above 2 or below 0 Non-standardized binary weights Set w.transform = "R" before computing
mi.I and gc.C both suggest “no pattern” but a map shows clumping Weights too coarse to capture the scale Rebuild w with a shorter distance band or KNN with smaller k
Moran’s I significant, Geary’s C not (or vice versa) Autocorrelation concentrated at a scale one index favours Report both and describe the scale; consider directional analysis
p_sim exactly 0.001 for both Too few permutations to resolve small p-values Increase to permutations=9999
ValueError on Geary(y, w) with NaN in y Missing attribute values Drop or impute NaN before computing either statistic

Next Steps

With the choice made, run the diagnostic in a full pipeline — see How to Calculate Moran’s I in PySAL for the complete Moran’s I workflow, then decompose a significant global result with Computing Local Moran’s I (LISA) in Python. Both build on the spatial autocorrelation metrics foundations.

Frequently Asked Questions

Do Moran’s I and Geary’s C ever disagree?

They usually agree in direction because they are inversely related: high Moran’s I corresponds to low Geary’s C. Disagreements in strength happen when autocorrelation is concentrated at short range or driven by a few local outliers. Geary’s C reacts more strongly to these local differences, so a moderate Moran’s I paired with a sharply low Geary’s C signals fine-scale structure that the global index averages away.

What are the expected values and ranges of the two statistics?

Moran’s I has expected value 1/(n1)-1/(n-1) under spatial randomness and typically falls near [1,1][-1, 1] with row-standardized weights. Geary’s C has expected value 11 under randomness, ranges from 00 to roughly 22, where values below 11 indicate positive autocorrelation and values above 11 indicate negative autocorrelation or dispersion.

Which should I report by default?

Report Moran’s I as the primary global summary because it is more widely understood, more interpretable on a correlation-like scale, and directly comparable across studies. Add Geary’s C when you suspect short-range differences, local outliers, or process behaviour that the broad covariation of Moran’s I would smooth over.


← Back to Spatial Autocorrelation Metrics

Related