Corrélogramme spatial
Le I de Moran à des ordres de voisinage croissants, avec une enveloppe de permutation — jusqu'où porte le regroupement spatial.

Le I de Moran calculé avec les voisins d'ordre 1 mesure le regroupement à la plus courte portée. Un corrélogramme spatial répète le calcul pour les voisins d'ordre 2 (voisins de voisins, sans les plus proches), 3, et ainsi de suite. La courbe montre l'échelle spatiale d'un phénomène : à combien d'étapes deux zones peuvent-elles encore se ressembler, et les zones éloignées deviennent-elles opposées — I négatif — comme lorsqu'un pays se partage en deux grandes régions ? C'est l'équivalent spatial de la fonction d'autocorrélation d'une série chronologique.
La bande grise est l'intervalle à 95 % de I sous l'hypothèse d'aléa spatial, tiré de 999 permutations à chaque ordre ; les points hors de la bande sont peu probables en l'absence de structure spatiale. Deux variables des statistiques morales de Guerry (1833) pour 85 départements sont comparées : l'alphabétisation, et la population par crime contre les personnes (plus elle est élevée, moins il y a de crimes). Les pondérations sont des contiguïtés de type reine d'ordre supérieur, tirées de libpysal.weights.higher_order et standardisées par ligne ; I vient de esda.Moran.
Le code et le texte à l'intérieur des figures sont en anglais.
import geopandas as gpd
import matplotlib.pyplot as plt
import numpy as np
from esda.moran import Moran
from libpysal import examples, weights
# Data: 85 French départements, c. 1830 (Guerry, 1833)
g = gpd.read_file(examples.load_example("Guerry").get_path("guerry.shp"))
variables = {"Litercy": ("Literacy", "#007AFF"),
"Crm_prs": ("Population per crime against persons", "#FF9500")}
w1 = weights.Queen.from_dataframe(g, use_index=False)
orders = range(1, 7)
res = {v: [] for v in variables}
for k in orders:
wk = weights.higher_order(w1, k, silence_warnings=True) # exactly k steps away
wk.transform = "r"
for v in variables:
m = Moran(g[v].to_numpy(dtype=float), wk, permutations=999)
res[v].append((m.I, *np.percentile(m.sim, [2.5, 97.5]), m.p_sim))
fig, ax = plt.subplots(figsize=(8, 5))
env = np.array(res["Litercy"])[:, 1:3] # envelope (similar for both variables)
ax.fill_between(orders, env[:, 0], env[:, 1], color="#E5E5EA", lw=0, label="95% under randomness")
ax.axhline(0, color="#8E8E93", lw=1)
for v, (name, c) in variables.items():
a = np.array(res[v])
ax.plot(orders, a[:, 0], color=c, lw=2.2, marker="o", label=name)
out = (a[:, 0] < a[:, 1]) | (a[:, 0] > a[:, 2])
ax.scatter(np.array(orders)[out], a[out, 0], s=90, facecolor="none", edgecolor=c, lw=1.5, zorder=4)
ax.set_xticks(list(orders))
ax.set_xlabel("Neighbour order (1 = shares a border, 2 = neighbour of a neighbour, …)")
ax.set_ylabel("Moran's I")
ax.grid(axis="x")
ax.legend(loc="upper right")
lit = np.array(res["Litercy"])
reach = max(k for k, (I, lo, hi, p) in zip(orders, lit) if I > hi)
ax.set_title(f"Literacy clusters up to {reach} steps away; distant départements become opposites", pad=26)
ax.text(0, 1.02, "Circled: outside the 95% permutation envelope · 999 permutations per order · "
f"queen contiguity · n = {w1.n} départements, Guerry (1833)",
transform=ax.transAxes, fontsize=9.5, color="#6E6E73")
plt.show()
Les figures utilisent le style PyStatlas (facultatif) : ajoutez plt.style.use("pystatlas.mplstyle") pour obtenir exactement le même rendu.
Source des données
- Guerry's moral statistics of France, c. 1830 (85 départements). Guerry, A.-M. (1833). Essai sur la statistique morale de la France. Crochard. Data as compiled in Friendly, M. (2007). A.-M. Guerry's moral statistics of France: Challenges for multivariable spatial analysis. Statistical Science, 22(3), 368–399. https://doi.org/10.1214/07-STS241
Prepared by the Center for Spatial Data Science (University of Chicago) from the R package Guerry (Friendly and Dray), provided “as is”. Fetched once and cached by libpysal (examples.load_example("Guerry")). Variables come from Guerry's tables as translated by Whitt and Reinking (2002).
Les exemples illustrent des méthodes statistiques. Leurs titres décrivent ce que chaque figure montre dans ces données précises — souvent un échantillon restreint, daté ou partiel —, et non la position de l'auteur sur la question de fond. Pour l'interprétation, le contexte et la qualité des données, reportez-vous aux sources originales citées ici.
Comment citer
PyStatlas est créé et maintenu par Thierry Warin. S'il vous a été utile dans vos travaux, merci de le citer.
Warin, T. (2026). Spatial correlogram. In PyStatlas: A Python Gallery of Statistical Graphics for the Social Sciences. https://warint.github.io/pystatlas/spatial-data/spatial-correlogram/
@misc{warin2026statlas,
author = {Warin, Thierry},
title = {PyStatlas: A Python Gallery of Statistical Graphics for the Social Sciences},
year = {2026},
howpublished = {\url{https://warint.github.io/pystatlas/}},
note = {Source code: https://github.com/warint/pystatlas}
}Plus dans Données spatiales
Carte choroplèthe avec pondérations spatiales
Une carte d'une variable avec, par-dessus, le réseau des voisins — la structure sur laquelle repose toute statistique spatiale.
spdep::poly2nb() + plot(nb, coords)Diagramme de Moran (autocorrélation globale)
Chaque zone face à la moyenne de ses voisines, avec le I de Moran, son test par permutation et la distribution de référence.
spdep::moran.plot() + spdep::moran.mc()Carte des regroupements LISA (autocorrélation locale)
Où se trouvent les regroupements et les valeurs atypiques spatiales — I de Moran local pour chaque zone, cartographié avec sa significativité par permutation.
spdep::localmoran_perm() / rgeoda::local_moran()