You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
guidance(#312): coarsening a coverage fraction is a mean over children, not MAX (#350)
Features whose native H3 resolution is coarser than the layer they are
overlaid on (ACE/plant-richness at res-8, connectivity at res-9, against
the res-10 conserved layer) were over-counted by every shipping model
except glm-5.2: they coarsened the conserved weight with MAX over the
res-10 children, scoring a whole parent cell as conserved whenever one
child was.
The guide documented MAX only for the reduction *within* a cell (across
overlapping units), which is correct, and said nothing about the second
reduction *across child cells* when changing resolution. One keyword,
two operations.
Adds a gated subsection to Problem 3 stating both reductions in order,
with the child-count divisor spelled out (7 per resolution step, 49 for
res-10 -> res-8) and a worked res-8 example, plus a one-line pointer from
"Joining Different Resolutions" — the section that steers models into
coarsening in the first place.
Verified against the report gold: the pattern gives 21.17% for ACE
BioRank 5 (gold 21.09, MAX rollup 32.68) and 22.30% for channelized
connectivity (gold 22.65, MAX rollup 25.58).
Copy file name to clipboardExpand all lines: h3-guide.md
+28Lines changed: 28 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -120,6 +120,8 @@ Units: `'km'`, `'m'`, or `'rads'`.
120
120
121
121
**Always join by converting the finer (higher-numbered) dataset to the coarser resolution — never look for child columns on the coarser dataset.**
122
122
123
+
Pick the reducer for that conversion by what the value means: a measured quantity per cell rolls up with `SUM` or `AVG`, but a **coverage fraction** (the share of a cell covered by something) rolls up as the mean over the parent's child cells — see *Feature coarser than the overlay layer* under Problem 3.
124
+
123
125
### Step 1: Check for pre-computed parent columns (preferred)
124
126
125
127
Many fine-resolution datasets (e.g. GEBCO h8) already carry pre-computed parent columns (`h7`, `h6`, `h5`, ...). Use these directly — they are faster than calling `h3_cell_to_parent()` on every row. Check the schema first:
@@ -310,6 +312,32 @@ ORDER BY pct_conserved;
310
312
311
313
Asking about **one** class ("what percent of hardwood woodland is conserved") is the same query with `WHERE f.whr13num = <code>` — keep the `frac × weight` product. Joining to the *distinct conserved cells* instead (a `SEMI JOIN` on `(h10, h0)`) counts every partly-conserved cell as fully conserved and overstates the percentage.
312
314
315
+
**Feature coarser than the overlay layer — average the child cells.***(Skip unless the feature's native resolution is coarser than the layer you are overlaying — e.g. a res-8 or res-9 feature against a res-10 coverage layer.)* Two reductions are needed, in this order. Across the overlapping units **within one fine cell**, take `MAX` (or `LEAST(SUM(w), 1)`), as above. Across the **child cells of a coarse parent**, take the mean — `SUM(w) / <children per parent>`, which is `7` for one resolution step (res-10 → res-9) and `49` for two (res-10 → res-8). The parent's weight is the share of the parent that is covered, so `MAX` across children is the wrong reducer there: it scores a whole parent as covered whenever a single child is.
316
+
317
+
```sql
318
+
WITH cell_w AS ( -- one weight per res-10 cell: MAX across overlapping units
319
+
SELECT h10, h8, h0, MAX((Final_g1_p + Final_g2_p) /100.0) AS w
320
+
FROM read_parquet('<conserved-areas hex>')
321
+
GROUP BY h10, h8, h0
322
+
),
323
+
parent_w AS ( -- res-10 → res-8: mean over the 49 children
Group on `h3_cell_to_parent(h10, 8)` when the fine layer carries no `h8` column. When the coarse feature is itself a `hex-fractions` layer, keep its `frac` in the product as in the same-resolution case: `SUM(f.frac * COALESCE(p.w9, 0)) / SUM(f.frac)`. Matching the coarse feature against the fine layer's *distinct cells* treats a parent as fully covered when any one child is; the inflation grows with the number of children per parent.
340
+
313
341
**If you plan to mask this result against another hex dataset:** put the
314
342
`SEMI JOIN` on the raw `read_parquet(...)`*before*`GROUP BY`, not in a
315
343
CTE after it. Aggregation blocks DuckDB's dynamic partition pruning, so a
0 commit comments