Blender protocol and registry¶
What you implement, and how you register it. See Methods: notation for the conventions a blender is expected to honour.
Shared protocol helpers¶
Shared blender scaffolding: weight renormalization, masked averaging, target clipping, and per-lead-bucket fitting.
PerBucketFitter
dataclass
¶
Fit one state object per lead bucket, with a global-fit fallback.
fit_one receives the row subset for a bucket and returns the state.
Without blend, buckets with fewer than min_rows rows fall back to
the global state — an all-or-nothing cliff, kept for states whose
parameters cannot be safely interpolated. Supplying blend replaces the
cliff with empirical-Bayes-style shrinkage: every non-empty bucket serves
blend(local, global, w) with weight w = n / (n + prior_rows), so
the global fit acts as a prior worth prior_rows rows of evidence. The
default prior of min_rows / 4 puts w = 0.8 at exactly min_rows
rows — the local fit dominates right where the old cliff granted it full
weight — while thinner buckets shade smoothly toward the global fit
instead of a barely-qualified local fit serving its sampling noise as a
constant bias.
FittedBuckets
dataclass
¶
apply ¶
apply(
lead: FloatArray, use: Callable[[S, ndarray], None]
) -> None
Group rows by bucket state and invoke use(state, row_indices).
renormalize_weights ¶
renormalize_weights(
weights: FloatArray, availability: BoolArray
) -> FloatArray
Per-row weights over available sources, renormalized to sum to 1.
Rows with no available source get all-zero weights.
masked_average ¶
masked_average(
values: FloatArray,
availability: BoolArray,
weights: FloatArray | None = None,
) -> FloatArray
Weighted average over available sources; NaN where none are available.
finalize_point ¶
finalize_point(
point: FloatArray,
kind: TargetKind,
variable: VariableSpec | None = None,
) -> FloatArray
Clip probability targets into [0, 1]; clamp declared variable bounds.
The bounds clamp mirrors the serve boundary, so the backtest scores the quantity a user would actually receive — never a negative wind speed. NaN (no prediction) passes through unchanged.
finalize_quantiles ¶
finalize_quantiles(
quantiles: FloatArray,
kind: TargetKind,
variable: VariableSpec | None = None,
) -> FloatArray
Monotone rearrangement plus the same clamps finalize_point applies.
Row-wise np.sort is the standard fix for quantile crossing: it never
worsens any proper scoring rule and guarantees emitted quantiles are a
valid distribution. Every quantile emitter must route through here.
quantile_blend_result ¶
quantile_blend_result(
quantiles: FloatArray,
levels: tuple[float, ...],
kind: TargetKind,
variable: VariableSpec | None,
) -> BlendResult
Finalized quantiles served with their own median as the point.
coefficient_state ¶
coefficient_state(
method_id: str,
variable: VariableSpec | None,
fit_status: str,
parameters: FloatArray | None,
names: tuple[str, ...],
) -> dict[str, object]
Glass-box to_state payload shared by coefficient-vector heads.
fit_shrunk_buckets ¶
fit_shrunk_buckets(
product: Product,
lead_hours: FloatArray,
fit_one: Callable[[ndarray], FloatArray],
) -> FittedBuckets[FloatArray]
Per-bucket coefficient fits with linear shrinkage toward the global fit.