GradientCOBRA
GradientCOBRA: kernel aggregation in prediction space
GradientCOBRA is a regression aggregation method that combines several base regressors through a kernel defined on their prediction vectors.
Instead of averaging the predictions of the base regressors directly, GradientCOBRA uses those predictions to define a new feature space. Training observations whose prediction vectors are close to the prediction vector of a query point receive larger weights in the final regression estimate.
The method also provides a bandwidth-selection strategy based on cross-validation and, when a differentiable kernel is used, gradient-based optimization.
At a glance
-
Base regressors
Fit several regression models on one part of the training sample.
Output: \(r_1,\ldots,r_M\)
-
Prediction space
Represent each observation by the predictions of all base regressors.
Feature vector: \(r(x)\)
-
Distance
Compare observations in prediction space.
Default: Euclidean distance
-
Kernel
Convert prediction-space distance into similarity weights.
Default: RBF / radial kernel
-
Bandwidth optimization
Tune one kernel parameter using cross-validation.
Methods: grid search or gradient-based optimization
-
Aggregation
Compute a weighted average of the observed target values.
Output: final prediction
Core idea
Use the base models to build a prediction space, find observations that behave similarly in that space, and average their targets with kernel weights.
Why GradientCOBRA?
When several regression estimators are available, a common approach is to:
- choose one model,
- average their predictions,
- or learn a linear combination.
GradientCOBRA follows a different idea.
Suppose a query observation \(x\) is passed through several regressors. The resulting predictions form a vector
This vector describes how the collection of regressors sees \(x\).
If another observation \(X_i\) has a similar prediction vector,
then the two observations are considered close in prediction space.
GradientCOBRA uses this prediction-space neighborhood to determine which observed targets \(Y_i\) should contribute most strongly to the prediction for \(x\).
Prediction space
Assume that \(M\) regression estimators are available:
For an observation \(x\), GradientCOBRA defines
For example:
then
This vector becomes the representation used by the aggregation method.
The original input \(x\) is therefore not compared directly with another observation during the aggregation stage. Instead, GradientCOBRA compares
Relationship to COBRA
Classical COBRA uses a hard notion of consensus.
A training observation contributes when the predictions of the base regressors are sufficiently close to the predictions of the query point.
For example, the classical rule can use
for all base regressors \(m\).
GradientCOBRA replaces this hard selection rule by a smooth kernel weighting scheme.
Instead of assigning a training observation only
the method assigns a continuous similarity weight.
very similar prediction vector -> large weight
moderately similar -> medium weight
very different -> small weight
This makes the consensus mechanism smoother and allows a broader class of kernel functions.
Mathematical formulation
Let the aggregation sample contain
Let
be the vector of predictions produced by the \(M\) base regressors.
The paper defines the combined estimator as
with kernel weights
The prediction is therefore a kernel-weighted average of the observed targets.
The important point is that the kernel acts on the whole prediction vector rather than independently on each individual estimator output.
One vector, one kernel
GradientCOBRA treats
as a single \(M\)-dimensional feature vector.
The kernel is applied to a distance between complete prediction vectors:
This is different from applying one univariate kernel separately to every component and summing the results.
Conceptually:
r1(x) ─┐
r2(x) ─┤
r3(x) ─┼──► prediction vector r(x)
... │
rM(x) ─┘
│
▼
distance to r(Xi)
│
▼
kernel
│
▼
weight
How the package implementation works
The current kfc-procedure implementation exposes:
Its training pipeline is:
flowchart LR
D["Training data"] --> S["Split"]
S --> DK["Dₖ"]
S --> DL["Dₗ"]
DK --> E["Fit base regressors"]
E --> P["Predict Dₗ"]
P --> N["Normalize prediction space"]
N --> DM["Pairwise distance matrix"]
DL --> CV["K-fold CV"]
DM --> CV
CV --> O["Optimize bandwidth"]
O --> B["Selected bandwidth"]
B --> K["Kernel weights"]
K --> A["Weighted mean"]
The main stages are:
- split the training sample;
- fit base regressors;
- create prediction-space features;
- normalize those predictions;
- compute pairwise distances;
- tune one bandwidth parameter;
- transform distances with a kernel;
- aggregate targets with a weighted mean.
Training-data split
By default, calling
uses
and creates two subsets:
-
\(D_k\)
Used to fit the base regressors.
-
\(D_\ell\)
Used to construct the prediction-space aggregation rule and optimize the bandwidth.
The paper also separates the construction of the base estimators from the aggregation data. A common theoretical split is approximately half-and-half.
Controlled overlap
The package additionally supports overlap between the two subsets:
The implementation requires
For the usual independent-style split, keep
Base regressors
If estimators=None, the current implementation uses:
Each estimator is fitted using \(D_k\).
The fitted estimators are stored in:
For every observation in \(D_\ell\), the model then evaluates all base regressors and stacks their predictions.
If there are \(M\) regressors and \(\ell\) aggregation observations, the prediction matrix has shape
Custom base regressors
You can select the base estimators explicitly.
from kfc_procedure.cobra import GradientCOBRA
model = GradientCOBRA(
estimators=[
"linear_regression",
"ridge_cv",
"random_forest_regressor",
"svr",
],
random_state=42,
)
Estimator parameters
Use estimators_params to configure registered estimators.
model = GradientCOBRA(
estimators=[
"k_neighbors_regressor",
"random_forest_regressor",
"svr",
],
estimators_params={
"k_neighbors_regressor": {
"n_neighbors": 7,
},
"random_forest_regressor": {
"n_estimators": 300,
"random_state": 42,
},
"svr": {
"C": 10.0,
},
},
random_state=42,
)
Prediction-space normalization
Before distances are computed, the implementation rescales the prediction matrix.
If \(M\) is the number of base regressors, the normalization constant is
where the default numerator is
The prediction matrix is then transformed as
The fitted constant is available as
Custom normalization numerator
You may provide:
For example:
Meaning of norm_constant
In the current source code, the supplied value replaces the default
numerator 30.0; it is still divided by the maximum absolute target value
and by the number of prediction features.
Distance in prediction space
The default distance is
so the aggregation distance between two observations is
The full pairwise matrix is stored as
Available distances
The package currently registers:
| Name | Aliases | Description |
|---|---|---|
euclidean |
l2 |
Euclidean distance |
manhattan |
l1 |
Manhattan distance |
minkowski |
lp |
General Minkowski distance |
cosine |
— | Cosine distance |
hamming |
— | Coordinate disagreement |
For continuous regression predictions, Euclidean distance is the default.
Kernel weighting
The default kernel is
with aliases
The current radial kernel computes
Before the kernel is evaluated, the one-parameter adapter scales the distance:
where \(b\) is the parameter called bandwidth in the implementation.
Therefore, the default effective kernel is
For query \(x\) and aggregation observation \(X_i\),
Important bandwidth convention
The paper commonly writes a kernel in the form
The current package instead scales the distance as
before evaluating the kernel.
With the default RBF kernel,
These conventions move in opposite directions:
-
Paper-style \(h\)
Larger \(h\) generally creates a wider neighborhood because the argument \(z/h\) becomes smaller.
-
Package
bandwidth\(b\)
Larger \(b\) creates a narrower neighborhood for the default radial kernel because \(e^{-bD}\) decays faster.
Do not compare the numerical values directly
The bandwidth_ stored by the current Python implementation should not be
interpreted numerically as the same \(h\) used in the paper's
\(K(z/h)\) notation.
Weighted-mean aggregation
The default aggregator is
and produces
This is the regression consensus step.
If the weights are effectively unusable for a query, the prediction path uses the global mean of the aggregation targets as a fallback:
The fitted fallback value is stored as
Bandwidth optimization
The bandwidth controls the neighborhood size in prediction space.
The implementation selects it by minimizing cross-validation error on \(D_\ell\).
The default settings are:
If bandwidth_list is not provided, the candidate values are
so the default grid contains 300 candidates.
K-fold cross-validation objective
For every candidate bandwidth \(b\), the implementation:
- transforms the stored prediction-space distance matrix;
- computes the kernel similarity matrix;
- separates validation rows and training columns for each fold;
- predicts validation targets by weighted aggregation;
- computes the selected loss;
- returns the average loss across folds.
Conceptually,
For the default MSE loss,
The selected parameter satisfies
After fitting:
contains the selected value.
Grid-search optimization
Grid search is the current default.
model = GradientCOBRA(
opt_method="grid",
optimizer="grid",
bandwidth_list=[
0.01,
0.05,
0.1,
0.5,
1.0,
2.0,
5.0,
],
random_state=42,
)
The optimizer evaluates every candidate and selects the one with the lowest cross-validation loss.
A denser grid can be supplied with NumPy:
import numpy as np
model = GradientCOBRA(
bandwidth_list=np.linspace(0.01, 5.0, 100),
n_cv=5,
random_state=42,
)
Gradient-based optimization
A central contribution of the GradientCOBRA paper is replacing exhaustive bandwidth search with gradient-based bandwidth optimization when the kernel is smooth enough.
The package supports the same general idea.
Set
and choose a gradient optimizer.
For example:
model = GradientCOBRA(
kernel="rbf",
opt_method="grad",
optimizer="gd",
learning_rate=0.1,
max_iter=300,
random_state=42,
)
Other registered gradient optimizers include:
Example with Adam
model = GradientCOBRA(
kernel="rbf",
opt_method="grad",
optimizer="adam",
learning_rate=0.05,
max_iter=200,
random_state=42,
)
How gradients are obtained in the current implementation
The paper derives the derivative of the cross-validation objective with respect to the bandwidth for suitable differentiable kernels.
The package's optimization framework is more general.
Its gradient optimizers can estimate the derivative numerically using finite differences. The default gradient approximation is central difference.
Conceptually,
This lets the same optimizer framework work with any sufficiently smooth objective without requiring a hard-coded analytical derivative for every kernel.
Paper vs implementation
The paper explicitly derives bandwidth derivatives for suitable kernels.
The current package passes the cross-validation objective to a reusable gradient-optimizer framework, which by default approximates the gradient numerically.
Kernel compatibility with gradient optimization
Not every kernel is differentiable.
The source implementation checks
before using opt_method="grad".
If the selected kernel does not support gradient optimization, the method falls back internally to grid mode.
However, the selected optimizer must still belong to the optimizer category
required by the final method.
Correct gradient configuration
Correct grid configuration
Do not combine opt_method='grad' with optimizer='grid'
The constructor defaults to
If you explicitly change only
while leaving optimizer="grid", the implementation raises a
ValueError, because the grid optimizer is not registered as a gradient
optimizer.
Optimization history
After fitting, GradientCOBRA stores optimization metadata in
The dictionary contains:
For example:
model.fit(X_train, y_train)
print(model.bandwidth_)
print(model.optimization_outputs_["score"])
print(model.optimization_outputs_["evaluations"])
print(model.optimization_outputs_["history"])
The history is converted to a pandas DataFrame, which makes it convenient to
inspect the optimization path.
Basic usage
from kfc_procedure.cobra import GradientCOBRA
model = GradientCOBRA(
random_state=42,
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
The default workflow is approximately:
training data
│
▼
50 / 50 split
│
├──► fit base regressors
│
└──► aggregation observations
│
base regressors│
│ │
└────► prediction vectors
│
▼
normalize
│
▼
Euclidean distance
│
▼
tune one bandwidth
│
▼
RBF kernel
│
▼
weighted mean
Full example
import numpy as np
from sklearn.datasets import make_regression
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from kfc_procedure.cobra import GradientCOBRA
X, y = make_regression(
n_samples=1000,
n_features=20,
noise=15.0,
random_state=42,
)
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.2,
random_state=42,
)
model = GradientCOBRA(
estimators=[
"linear_regression",
"ridge_cv",
"lasso_cv",
"k_neighbors_regressor",
"random_forest_regressor",
"svr",
],
distance="euclidean",
kernel="rbf",
aggregator="weighted_mean",
loss="mse",
bandwidth_list=np.linspace(0.01, 5.0, 80),
n_cv=5,
random_state=42,
)
model.fit(X_train, y_train)
prediction = model.predict(X_test)
rmse = mean_squared_error(
y_test,
prediction,
) ** 0.5
print("Bandwidth:", model.bandwidth_)
print("RMSE:", rmse)
Gradient-optimization example
from kfc_procedure.cobra import GradientCOBRA
model = GradientCOBRA(
estimators=[
"ridge_cv",
"lasso_cv",
"random_forest_regressor",
"svr",
],
kernel="rbf",
opt_method="grad",
optimizer="adam",
learning_rate=0.05,
max_iter=150,
n_cv=5,
random_state=42,
)
model.fit(X_train, y_train)
print(model.bandwidth_)
print(model.optimization_outputs_["score"])
y_pred = model.predict(X_test)
Providing a separate aggregation sample
You can provide \(D_k\) and \(D_\ell\) explicitly instead of using the internal split.
In this configuration:
This can be useful when the data split has already been prepared elsewhere.
Using precomputed predictions
GradientCOBRA also supports
during fit.
In this mode, the supplied feature matrix is interpreted directly as the prediction space.
For example:
regressor 1 regressor 2 regressor 3
sample 1 12.4 11.8 12.1
sample 2 18.2 17.9 19.0
sample 3 7.4 8.0 7.7
is already a valid prediction-space matrix.
During prediction, the new matrix must use the same columns and the same ordering.
This mode is especially useful when GradientCOBRA is used as an aggregation component inside another pipeline.
Use inside the KFC procedure
The package registers a regression combiner under
through GradientCOBRACombiner.
The combiner receives candidate-model predictions directly and fits GradientCOBRA with
Conceptually, inside KFC:
This matches the role of consensual aggregation in the final C-Step of the KFC procedure.
Info
When GradientCOBRA is used this way, the local KFC models have already produced the prediction features, so GradientCOBRA does not need to train its own default base regressors.
Available kernels
The package contains several kernel implementations, including:
rbf
gaussian
radial
cobra
naive
epanechnikov
triangular
biweight
triweight
cauchy
exponential
reverse_cosh
Different kernels define different relationships between distance and similarity.
For example, the default radial kernel uses smooth exponential decay:
Compact-support kernels can instead assign exactly zero weight beyond a specified region.
Available loss functions
The optimization objective is configurable.
Registered losses include:
| Name | Aliases |
|---|---|
mse |
l2, squared_error |
mae |
l1 |
huber |
— |
quantile |
— |
log_loss |
cross_entropy |
hinge |
— |
For regression, the default is:
which matches the quadratic-error optimization described in the paper.
Important fitted attributes
After fit(), useful attributes include:
| Attribute | Description |
|---|---|
X_k_, y_k_ |
base-estimator training subset |
X_l_, y_l_ |
aggregation subset |
estimators_ |
fitted base regressors when as_predictions=False |
as_predictions_ |
whether the supplied input was already prediction space |
global_mean_ |
fallback mean target |
normalize_constant_ |
prediction scaling constant |
Y_l_norm_ |
normalized aggregation prediction matrix |
distance_matrix_ |
pairwise prediction-space distances |
cv_folds_ |
cross-validation folds |
bandwidth_ |
selected kernel scaling parameter |
optimization_outputs_ |
optimization metadata and history |
Prediction workflow
For a new observation \(x\):
flowchart LR
X["New observation x"]
E["Base regressors"]
R["Prediction vector r(x)"]
N["Normalize"]
D["Distance to r(Xᵢ)"]
B["Scale by bandwidth"]
K["Kernel weights"]
A["Weighted mean of Yᵢ"]
Y["ŷ(x)"]
X --> E --> R --> N --> D --> B --> K --> A --> Y
Mathematically, the current default implementation follows
Statistical interpretation
GradientCOBRA can be viewed as a nonparametric regression procedure in the space generated by the base models.
The base regressors transform
into
Then the aggregation method performs kernel-style regression in that \(M\)-dimensional prediction space.
This is useful because each base regressor may capture a different aspect of the relationship between \(X\) and \(Y\). Their joint prediction vector can therefore provide a rich representation even when no single model is sufficient.
Theoretical result from the paper
The paper studies the regression risk
It shows that, under its stated assumptions, the kernel-based aggregation inherits the performance of consistent base estimators.
A key risk bound has the form
This expresses an important property of consensual aggregation: asymptotically, the combined method can track the performance of the strongest estimator in the candidate collection, up to a term that decreases with the aggregation sample size under the assumptions of the theorem.
Note
This statement summarizes the theoretical result proved in the paper. It should not be interpreted as a finite-sample guarantee for every dataset or every package configuration.
What gradient descent changes
The statistical estimator and the bandwidth optimizer are two separate ideas.
The estimator itself is
Gradient descent changes only the way the bandwidth is selected.
Instead of evaluating a long list of possible bandwidths,
the optimizer follows the slope of the cross-validation objective toward a lower-loss value.
The paper motivates this using cross-validation error curves that are often approximately convex-like in the bandwidth.
Grid search vs gradient optimization
| Property | Grid search | Gradient-based |
|---|---|---|
| Candidate values | Explicit finite grid | Iterative updates |
| Derivative needed | No | Yes or numerical approximation |
| Works with non-smooth kernels | Generally yes | Not always |
| Default in package | Yes | No |
| Package optimizers | grid |
gd, momentum, adam |
| Search resolution | Limited by grid | Continuous parameter updates |
Grid search is simple and robust.
Gradient optimization can avoid evaluating a large dense grid when the kernel and objective are sufficiently smooth.
GradientCOBRA vs MixCOBRA
The two estimators use different spaces.
| Method | Input-space distance | Prediction-space distance | Tuned parameters |
|---|---|---|---|
| GradientCOBRA | — | ✓ | one bandwidth |
| MixCOBRA | ✓ | ✓ | input/prediction trade-off |
GradientCOBRA asks:
Which observations receive predictions similar to this query from the collection of regressors?
MixCOBRA additionally asks:
Are those observations also close in the original feature space?
Use this distinction when choosing which conceptual page to read next.
GradientCOBRA vs direct model averaging
Direct model averaging might compute
GradientCOBRA does something fundamentally different.
The base-model predictions are used as coordinates, not as the quantities that are directly averaged.
The method first finds relevant training observations in prediction space, and then averages their observed target values:
So:
while:
GradientCOBRA
base predictions
↓
prediction-space neighborhood
↓
training targets
↓
weighted average
↓
prediction
Practical considerations
Number of base regressors
If too few estimators are used, prediction space may not capture enough structure.
If many weak or redundant estimators are used, the prediction-space dimension \(M\) grows and neighborhood estimation can become harder.
The paper's convergence-rate term explicitly depends on \(M\), which reflects this dimensional effect.
Scaling
Prediction outputs from heterogeneous regressors may differ in magnitude. The package rescales prediction space before computing distances.
Kernel choice
Smooth kernels are natural when gradient optimization is desired.
Compact-support kernels can create sparse neighborhoods but may not support the same gradient behavior.
Bandwidth
The bandwidth determines how local the final aggregation is.
With the package's default radial kernel:
small package bandwidth -> slower decay -> broader neighborhood
large package bandwidth -> faster decay -> narrower neighborhood
Inspecting a fitted model
model.fit(X_train, y_train)
print("Bandwidth")
print(model.bandwidth_)
print("Normalization")
print(model.normalize_constant_)
print("Optimization")
print(model.optimization_outputs_)
print("Prediction-space distance matrix")
print(model.distance_matrix_)
For a concise look at the optimization path:
Reproducibility
Use random_state to make the internal split and K-fold configuration
reproducible:
You can also control base-estimator randomness through estimators_params.
Parallel base-estimator execution
The constructor exposes
by default.
The helper functions used to fit and evaluate the base estimators can use this value for parallel execution.
For example:
This setting concerns the base-estimator stage; it does not mean that every bandwidth evaluation is automatically parallelized.
Paper and implementation terminology
The following mapping is useful when reading both the paper and the source code.
| Paper concept | Package representation |
|---|---|
| base estimators \(r_{k,1},\ldots,r_{k,M}\) | estimators_ |
| prediction vector \(r_k(x)\) | output of _load_predictions() |
| aggregation sample \(D_\ell\) | X_l_, y_l_ |
| prediction-space distances | distance_matrix_ |
| kernel \(K_h\) | kernel_ + adapter_ |
| bandwidth | bandwidth_ |
| weighted regression estimate | weighted_mean aggregator |
| CV objective \(\phi_\kappa\) | kappa_cross_validation_error() |
| bandwidth optimization | _optimize_hyperparameters() |
Mental model
GradientCOBRA turns the predictions of several regressors into a new feature space and performs kernel-weighted regression in that space.