Land-Use Regression for Air Pollution Exposure
This guide is part of the Environmental Exposure & Risk Surface Modeling section. Land-use regression is the method to reach for when the exposure varies over hundreds of metres rather than tens of kilometres, and a smooth interpolated surface would average away exactly the contrast the study is about.
Concept & Epidemiological Alignment
Land-use regression abandons the geostatistical premise. Instead of assuming nearby places are similar and borrowing strength from neighbouring measurements, it assumes concentration is a function of the built environment surrounding a location — road length within 100 m, industrial land within 500 m, population density within 1 km, elevation, distance to the nearest major road. Those predictors are computed at each monitoring site, a regression is fitted against the measured concentrations, and the fitted model is then evaluated at any location where the predictors can be computed, which is everywhere.
The epidemiological appeal is direct. Traffic-related pollutants — nitrogen dioxide, ultrafine particles, black carbon — fall by half within one to two hundred metres of a busy road. A cohort study of asthma incidence lives or dies on whether the exposure model can distinguish a residence on the corridor from one three streets back. Kriging a regulatory network cannot: the monitors are deliberately sited away from roadsides to measure background, and the fitted covariance smooths over the gradient. Land-use regression can, because the gradient is encoded in the predictors rather than inferred from the measurements.
The trade is severe and must be stated up front. The model is fitted on a small number of sites — 40 to 80 in a typical metropolitan campaign — against dozens or hundreds of candidate predictors generated by crossing a handful of land-use variables with a ladder of buffer radii. That ratio is a recipe for a model that fits its own monitors superbly and predicts poorly a kilometre away. Every serious design decision in this topic exists to manage that one risk.
A second assumption deserves naming: the model is a statistical description of the sampling campaign’s period and place, not a dispersion model. It contains no physics. It will not extrapolate to a source that did not exist during the campaign, it will not respond to a highway rebuilt after the fit, and its coefficients have no meaning outside the range of predictor values that were sampled.
Predictor Families and What Each One Captures
| Predictor family | Typical buffers | Captures | Expected sign | Common failure |
|---|---|---|---|---|
| Road length by class | 25–1000 m | Direct traffic emissions | Positive | Road classes inconsistent between jurisdictions |
| Traffic volume × length | 50–1000 m | Emission intensity, not just presence | Positive | Volume counts missing on minor roads |
| Distance to major road | Point measure | Near-source decay | Negative | Undefined where no major road is within range |
| Land cover: industrial, port | 100–5000 m | Point-source influence | Positive | Class definitions change between raster vintages |
| Land cover: green, water | 100–5000 m | Dilution, absence of sources | Negative | Correlated with rurality, so it proxies everything |
| Population or dwelling density | 100–5000 m | Domestic and area sources | Positive | Near-collinear with road density |
| Elevation, terrain | Point or buffer | Drainage, inversion layers | Context-dependent | Sign varies by basin; do not constrain blindly |
Crossing seven families with six buffer radii yields more than forty candidates before interactions, and a campaign with 50 sites can support perhaps four or five predictors in the final model.
Spatial Data Prerequisites
- Geometry: monitoring sites as points with a stable identifier; a road network with a usable functional class attribute; land-cover raster or polygons; population at block or grid resolution.
- Coordinate reference system: one projected metric system for every layer. Buffer radii are the model, so a buffer computed in degrees invalidates every predictor at once.
- Site count: a usable campaign has at least 40 sites; below 30, the model cannot be validated in a way anyone should believe.
- Site siting: the campaign must sample the range of the predictors, not just the geography. Twenty background sites and two roadside sites cannot estimate a roadside gradient regardless of the total count.
- Vintage alignment: road network, land cover and population must date from the measurement campaign, not from today. A model fitted with current land cover against a 2015 campaign attributes concentrations to development that had not happened.
- Predictor completeness: every predictor must be computable at every prediction location. A distance-to-port predictor is undefined for most of a state and cannot enter a state-wide model.
Production Implementation
The routine below builds the buffer predictors, then runs supervised forward selection with two constraints that separate a defensible land-use regression from a data-dredging exercise: an expected sign for each predictor family, and a rule that only one buffer from each family may enter.
# Land-use regression: buffer predictors + supervised selection with sign constraints.
# Pinned: geopandas==0.14.4, numpy==1.26.4, pandas==2.2.2, scikit-learn==1.5.0
import logging
import re
import numpy as np
import pandas as pd
import geopandas as gpd
from sklearn.linear_model import LinearRegression
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("exposure.lur")
BUFFERS_M = (25, 50, 100, 300, 1000, 3000)
# Direction each family must take; a candidate with the wrong sign is rejected
# outright rather than accepted because it improved the fit.
EXPECTED_SIGN = {"road": +1, "traffic": +1, "industrial": +1, "port": +1,
"popdens": +1, "green": -1, "water": -1, "dist_major": -1}
MAX_VIF = 3.0
MIN_R2_GAIN = 0.01
def build_buffer_predictors(sites: gpd.GeoDataFrame, roads: gpd.GeoDataFrame,
landcover: gpd.GeoDataFrame,
buffers=BUFFERS_M) -> pd.DataFrame:
"""Road length and land-cover area within each buffer, per site."""
if sites.crs.is_geographic:
raise ValueError("project to metres — buffer radii are the model")
sites = sites.sort_values("site_id").reset_index(drop=True)
cols = {"site_id": sites["site_id"].to_numpy()}
for r in buffers:
ring = sites.copy()
ring["geometry"] = ring.geometry.buffer(r)
seg = gpd.overlay(roads[["fclass", "geometry"]], ring[["site_id", "geometry"]],
how="intersection", keep_geom_type=False)
seg["m"] = seg.geometry.length
major = seg[seg["fclass"].isin(("motorway", "trunk", "primary"))]
cols[f"road_major_{r}"] = (major.groupby("site_id")["m"].sum()
.reindex(sites["site_id"]).fillna(0.0).to_numpy())
cols[f"road_all_{r}"] = (seg.groupby("site_id")["m"].sum()
.reindex(sites["site_id"]).fillna(0.0).to_numpy())
lc = gpd.overlay(landcover[["class", "geometry"]], ring[["site_id", "geometry"]],
how="intersection", keep_geom_type=False)
lc["a"] = lc.geometry.area
for cls, name in (("industrial", "industrial"), ("forest", "green")):
cols[f"{name}_{r}"] = (lc[lc["class"] == cls].groupby("site_id")["a"].sum()
.reindex(sites["site_id"]).fillna(0.0).to_numpy())
log.info("built %d candidate predictors for %d sites", len(cols) - 1, len(sites))
return pd.DataFrame(cols)
def _family(name: str) -> str:
return re.sub(r"_\d+$", "", name)
def _vif(X: np.ndarray, j: int) -> float:
others = np.delete(X, j, axis=1)
if others.shape[1] == 0:
return 1.0
m = LinearRegression().fit(others, X[:, j])
r2 = m.score(others, X[:, j])
return 1.0 / max(1e-9, 1.0 - r2)
def supervised_forward_selection(X: pd.DataFrame, y: np.ndarray,
max_terms: int | None = None) -> list[str]:
"""Add predictors one at a time, honouring sign, family and collinearity rules."""
n = len(y)
cap = max_terms or max(1, n // 10) # one term per ten sites, hard ceiling
chosen, used_families, r2 = [], set(), 0.0
while len(chosen) < cap:
best = None
for col in X.columns:
fam = _family(col)
if col in chosen or fam in used_families:
continue
trial = chosen + [col]
M = X[trial].to_numpy(float)
fit = LinearRegression().fit(M, y)
want = EXPECTED_SIGN.get(fam)
if want is not None and np.sign(fit.coef_[-1]) != want:
continue # wrong direction: reject, do not keep
if _vif(M, M.shape[1] - 1) > MAX_VIF:
continue
gain = fit.score(M, y) - r2
if gain > MIN_R2_GAIN and (best is None or gain > best[1]):
best = (col, gain, fit.score(M, y))
if best is None:
break
chosen.append(best[0])
used_families.add(_family(best[0]))
r2 = best[2]
log.info("selected %-22s cumulative_r2=%.3f terms=%d", best[0], r2, len(chosen))
log.info("final model: %s", " + ".join(chosen) or "(intercept only)")
return chosen
The three guards in that loop do most of the work. The sign constraint refuses a predictor whose fitted direction contradicts physical reasoning — a negative coefficient on major road length within 100 m is not a discovery, it is collinearity producing a nonsense partial effect, and accepting it because the fit improved is how untransferable models are built. The one-buffer-per-family rule stops a correlated ladder from entering multiple times. The term cap of one predictor per ten sites is blunt and effective; a 50-site campaign gets at most five terms no matter how good the candidates look.
Parameter Selection & Tuning
The buffer ladder should span the physical scales that matter: tens of metres for near-road, hundreds for neighbourhood sources, kilometres for regional background. Adding more rungs does not add information — adjacent buffers correlate above 0.9 — and does inflate the selection search.
The term cap is the single most effective defence against overfitting. One term per ten sites is a common convention. Treat it as a hard ceiling, not a target: a three-term model that validates is better than a five-term model that does not.
The minimum gain threshold stops the procedure from adding terms that improve the fit by rounding error. One per cent of explained variance is a reasonable floor; the exact value matters less than declaring it before the run.
Collinearity tolerance. A variance inflation factor above about 3 means the new predictor is largely a linear combination of those already in the model, and its coefficient is unstable. Some published models tolerate 5 or 10; the higher the tolerance, the less transferable the result.
Transformations. Traffic-related concentrations are often closer to linear in the square root or logarithm of road length than in the raw metre count. Fix the transformation from the physical reasoning before selection, and apply it uniformly across the family — choosing a transformation per predictor by fit is another route to overfitting.
Edge Cases & Failure Modes
A campaign that samples geography rather than predictor range. If the sites span the metropolitan area evenly but only two sit within 50 m of a major road, the near-road coefficient is estimated from two observations, and its confidence interval will span zero even as the model reports a good overall fit. Design or subset the campaign around the predictor distribution.
Predictors undefined at prediction locations. A distance-to-port term fitted on a coastal campaign has no value inland. Every predictor must be computable everywhere the surface will be evaluated, or the surface has holes that get filled with an implicit extrapolation.
Extrapolation past the sampled range. A model fitted where road length within 100 m never exceeded 800 m will happily predict for a location with 3000 m, and the prediction is pure linear extrapolation. Flag prediction locations that fall outside the training hull of every predictor and treat them as unmodelled.
Vintage drift. Applying a model fitted on a 2016 campaign to 2024 land cover changes the predictor values without changing the coefficients, silently assuming the emission-per-unit-road relationship has not moved. Fleet turnover alone has cut roadside nitrogen dioxide substantially over such a period.
Spatial autocorrelation in the residuals. If the model residuals cluster in space, a systematic source is missing and the standard errors are too small. Test them with the diagnostics in Diagnosing Spatial Autocorrelation in Regression Residuals, and consider adding a kriged residual layer rather than chasing another predictor.
The training hull is the control that stops those extrapolation failures from reaching a published surface, and it is simple to picture:
Compliance & Audit Controls
A land-use regression is a published claim about a place at a time, so its record must let someone rebuild it. Store the campaign dataset and measurement period; the road, land-cover and population sources with vintages; the full candidate list and the buffer ladder; the selection rules including expected signs, family rule, term cap, gain threshold and collinearity tolerance; the selected terms with coefficients and standard errors; the held-out validation statistics; and the training hull of each predictor so extrapolation can be detected later.
Determinism requires a stable site sort and a fixed candidate column order, because forward selection with near-ties is sensitive to ordering. Where the selection is bootstrapped, seed it. The model itself contains no protected data and should be published; the exposure values it generates at residences do, and enter the controls described in the parent section.
Production Implementation Checklist
Frequently Asked Questions
How many monitoring sites do I need? Forty is a working minimum for a metropolitan model and sixty is comfortable. What matters more than the raw count is coverage of the predictor range: a campaign of eighty sites that all sit in background locations cannot estimate a near-road gradient, while forty sites deliberately spread across the road-density distribution can.
Can I use a published model from another city? Only with local validation. Land-use regression coefficients encode a specific fleet, road classification and land-cover taxonomy, and they transfer poorly across those boundaries. Measure at a handful of local sites and check the transferred model’s error before adopting it; the procedure is set out in the transfer guide below.
Should I combine land-use regression with kriging? Frequently, yes. Fitting the regression first and then kriging its residuals captures both the street-scale structure the predictors explain and the regional structure they miss. The combination usually validates better than either alone, and it restores a prediction variance the regression does not provide.
Why did my model select an implausible negative coefficient on road length? Collinearity. When two correlated predictors enter together, the partial coefficients can take large offsetting values with meaningless signs. The sign constraint in the selection loop exists precisely to reject those, and a family that keeps producing them is a sign that the candidate set is too correlated for the site count.
How do I know the model will not be used outside its valid range? Store the minimum and maximum of every selected predictor across the training sites, and evaluate that hull at every prediction location. Locations outside it should be flagged in the output rather than shipped as ordinary predictions, because for those the model is extrapolating linearly with nothing to support it.
Related Topics
- Environmental Exposure & Risk Surface Modeling — the parent section and when to prefer regression over interpolation.
- Building Buffer Predictors for a Land-Use Regression Model — the geometry work behind the candidate set, done efficiently.
- Avoiding Overfitting in Land-Use Regression Variable Selection — the selection protocol in depth, including nested validation.
- Interpolating Environmental Exposure Surfaces — the geostatistical alternative, and the residual-kriging hybrid.