apbase.cross_validate
Leave-one-out cross-validation for IDW, ordinary kriging, and cokriging.
This package exports the public functions used to evaluate IDW/kriging and
collocated/ICM/LMC cokriging accuracy (MAE, RMSE, R2) on the same source
dataset, plus select_best_model to automatically pick the statistically
better method from either result.
- class apbase.cross_validate.BestModelResult(method, metric, idw_score, kriging_score, margin, relative_margin, significant, confidence_level, ci_low, ci_high, n_common_valid)
Bases:
objectStatistically-supported IDW-vs-kriging pick.
- Variables:
method ({"idw", "kriging"}) – Selected method.
metric ({"rmse", "mae"}) – Metric used for comparison.
kriging_score (idw_score,) – Paired scores over common finite held-out samples.
relative_margin (margin,) – Absolute and relative improvement of the selected method.
significant (bool) – Whether the bootstrap confidence interval excludes zero.
confidence_level (float) – Confidence level used for the interval.
ci_high (ci_low,) – Bounds of the idw-minus-kriging score difference.
n_common_valid (int) – Number of paired finite samples used for comparison.
- Parameters:
method (Literal['idw', 'kriging'])
metric (Literal['rmse', 'mae'])
idw_score (float)
kriging_score (float)
margin (float)
relative_margin (float)
significant (bool)
confidence_level (float)
ci_low (float)
ci_high (float)
n_common_valid (int)
- method: Literal['idw', 'kriging']
- metric: Literal['rmse', 'mae']
- idw_score: float
- kriging_score: float
- margin: float
- relative_margin: float
- significant: bool
- confidence_level: float
- ci_low: float
- ci_high: float
- n_common_valid: int
- class apbase.cross_validate.CokrigingCrossValidationResult(by_method, n_samples, radius, model_params)
Bases:
objectLeave-one-out cross-validation results for collocated/ICM/LMC cokriging.
See
cross_validate_cokriging().- Variables:
by_method (dict[str, MethodCrossValidation]) – Validation results keyed by method name. A method whose model could not be fitted is absent; see
cross_validate_cokriging().n_samples (int) – Number of held-out primary samples evaluated.
radius (float) – Shared local search radius.
model_params (dict) – Fitted cokriging parameters keyed by method name, with the same keys as
by_method.
- Parameters:
by_method (dict[str, MethodCrossValidation])
n_samples (int)
radius (float)
model_params (dict[str, dict[str, Any]])
- by_method: dict[str, MethodCrossValidation]
- n_samples: int
- radius: float
- model_params: dict[str, dict[str, Any]]
- class apbase.cross_validate.CrossValidationResult(idw, kriging, n_samples, radius, model_params)
Bases:
objectLeave-one-out cross-validation results for IDW and ordinary kriging.
- Variables:
kriging (idw,) – Per-method validation results.
n_samples (int) – Number of held-out samples evaluated.
radius (float) – Shared local search radius.
model_params (dict) – Readable fitted variogram parameters.
- Parameters:
idw (MethodCrossValidation)
kriging (MethodCrossValidation)
n_samples (int)
radius (float)
model_params (dict[str, float | int | str])
- kriging: MethodCrossValidation
- n_samples: int
- radius: float
- model_params: dict[str, float | int | str]
- class apbase.cross_validate.MethodCrossValidation(mae, rmse, r2, n_valid, predicted, actual)
Bases:
objectLeave-one-out results for a single interpolation method.
- Variables:
- Parameters:
mae (float)
rmse (float)
r2 (float)
n_valid (int)
predicted (ndarray)
actual (ndarray)
- mae: float
- rmse: float
- r2: float
- n_valid: int
- predicted: ndarray
- actual: ndarray
- class apbase.cross_validate.MultiMethodBestModelResult(method, runner_up, metric, scores, margin, relative_margin, significant, confidence_level, ci_low, ci_high, n_common_valid)
Bases:
objectStatistically-supported best-of-N pick from a named method mapping.
Generalizes
BestModelResultto more than two methods (e.g.CokrigingCrossValidationResult.by_method) – seeselect_best_model().- Variables:
runner_up (method,) – Selected method and second-best method.
metric ({"rmse", "mae"}) – Metric used for comparison.
scores (dict[str, float]) – Paired scores over common finite held-out samples.
relative_margin (margin,) – Absolute and relative improvement of
methodoverrunner_up.significant (bool) – Whether the bootstrap confidence interval excludes zero.
confidence_level (float) – Confidence level used for the interval.
ci_high (ci_low,) – Bounds of the runner-up-minus-winner score difference.
n_common_valid (int) – Number of paired finite samples used for comparison.
- Parameters:
method (str)
runner_up (str)
metric (Literal['rmse', 'mae'])
scores (dict[str, float])
margin (float)
relative_margin (float)
significant (bool)
confidence_level (float)
ci_low (float)
ci_high (float)
n_common_valid (int)
- method: str
- runner_up: str
- metric: Literal['rmse', 'mae']
- scores: dict[str, float]
- margin: float
- relative_margin: float
- significant: bool
- confidence_level: float
- ci_low: float
- ci_high: float
- n_common_valid: int
- apbase.cross_validate.cross_validate(x, y, z, *, max_points=500, seed=None, radius=None, power=2.0, max_neighbors=40, min_neighbors=3, model_values=None)
Leave-one-out cross-validate local IDW and local ordinary kriging.
Each held-out point is removed one at a time and re-estimated from the remaining source points, reusing one variogram/radius and one spatial index for both methods. Evaluation is capped at
max_pointsheld-out samples; seemax_pointsfor the sampling behavior on larger datasets.- Parameters:
x (ArrayLike) – One-dimensional source coordinates and values. Rows where any of them are
NaNor infinite are ignored.y (ArrayLike) – One-dimensional source coordinates and values. Rows where any of them are
NaNor infinite are ignored.z (ArrayLike) – One-dimensional source coordinates and values. Rows where any of them are
NaNor infinite are ignored.max_points (int) – Maximum number of source points evaluated by leave-one-out. If the (finite) dataset has more points than this, a random subsample of this size is drawn instead of evaluating every point.
seed (int | None) – Seed for the subsample draw when
xhas more thanmax_pointsfinite points.Noneuses fresh entropy.radius (float | None) – Local search radius shared by both methods. If
None, derived asrangefrom the fitted (or supplied) variogram (range / 3with 10 000 or more points), matching the default used byIDWandKriging.power (float) – IDW distance exponent.
max_neighbors (int) – Neighbor bounds shared by both methods.
max_neighborsis capped atapbase.config["max_neighbors_ceiling"](default500).min_neighbors (int) – Neighbor bounds shared by both methods.
max_neighborsis capped atapbase.config["max_neighbors_ceiling"](default500).model_values (ArrayLike | None) – Optional native variogram model vector (5 values). If omitted, a variogram is fit from
x,y,z.
- Returns:
MAE, RMSE, and R2 for both methods, plus per-sample predictions and the held-out actual values.
- Return type:
- Raises:
ValueError – If input arrays have inconsistent size, too few finite rows, invalid neighbor bounds, invalid radius, or invalid bootstrap/sample configuration.
NativeExecutionError – If the native cross-validation kernel reports a failure status.
Examples
>>> result = cross_validate(x, y, z, max_points=300) >>> result.idw.rmse, result.kriging.rmse
- apbase.cross_validate.cross_validate_cokriging(x0, y0, z0, secondaries, *, max_points=500, seed=None, radius=None, max_neighbors=40, min_neighbors=3, n_structures=2, max_colocation_dist=None, max_secondary_neighbors=None)
Leave-one-out cross-validate collocated, ICM, and LMC cokriging together.
Each of the three coregionalization models is fit once from the full dataset (same as
fit()); only the primary is then held out one point at a time and re-estimated, sharing one primary spatial index and one radius across all three methods – seecross_validate()for the analogous IDW/kriging function.- Parameters:
x0 (ArrayLike) – Primary variable source coordinates and values.
y0 (ArrayLike) – Primary variable source coordinates and values.
z0 (ArrayLike) – Primary variable source coordinates and values.
secondaries (SecondaryInput) – Same accepted forms as
fit().max_points (int) – Maximum number of source points evaluated by leave-one-out; see
cross_validate().seed (int | None) – Seed for the subsample draw when there are more than
max_pointsfinite points.Noneuses fresh entropy.radius (float | None) – Local search radius shared by all three methods and by every variable’s neighbor search. If
None, derived asrange(range / 3with 10 000 or more points) from a variogram fit on the primary alone (independent of any one method’s own joint range fit).max_neighbors (int) – Neighbor bounds shared by all three methods.
min_neighbors (int) – Neighbor bounds shared by all three methods.
n_structures (int) – Number of nested LMC structures (S), see
CoKriging.max_colocation_dist (float | None) – Pairing distance for the cross-covariances and secondary neighbor limit (ICM and LMC), see
CoKriging.max_secondary_neighbors (int | None) – Pairing distance for the cross-covariances and secondary neighbor limit (ICM and LMC), see
CoKriging.
- Returns:
MAE, RMSE, and R2 per method under
by_method("collocated","icm","lmc"), plus per-sample predictions and the held-out actual values (identical across methods, evaluated on the same held-out samples). A method whose model cannot be fitted is left out instead of failing the call: any method when a secondary has too few samples paired with the primary (seemax_colocation_dist), and ICM or LMC when the fit is rejected as non-positive-semidefinite or invalid. The error is raised only when no method can be fitted.- Return type:
- Raises:
ValueError – If input arrays, neighbor bounds, secondary variables, radius, or sample configuration are invalid.
NativeExecutionError – If the cross-validation kernel reports a failure status, or if no method’s model can be fitted (the first fit error is raised).
Examples
>>> result = cross_validate_cokriging(x0, y0, z0, {"ndvi": (xu, yu, zu)}) >>> result.by_method["icm"].rmse
- apbase.cross_validate.select_best_model(result: CrossValidationResult, *, metric: Literal['rmse', 'mae'] = 'rmse', n_bootstrap: int = 2000, confidence_level: float = 0.95, seed: int | None = None) BestModelResult
- apbase.cross_validate.select_best_model(result: Mapping[str, MethodCrossValidation], *, metric: Literal['rmse', 'mae'] = 'rmse', n_bootstrap: int = 2000, confidence_level: float = 0.95, seed: int | None = None) MultiMethodBestModelResult
Pick the statistically better method from two or more evaluated methods.
Given a
CrossValidationResult(IDW vs. kriging), this keeps its original two-method behavior and return type unchanged – see below. Given any other named mapping ofMethodCrossValidation(e.g.CokrigingCrossValidationResult.by_method, or a hand-built{"a": ..., "b": ..., "c": ...}), it generalizes to a best-vs-runner-up comparison across all of them and returns aMultiMethodBestModelResultinstead.Pick the better of IDW/kriging from a
CrossValidationResult.Compares IDW against ordinary kriging on the held-out samples where both methods produced a finite leave-one-out prediction (some samples can be finite for one method and NaN for the other – e.g. a singular local kriging system – so the two error series stay paired point-for-point). The lower-
metricmethod wins (ties go to"idw", matchingcreate_map()’s selection rule). A paired bootstrap over that common set then estimates a confidence interval for the score difference (idw minus kriging);significantisTruewhen that interval excludes zero, i.e. the win is unlikely to be an artifact of the particular held-out sample draw.- Parameters:
result (CrossValidationResult | Mapping[str, MethodCrossValidation]) – Output of
cross_validate().metric (Literal['rmse', 'mae']) – Error metric used both for the point estimate and for each bootstrap replicate.
"rmse"matches the metric already used bycreate_map()to auto-select a method. R2 is intentionally not offered here: it is monotonic in RMSE for a fixed actual-value set, but its normalization (1 - SS_res/SS_tot) depends on the evaluated subset’s variance, so it does not compare as cleanly once the two methods’ NaN patterns diverge.n_bootstrap (int) – Number of paired bootstrap resamples. Memory and time scale as
O(n_bootstrap * n_common_valid); the default is fast (well under a second) up tocross_validate’s defaultmax_points=500.confidence_level (float) – Two-sided confidence level for the score-difference interval, e.g.
0.95for a 95% CI.seed (int | None) – Seed for the bootstrap resample draw.
Noneuses fresh entropy.
- Returns:
The selected method plus the paired scores, margin, and bootstrap confidence interval backing that choice. For IDW vs kriging,
ci_low/ci_highbound the idw-minus-kriging score difference: a positive interval means kriging scored better, a negative interval means idw scored better.- Return type:
- Raises:
ValueError – If the metric/bootstrap configuration is invalid, predicted/actual arrays are inconsistent, fewer than two methods are supplied, or no paired evidence exists for comparison.
Notes
This uses a percentile bootstrap on the paired per-sample errors instead of a parametric test (e.g. a paired t-test), so it needs no distributional assumption and no SciPy dependency:
n_bootstrapindex draws are taken once vianumpy.random.Generator.integers(), and every replicate’s RMSE/MAE is computed in one vectorized reduction, not a Python loop. Resampling reuses the same draw for both methods on each replicate, which preserves the point-to-point pairing/correlation between IDW and kriging errors – essential for a meaningful difference interval.Any held-out sample where
actualitself is non-finite is also excluded (this cannot happen fromcross_validate’s own output, which is filtered upfront, but protects hand-builtCrossValidationResultinputs).If one method has zero finite predictions on the common set while the other has at least one, that method wins outright (
significant=True,margin=inf, no bootstrap – there is nothing to resample). If neither method has any finite prediction, or the two methods’ finite predictions never overlap on the same held-out sample, this raisesValueError: unlikecreate_map’s plain RMSE tie-break, this function refuses to guess when there is no shared, paired evidence to compare.Examples
>>> result = cross_validate(x, y, z, max_points=300) >>> best = select_best_model(result) >>> best.method 'kriging' >>> best.significant True