Prediction Space
COBRA-style estimators in kfc_procedure do not have to compare observations
only in the original feature space.
They can first transform each observation into a vector of predictions produced by an ensemble of base estimators:
The resulting matrix is the prediction space.
In the current source, prediction-space construction is shared by:
through utilities in:
especially:
Why prediction space exists
Suppose the original feature matrix is:
After fitting \(M\) base estimators, the package constructs:
Therefore:
The prediction-space columns are estimator outputs rather than original input features.
Construction pipeline
flowchart LR
X["Original X"]
E1["Estimator 1"]
E2["Estimator 2"]
EM["Estimator M"]
P["Prediction-space matrix P"]
X --> E1
X --> E2
X --> EM
E1 --> P
E2 --> P
EM --> P
The package implements this through:
which collects:
from every fitted estimator and returns:
Prediction-space shape
If there are:
samples and:
base estimators, then:
For example:
has:
Regression prediction space
For regression, each column normally contains a continuous prediction.
Example:
GradientCOBRA and MixCOBRARegressor use these prediction vectors when
computing similarity.
Classification prediction space
For classification, CombinedClassifier uses hard class predictions from
its base estimators.
predict_estimators() calls:
not:
So a prediction-space row might be:
rather than a concatenation of class-probability vectors.
This distinction is important when choosing a distance such as:
for classification.
Base-estimator fitting
The shared helper:
supports estimator specifications as:
For each estimator it eventually calls:
and returns the fitted estimator list.
Prediction space is then created by calling each fitted estimator's
predict() method.
Standard training mode
The normal COBRA workflow starts from raw features.
For example:
from kfc_procedure.cobra import GradientCOBRA
model = GradientCOBRA(
random_state=42,
)
model.fit(
X_train,
y_train,
)
With:
the training context contains two roles:
X_k, y_k
used to fit base estimators
X_l, y_l
used to construct the aggregation / calibration prediction space
Automatic split
When you do not provide X_l and y_l, the shared
resolve_training_context() function creates a splitter:
SplitterFactory.create(
"split_overlap",
split_ratio=split_ratio,
overlap=overlap,
random_state=random_state,
)
The returned indices are then used to build:
Explicit calibration data
You can also provide:
explicitly.
The helper requires both to be present together.
Providing only one raises:
as_predictions=True
All three major COBRA estimators expose an as_predictions fit mode.
This tells the training-context resolver that the supplied X is already a
prediction matrix.
For:
the current resolver returns:
No raw-feature training subset is created.
What this means
In prediction mode:
and base-estimator fitting is skipped by the estimators that honor this mode.
This is the mechanism used by the KFC C-Step wrappers when they pass the F-Step prediction matrix into COBRA components.
GradientCOBRA prediction mode
GradientCOBRA.fit() contains:
if not self.as_predictions_:
self.estimators_ = self._fit_estimators(
self.X_k_,
self.y_k_,
)
prediction_space = self._load_predictions(
self.X_l_,
)
else:
prediction_space = self.X_l_
So when:
the supplied matrix is used directly as:
and no internal base estimators are trained.
GradientCOBRA stored representation
After constructing or accepting prediction space, GradientCOBRA computes:
and stores the normalized prediction matrix:
It then computes the pairwise calibration distance matrix:
So for GradientCOBRA:
prediction matrix
↓
scalar normalization
↓
prediction-space distance matrix
↓
kernel
↓
weighted target aggregation
GradientCOBRA normalization
The helper:
uses:
where:
- \(M\) is the number of prediction columns;
sis the scale numerator.
GradientCOBRA calls it with:
unless:
is supplied.
Then:
Stored GradientCOBRA attributes
Useful fitted attributes include:
X_k_
y_k_
X_l_
y_l_
as_predictions_
estimators_
normalize_constant_
Y_l_norm_
distance_matrix_
cv_folds_
bandwidth_
optimization_outputs_
global_mean_
When:
the source does not create:
because the base-estimator fit branch is skipped.
GradientCOBRA prediction
At prediction time:
So prediction mode is internally consistent for GradientCOBRA:
Here P_test is treated directly as new prediction-space data.
CombinedClassifier prediction mode
CombinedClassifier.fit() has a parallel branch:
if not self.as_predictions_:
self.classes_ = np.unique(
self.y_k_
)
self.estimators_ = self._fit_estimators(
self.X_k_,
self.y_k_,
)
self.pred_l_ = self._load_predictions(
self.X_l_
)
else:
self.classes_ = np.unique(
self.y_l_
)
self.pred_l_ = self.X_l_
Thus:
uses the supplied matrix directly as:
CombinedClassifier distance matrix
The fitted calibration prediction matrix is compared with itself:
The default classification distance is:
which is a natural fit for vectors of hard class predictions.
CombinedClassifier prediction
At prediction time:
Then:
So prediction mode is also internally consistent for
CombinedClassifier:
KFC and prediction space
The KFC Procedure constructs its own prediction matrix in F-Step.
For new samples:
The C-Step wrappers for:
fit their wrapped COBRA estimators with:
so the F-Step matrix is intended to become the COBRA prediction-space representation directly.
Conceptually:
flowchart LR
X["Original KFC features"]
K["K-Step"]
F["F-Step"]
P["KFC prediction matrix"]
C["COBRA combiner"]
Y["Final output"]
X --> K --> F --> P --> C --> Y
Prediction space in CombinedClassifier
With a KFC classifier, one F-Step row might be:
where the columns correspond to divergence-specific local classifier predictions.
When passed to:
this row becomes a point in the wrapped CombinedClassifier prediction space.
The wrapped classifier compares that pattern with calibration patterns stored in:
Prediction space in GradientCOBRA
With KFC regression, one row might be:
When passed to GradientCOBRA using:
the row is treated as a four-dimensional prediction vector.
GradientCOBRA then applies its normalization, distance, kernel, and target aggregation stages.
MixCOBRA uses two spaces
MixCOBRARegressor differs from GradientCOBRA because its normal mode combines:
The source describes the two spaces as:
where:
is the normalized calibration input space and:
is the normalized estimator-prediction space.
MixCOBRA two-parameter mode
By default:
and the source computes:
from:
and:
from:
The two-parameter adapter then combines them as:
This comes directly from:
which returns:
MixCOBRA one-parameter mode
With:
the source concatenates the normalized input and prediction spaces:
and computes one distance matrix on that concatenated representation.
A one-parameter kernel adapter then scales that distance as:
MixCOBRA normalization
MixCOBRA computes two scalar constants.
For the input side:
using:
and for the prediction side:
using:
Both also divide by the number of prediction columns through
compute_normalization_constant().
The normalized spaces are:
self.X_l_norm_ = (
self.X_l_
* self.normalize_constant_x_
)
self.Y_l_norm_ = (
prediction_space
* self.normalize_constant_y_
)
Important MixCOBRA as_predictions=True behavior
The current MixCOBRARegressor.fit() accepts:
and, like the other estimators, skips internal base-estimator fitting.
During fit:
if not self.as_predictions_:
self.estimators_ = ...
prediction_space = ...
else:
prediction_space = self.X_l_
However, the current predict() implementation does not branch on:
before generating prediction features.
It starts with:
Consequence
When the model was fitted with:
the source did not create:
but predict(X) still tries to call:
when:
This means the current precomputed-prediction fit mode is not symmetrical with
the default prediction path in MixCOBRARegressor.
Current source limitation
GradientCOBRA and CombinedClassifier explicitly treat X as prediction
space during predict() when as_predictions_ is true.
The current MixCOBRARegressor.predict() implementation does not perform
that same branch.
Code that relies on MixCOBRARegressor(as_predictions=True) should inspect
this behavior carefully in the current source version.
pred_X in MixCOBRA prediction
MixCOBRARegressor.predict() exposes:
as an optional argument.
When supplied, it bypasses:
and uses:
as the test prediction representation.
The method still separately uses:
for the input-space representation:
This matches MixCOBRA's two-space design in its normal feature-based mode.
pred_features in training context
The shared resolve_training_context() function also has a:
argument.
Its branch currently returns:
TrainingContext(
X_k=np.asarray(X),
y_k=np.asarray(y),
X_l=pred_features,
y_l=np.asarray(y),
as_predictions=False,
)
when pred_features is supplied.
Current MixCOBRA use of pred_features
MixCOBRARegressor.fit() passes its:
argument into resolve_training_context().
But after receiving the context, the current fit code still does:
if not self.as_predictions_:
self.estimators_ = self._fit_estimators(
self.X_k_,
self.y_k_,
)
prediction_space = self._load_predictions(
self.X_l_
)
In the pred_features branch:
has been set to:
rather than raw calibration features.
Therefore the current fit implementation feeds pred_features into the fitted
base estimators instead of directly assigning it to prediction_space.
Current source behavior
The pred_features argument is documented as precomputed model
predictions, but the current training path does not directly use it as the
prediction matrix.
This page documents the source as implemented rather than assuming the intended behavior.
Prediction-space distances
Once a prediction matrix is available, COBRA components use a registered distance object implementing:
The common interface returns:
pairwise distances.
Built-in distance modules include:
The detailed behavior belongs to:
Calibration-to-calibration distance
During fitting, prediction-space models usually compute a square distance matrix.
For example, GradientCOBRA:
and CombinedClassifier:
If there are \(n_l\) calibration samples, the result has shape:
Query-to-calibration distance
At prediction time, a new prediction matrix is compared against the fitted calibration representation.
For GradientCOBRA:
For CombinedClassifier:
So with:
the distance matrix has shape:
Kernel scaling
Prediction-space distance is not used directly as an aggregation weight.
The distance matrix first passes through a kernel adapter.
For GradientCOBRA and CombinedClassifier, the one-parameter adapter performs:
The source implements this as:
Then the selected kernel converts the adapted distance into similarities.
For the default RBF kernel, see:
Target aggregation
After the kernel produces a weight matrix:
regression estimators aggregate calibration targets using a registered aggregator.
The default regression aggregator is:
which computes:
If the weight sum is effectively zero, the aggregator uses a fallback value.
GradientCOBRA supplies:
during final prediction.
Classification aggregation
CombinedClassifier uses:
by default.
For hard prediction:
computes weighted class scores and returns the class with the largest score.
Probability caveat in current weighted_vote
The current:
constructs one-hot class indicators and computes:
It does not use the supplied weights argument in that method.
Therefore CombinedClassifier.predict_proba() currently returns unweighted
class frequencies over the calibration labels passed to aggregate_proba(),
rather than probabilities derived from the kernel weights.
Warning
This behavior applies to the current source implementation of
aggregate_proba().
Hard-label prediction uses the supplied weights correctly through
aggregate().
Prediction space and cross-validation
COBRA hyperparameters are optimized using folds over the calibration dataset.
For GradientCOBRA, the already-computed prediction-space distance matrix is adapted for a candidate bandwidth:
The code then extracts:
for each fold and aggregates training-fold targets to predict the validation fold.
This lets bandwidth optimization happen within the stored prediction-space geometry.
Prediction space and data leakage
The package's normal mode separates:
through X_k/y_k and X_l/y_l.
The prediction matrix used for COBRA aggregation is generated on the calibration side after base estimators were fitted on the training side.
That source-level structure is why resolve_training_context() carries both
sets separately.
Inspect prediction space in GradientCOBRA
After fitting:
inspect:
print(
model.Y_l_norm_.shape
)
print(
model.distance_matrix_.shape
)
print(
model.normalize_constant_
)
To inspect the unnormalized calibration predictions in standard mode, recreate them through the fitted estimator pool:
Inspect prediction space in CombinedClassifier
After fitting:
the unnormalized calibration prediction space is stored directly as:
Inspect:
and:
Inspect MixCOBRA spaces
In normal feature mode:
inspect:
For two-parameter mode:
For one-parameter mode:
Precomputed prediction example: GradientCOBRA
Suppose another pipeline already created:
with one column per external model.
You can fit:
from kfc_procedure.cobra import GradientCOBRA
cobra = GradientCOBRA(
random_state=42,
)
cobra.fit(
P_train,
y_train,
as_predictions=True,
)
y_pred = cobra.predict(
P_test
)
In this mode:
becomes the calibration prediction space directly.
Precomputed prediction example: CombinedClassifier
from kfc_procedure.cobra import CombinedClassifier
classifier = CombinedClassifier(
distance="hamming",
random_state=42,
)
classifier.fit(
P_train,
y_train,
as_predictions=True,
)
y_pred = classifier.predict(
P_test
)
The matrices should contain hard class predictions because the current
classification prediction space is based on estimator predict() outputs.
KFC C-Step example
The C-Step wrapper performs the same conceptual operation automatically.
For example, GradientCOBRACombiner.fit() calls:
where X is already the KFC F-Step prediction matrix.
Similarly, CobraClassifierCombiner calls:
for CombinedClassifier.
What prediction space is not
In the current source, prediction space does not mean:
hidden neural-network embeddings
class-probability vectors by default
K-Step centroids
original input features
C-Step coefficients
It specifically refers to a matrix assembled from estimator predictions, or a
matrix explicitly supplied through as_predictions=True.
Prediction-space column order
When prediction space is generated internally, column order follows the order of the fitted estimator list:
because:
preserves that order.
This matters when interpreting distance geometry because every column is one coordinate in prediction space.
Default GradientCOBRA estimator pool
When no estimators are supplied, GradientCOBRA currently uses:
Therefore its normal prediction space has six columns, assuming all defaults are successfully resolved.
Default MixCOBRA estimator pool
The current MixCOBRA default is:
This differs slightly from GradientCOBRA, which uses:
instead of:
Default CombinedClassifier estimator pool
When no classifier estimators are supplied:
are fitted.
The resulting prediction-space matrix therefore has four hard-label columns by default.
Parallel prediction generation
predict_estimators() supports:
If:
predictions are generated sequentially.
Otherwise the source uses:
and then column-stacks the returned prediction arrays.
Debugging prediction space
Check the matrix dimension
Expected:
Check row alignment
The prediction matrix and target vector must describe the same samples.
These should match when using:
because resolve_training_context() begins with:
Check column count
This is the number of prediction-space coordinates.
For internally generated space, it should correspond to the number of fitted base estimators.
Check finite regression predictions
Non-finite values can propagate into distance calculations.
Inspect stored calibration representation
GradientCOBRA:
CombinedClassifier:
MixCOBRA:
Quick comparison
| Estimator | Prediction-space attribute | Normalized? | as_predictions predict path |
|---|---|---|---|
GradientCOBRA |
Y_l_norm_ |
Yes | treats new X as prediction space |
CombinedClassifier |
pred_l_ |
No | treats new X as prediction space |
MixCOBRARegressor |
Y_l_norm_ |
Yes | current predict() still expects/derives pred_X |
Quick reference
| Concept | Current source behavior |
|---|---|
| prediction generation | est.predict(X) |
| matrix construction | np.column_stack(preds) |
| standard mode | fit estimators on X_k, predict on X_l |
| explicit calibration set | supported with X_l, y_l |
| precomputed mode | as_predictions=True |
| GradientCOBRA scaling | scalar normalization, scale factor 30.0 |
| CombinedClassifier scaling | no prediction normalization before distance |
| MixCOBRA prediction scaling | separate input/prediction constants |
| Gradient adapter | one-parameter distance scaling |
| CombinedClassifier adapter | one-parameter distance scaling |
| MixCOBRA adapter | one- or two-parameter |
| Mix two-space fusion | alpha * D_X + beta * D_Y |
| classification space | hard predict() labels |
| default classifier distance | hamming |
Mental model
Prediction space replaces “How close are these samples in their original features?” with “How similarly do the model experts predict these samples?”
GradientCOBRA works directly in that prediction representation, CombinedClassifier applies the same idea to hard class predictions, and MixCOBRA combines prediction-space geometry with an input-space geometry.