Skip to content

Accuracy assessment: stratified sampling and error-adjusted area with CIs (#81) - #90

Merged
NewGraphEnvironment merged 10 commits into
mainfrom
81-accuracy-assessment-for-change-maps-stra
Sep 29, 2026
Merged

NewGraphEnvironment merged 10 commits into
mainfrom
81-accuracy-assessment-for-change-maps-stra

Conversation

@NewGraphEnvironment

Copy link
Copy Markdown
Owner

Summary

Until now drift reported mapped area only. Mapped area is biased wherever the map is wrong, and badly so for change maps. This PR adds the standard remedy (Olofsson et al. 2014; Stehman 2014) as the dft_accuracy_* family:

  • dft_accuracy_sample(strata, n, seed, map =) draws stratified random points from any strata raster: map classes, a transition map, or caller-defined strata. It records the stratum weights and the map's class at each point.
    • Draws are reproducible without terra::spatSample(). The same seed with a larger n extends the pilot, so pilot labels carry over.
    • A stratum no larger than its allocation is taken whole.
  • dft_accuracy_estimate(labels, strata) wraps mapaccuracy::stehman2014(), which is valid whether or not the strata are the map classes. It returns error-adjusted area in ha with CIs, overall / user's / producer's accuracy, a long error matrix, and a per-stratum table.
  • dft_accuracy_labels() defines the label contract. NA or blank labels (nonresponse) are refused, and so are training rows.
  • dft_accuracy_size() implements Olofsson Eq. 13 plus allocation, sized from a pilot's per-stratum SD.

Related Issues

Test plan

  • Olofsson 2014 Tables 8–9 reproduce through dft_accuracy_estimate() to the published precision, using absolute tolerances. Three printed values contradict the paper's own equations; the tests pin the equation values (helper-accuracy.R).
  • Must-fail: the same labels with equal stratum weights give 200,748 ha of deforestation instead of 21,158.
  • Census oracle, 300 draws against the full bundled tiles:
    • The estimate is unbiased for map-class strata and for changed/stable strata.
    • Coverage is 0.91–0.96 for changed/stable at n = 60, and 0.89–0.95 for map-class strata at n = 150.
    • At n = 25, Water's interval covers only 61%: a rare class hiding in a large stratum. This is documented on the estimator.
  • Sampler guarantees:
    • a pinned golden draw
    • chunk invariance (1, 7, 50 and full rows), with an exact brute-force check
    • pilot extension, including a stratum tipped into a census
    • RNG state restored: existing seed, absent seed, and L'Ecuyer
  • Code-check, three rounds (12 findings, 5 of them bugs). Twice a defect sat inside the previous round's fix, and all shared one mechanism: an identity derived separately at each site. The loop ended by enumerating all 29 identity sites and routing each through one accuracy_key(); every fix was mutation-checked.
  • Suites: devtools::test() gives 1289 pass / 15 skip. R CMD check gives 0 errors, 1 NOTE (future timestamps) and 1 WARNING: non-ASCII in R/dft_stac_fetch.R, which is already on main and untouched by this PR.
  • All new @examples run, and pkgdown::check_pkgdown() is clean.

Scale test (BULK floodplain, per CLAUDE.md)

classified_2017.tif is 14651 × 11552 = 169,248,352 cells, of which 4,108,972 hold data. Run on a 64 GB machine, with RSS sampled every 1–2 s:

step time peak RSS
one chunked pass 1.7 s
dft_accuracy_sample(r17, n = 100) (2 passes + draw) 3.3 s 0.95 GiB (0.27 GiB after load)
classify 2017+2023, then dft_rast_transition(), then sample the 63-stratum factor map (n = 30, 10 censuses) 1.5 + 3.4 + 3.0 s 4.63 GiB, dominated by the in-memory transition raster
dft_accuracy_estimate() on 1,677 points, 63 classes 10.8 s

The estimator's run time grows with roughly the 2.5th power of the class count (13 s at 80 classes and 1,000 points). That comes from stehman2014()'s class² indicator columns. It is documented and not filed upstream.

Notes

  • Scope decisions, recorded in the Accuracy assessment for change maps: stratified sampling and error-adjusted area with CIs (Olofsson et al. 2014) #81 body:
    • Strata may differ from the map classes, so the Stehman form is used.
    • The estimator wraps mapaccuracy rather than reimplementing it (a user decision).
    • A train/test split helper is not included; the estimator refuses training rows instead, which is the issue's stated minimum.
  • planning/archive/2026-09-issue-81-accuracy-assessment/ holds the plan review, the three code-check rounds and the measurement record.
  • The version is bumped to 0.19.0 in ce56768. One doc-only commit follows it: 0a360bb qualifies bare #93 references in the archive.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN

NewGraphEnvironment and others added 10 commits September 28, 2026 18:10
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Two blockers. freq() and readValues() disagree on factor strata (confirmed
by probe). Sizing assumed strata equal map classes. Also: per-stratum
seeds so a pilot extends, a census for tiny strata under an fpc argument,
map extraction at sampled cells, and a census oracle that needs no PDFs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
The user chose to import mapaccuracy (CRAN, stats-only) over a second
implementation. drift keeps the contract, CIs in ha, the tidy matrix and
the per-stratum table the sizer needs. The FPC argument goes: the package
always applies it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Tables 8-9, section 5.1.1 and 5.2, with page and table cited. Two PA
half-widths and one area SE are printed inconsistently with the paper's
own equations; the equation values are kept and the printed ones recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
dft_accuracy_sample() draws stratified random points from any strata
raster in two chunked passes, with per-stratum seeded streams, so a
larger n extends a pilot and draws do not depend on terra's sampler.
dft_accuracy_estimate() wraps mapaccuracy::stehman2014() (strata may
differ from the map classes) and adds CIs in ha, a long matrix and a
per-stratum table. dft_accuracy_labels() is the label contract and
dft_accuracy_size() is Olofsson Eq. 13 plus allocation.

Tests reproduce Olofsson et al. 2014 Tables 8-9, check against a census
of the bundled tiles, and pin a golden draw. Three code-check rounds,
the last ended by enumerating every identity site.

Relates to NewGraphEnvironment/sred#16

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
@NewGraphEnvironment
NewGraphEnvironment merged commit fe2f4a8 into main Sep 29, 2026
1 check passed
@NewGraphEnvironment
NewGraphEnvironment deleted the 81-accuracy-assessment-for-change-maps-stra branch September 29, 2026 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Accuracy assessment for change maps: stratified sampling and error-adjusted area with CIs (Olofsson et al. 2014)

1 participant