DEMO LAB LOADING
Small-area estimation

Poverty mapping
from space

BPS publishes a poverty rate for 514 kabupaten and kota, once a year. Below that line nothing official exists. But the signal is overhead: how many roofs, how big they are, how bright the night, how much of the ground is built. This case learns the relationship against every official rate from 2016 to 2025, tests it on provinces the model has never seen, publishes the result whichever way it falls, and then carries it down to the kecamatan — distributing the official number, never replacing it.

PREPARING THE REVEAL…

01

The official map, and its resolution

Every number this case is judged against comes from one place: the March Susenas, published by BPS as a poverty headcount for each of 514 regencies and cities. It is authoritative, it is annual, and it is the coarsest unit at which Indonesian poverty is publicly measured — a single rate for territories that run from 4 km² to 44,000 km².

The national headcount, 2016–2025

Population-weighted mean of the 514 published regency rates, and the band between the 10th and 90th percentile regency.

514 regencies, one year

Every regency in the latest release, sorted. Hover for the name and rate; the spread is the reason a national average tells a client almost nothing.

So what.

02

How well it predicts — before anything else

A poverty map that has not been validated out of sample is a picture, not an estimate. So the trust chapter comes first. The model never sees the province it is scored on: 38 folds, one per province, every year of a held-out province removed from training. The random k-fold on the same rows is computed too — not as a result, but to show how much a non-spatial fold flatters a model whose neighbours look alike.

Model against official, held-out

One dot per regency in the latest release. The diagonal is perfect agreement.

What a random fold buys you

The same model and the same rows, scored under four fold designs. The gap between the top bar and the bottom one is the cost of honesty — and the size of the error a client would inherit.

Sees forward, not just sideways

Trained on 2016–2023, then asked for releases it has never seen. Plotted against the strict version, where the regency's whole province is held out too — otherwise the model can simply remember the level it learned from that regency's earlier years.

So what.

03

What the model actually looks at

Gradient boosting is not a black box if you open it. These are the feature families ranked by how much they move a prediction, and below them any regency you pick, read back in plain words.

Feature families

Mean absolute contribution to a regency's predicted poverty rate.

Read one regency back

The five signals that moved this regency furthest from the national average, and which way.

So what.

04

Below the survey line

The payoff, and the part that needs the most care. The regency model is applied to kecamatan features built by the same code, then every kecamatan in a regency is rescaled by one factor so the population-weighted mean reproduces the official rate exactly. The model decides only how the official number is distributed inside its regency.

Inside one regency

Each kecamatan with its interval; the teal line is the official regency rate the estimates are benchmarked to.

The contrasts we can defend

Pairs of kecamatan inside a single regency whose intervals do not overlap — the sharpest statement this model is entitled to make.

So what.

05

Explore

Official rates at the regency, model estimates at the kecamatan. Click any unit for its panel. The URL carries the view, so a link reopens it.

2025
06

Method, limits and provenance

Everything a reviewer needs to disagree with us.

What is measured, and what is estimated

The target is the BPS poverty headcount P0 — the share of people below the official provincial poverty line — never "wealth", never consumption. Susenas and DHS microdata are restricted, so the model is trained at the level BPS publishes and carried down from there.

A regency number on this page is official. A kecamatan number is a model estimate with an interval, and the words and the colour differ wherever they appear: official series in teal, model estimates in ochre.

Benchmarking

For every regency and year, kecamatan predictions are multiplied by one factor so that the population-weighted mean equals the published rate. Units pinned at 0 or 100 % hand their residual back to the units still free, so the identity holds exactly. The reproducibility check recomputes it from the shipped file.

Cross-validation

Leave-one-province-out, 38 folds. A held-out province leaves the training set in every year, so no temporal copy of a test regency can leak back in. A 200 km block scheme is reported as a spatial sensitivity, and a random k-fold purely to quantify its optimism.

Known limits

    Administrative-code reconciliation

    Sources and vintages

    LayerVintageLicence
    BPS WebAPI — P0/P1/P2 and the poverty line, per kabupaten/kota2016–2025, March SusenasFree key · cite BPS
    Google Open Buildings v3 — footprints, confidence ≥ 0.70files dated 2023-06CC BY 4.0 (dual-licensed; CC BY elected)
    NASA Black Marble VNP46A4 / VJ146A4 annual radiance2012–2025, reused from the nighttime-lights caseOpen (NASA) · Román et al. 2018
    WorldPop R2025A constrained 100 m population2016–2025CC BY 4.0
    ESA WorldCover v200 land cover, 10 m2021 (no later vintage exists)CC BY 4.0
    HDX COD-AB administrative boundaries (BPS-derived)2020-04CC BY-IGO

    © ESA WorldCover project 2021 / Contains modified Copernicus Sentinel data (2021) processed by the ESA WorldCover consortium.

    Scouted and rejected

    Meta Relative Wealth Index and the SMERU 2015 poverty map are CC BY-NC and are not used, which removed the planned independent wealth cross-check; the temporal hold-out replaces it. BPS Podes microdata is behind registration and a fee. Satellite embedding sets (Tessera, Major TOM) and Open Buildings 2.5D Temporal are deferred on licence or size grounds.

    Not in this build

    GHSL built-up surface, OSM road density and Sentinel-2 spectral indices are specified but not ingested in this pass; each is additive and none of them blocks the roof / lights / population / land-cover families the model runs on.

    Reproduce it

    cd cases/poverty-map
    uv sync
    make rebuild        # ingest → features → train → downscale → validate → export
    make validate       # all four published checks → data/stats.json
    SCOPE=java make rebuild   # the ~11 GB fast path

    Every raw input is deleted as soon as it has been reduced to per-kecamatan aggregates, so about 16 GB flows through a 48 GB disk that never holds more than a couple of gigabytes of it. The run is resumable: each completed unit is appended to a ledger and a rerun skips it.

    Files this case publishes

      07

      We had this case reviewed, adversarially.

      An independent read of the same data against the published literature. It tests the defence this page used to give for its failing skill check — that the target is a nominal poverty line no satellite can see — by handing the model that line and by re-targeting it onto the line itself. Neither test supports the defence, and the explanation that replaces it is a better one. It also finds that night lights and population alone score higher than all thirty-one features, and reports what the benchmarked disaggregation is really worth.

      Read the review article →