|
8 | 8 |
|
9 | 9 | ## The problem this solves |
10 | 10 |
|
11 | | -You have point observations — sites, sensors, parcels, plots — and you want a |
12 | | -model that predicts well at locations you have not sampled. You fit something |
13 | | -flexible, cross-validate it, and get an R² of 0.8. Then you predict onto a grid |
14 | | -and the map is wrong in ways the score never hinted at. |
15 | | - |
16 | | -The score was wrong because the folds were wrong. Random k-fold puts a test |
17 | | -point's nearest neighbours in the training set, and under spatial |
18 | | -autocorrelation those neighbours carry most of its signal. The model is scored |
19 | | -on interpolation between known points while the actual task is extrapolation |
20 | | -away from them. The same thing happens one level up, in variable selection: a |
21 | | -predictor chosen by random inner folds can be chosen for leaking rather than |
22 | | -for predicting. |
23 | | - |
24 | | -`spatialkit` is built around fixing that. It provides folds that hold out whole |
25 | | -regions sized to the data's own autocorrelation range; three model backends — |
26 | | -geographically weighted regression (`GWmodel`), a Bayesian spatial Gaussian |
27 | | -process (`brms`), and random forests (`ranger`) — behind one `spatial_fit` S3 |
28 | | -class so they can be scored on identical folds; and an area-of-applicability |
29 | | -estimate that marks where the resulting score actually applies. Around all of |
30 | | -that sits a tessellation and aggregation pipeline built on |
31 | | -[`sf`](https://r-spatial.github.io/sf/): CRS management, Voronoi, hex, square |
32 | | -and Delaunay cells with stable reproducible IDs, and cell-level summaries with |
33 | | -optional design-effect-corrected standard errors. |
| 11 | +You have point observations — sites, sensors, parcels, plots — and you need to |
| 12 | +summarise or model them over areas. The path of least resistance is to borrow |
| 13 | +boundaries that already exist: ZIP codes, census tracts, counties, sales |
| 14 | +territories. Every one of those was drawn for mail routing, enumeration or |
| 15 | +politics, and none of them knows anything about the process you are studying. |
| 16 | +Aggregate to them and part of your answer is an artefact of the partition — |
| 17 | +the modifiable areal unit problem, and it is not a rounding error: the same |
| 18 | +observations can support materially different conclusions under different |
| 19 | +boundaries. |
| 20 | + |
| 21 | +`spatialkit` lets the data draw the boundaries instead: |
| 22 | + |
| 23 | +- **Seed cells where the observations actually are** — `get_voronoi_seeds()` |
| 24 | + places seeds by k-means on the point cloud, so cell density follows sampling |
| 25 | + density rather than an inherited grid. |
| 26 | +- **Let the spatial structure choose how many** — `determine_optimal_levels()` |
| 27 | + ranks candidate cell counts by the elbow of within-cluster variance, and, |
| 28 | + once you hand it a response, also by how much spatial autocorrelation each |
| 29 | + partition leaves in the residuals. Better than picking a round number. |
| 30 | +- **Build them, reproducibly** — `build_tessellation()` produces Voronoi, hex, |
| 31 | + square or Delaunay cells, clipped to your study area, with stable IDs that do |
| 32 | + not shift when the input row order does. |
| 33 | +- **Aggregate honestly** — `summarize_by_cell(deff = "kish")` corrects |
| 34 | + cell-level standard errors for within-cell autocorrelation, rather than |
| 35 | + treating clustered observations as independent and reporting intervals that |
| 36 | + are too narrow. |
| 37 | + |
| 38 | +Redrawing boundaries is easy; knowing whether the result means anything is not. |
| 39 | +So the second half of the package exists to keep you honest: three model |
| 40 | +backends — geographically weighted regression (`GWmodel`), a Bayesian spatial |
| 41 | +Gaussian process (`brms`), and random forests (`ranger`) — behind one |
| 42 | +`spatial_fit` S3 class so they can be scored on identical folds; cross-validation |
| 43 | +that holds out whole regions sized to the data's own autocorrelation range; and |
| 44 | +an area-of-applicability estimate that marks where the resulting score actually |
| 45 | +applies. All of it is built on [`sf`](https://r-spatial.github.io/sf/), with CRS |
| 46 | +management that will not silently hand metres to a function expecting degrees. |
| 47 | + |
| 48 | +That validation half matters more than it sounds. Fit something flexible, |
| 49 | +cross-validate it, get an R² of 0.8, predict onto a grid — and the map is wrong |
| 50 | +in ways the score never hinted at. The score was wrong because the folds were |
| 51 | +wrong. Random k-fold puts a test point's nearest neighbours in the training set, |
| 52 | +and under spatial autocorrelation those neighbours carry most of its signal. The |
| 53 | +model is scored on interpolation between known points while the actual task is |
| 54 | +extrapolation away from them. The same thing happens one level up, in variable |
| 55 | +selection: a predictor chosen by random inner folds can be chosen for leaking |
| 56 | +rather than for predicting. |
34 | 57 |
|
35 | 58 | Here is the gap, on 600 synthetic points with a smooth spatial field the |
36 | 59 | predictor does not explain. Same data, same model, same settings — only the |
|
0 commit comments