Detecting Invasive Plants from Space · Part 3 of 3
Iterating with Intent
May 2025
In Part 2, I diagnosed why the first version of the pipeline missed three out of four invasive sites. Not because phenology detection doesn't work — but because three distinct failure modes were at play: threshold design, rule coverage, and ground-truth sampling.
The value of that diagnosis is that each failure mode points to a different kind of fix. In this part, I'll describe the two changes I made, and the one I didn't.
Two New Rules
The diagnosis suggested two targeted additions to the classifier:
Rule 1 — summer-vs-control: Flag a site if its summer NDVI is more than 0.08 above the native control, regardless of absolute value. This addresses the Dyke Marsh failure directly — the original rule checked whether summer NDVI exceeded 0.85, a threshold calibrated for kudzu's explosive growth. Phragmites doesn't reach that height, but a +0.10 relative elevation above the control is still meaningful. The new rule catches it.
Rule 2 — composite signal: Flag a site if the sum of its seasonal deltas (each season vs. the control) is at least 0.15, and all four deltas are positive. This addresses the Scotts Run failure. English ivy doesn't shout in any single season — it whispers consistently across all four. Scotts Run's seasonal deltas sum to +0.288, with all four positive. That pattern is now detectable.
Neither rule required tuning a free parameter until it fit the data. Each was derived directly from the failure diagnosis. That's the distinction between iterating with intent and iterating by trial and error.
v1.1 Results
| Site | v1 | v1.1 |
|---|---|---|
| Huntley Meadows (Phragmites) | ✓ | ✓ |
| Scotts Run (English ivy) | ✗ | ✓ composite signal |
| Dyke Marsh (Phragmites) | ✗ | ✓ summer vs. control |
| Great Falls (Kudzu) | ✗ | — (intentional) |
| Manassas Battlefield (native) | ✓ correct | ✓ correct |
Detection rate: 1 out of 5 → 3 out of 5, with no parameter tuning and no change to the underlying data.
The Intentional Miss
Great Falls is still undetected in v1.1, and I left it that way on purpose.
The failure at Great Falls was a sampling error: the site coordinate was on the rocky overlook above the river, not on a kudzu patch. Shrinking the sampling buffer made things worse because it concentrated the sample over bare rock and open water. No rule change, threshold adjustment, or additional Sentinel-2 feature would fix this — the satellite is faithfully reporting what it sees, and what it sees is the wrong location.
The correct fix is field knowledge: go to the site, find where the kudzu actually grows, and update the coordinate. That's not an algorithm problem. Adding more rules to the classifier would be addressing the wrong layer of the system.
Knowing when not to iterate on the model is, I think, one of the harder things to learn in this kind of work.
What I Took Away
A wrong classification is a feature, not a bug — if you bother to diagnose it carefully.
The three failure modes I identified — threshold strictness, rule coverage, and ground-truth accuracy — are orthogonal. They operate at different layers of the system and require different kinds of fixes. Conflating them, or treating all misses as evidence that the method doesn't work, destroys the information the failures contain. Separating them tells you exactly what to do next.
The broader pattern matters too: none of this required labeled training data, no ML model, no GPU. It required thinking carefully about why the signal should exist, writing rules that could catch it, and then reading the failures honestly. That's the part of remote sensing that no satellite upgrade makes easier.
Wenxuan Tang · DC area · Interactive dashboard