Stacking
Stacking is a learned C-Step strategy that uses the F-Step prediction matrix as input to a second-level predictive model.
The package provides two task-specific stacking combiners:
They are implemented by:
Both follow the same structure:
Core idea
Suppose the F-Step produces predictions from \(M\) divergence-specific local model families.
For \(n\) observations, the C-Step receives:
Stacking treats the columns of \(P\) as features for a new predictive model.
For regression:
For classification:
The source calls these second-level models:
where:
Where stacking appears in KFC
flowchart LR
K["K-Step"]
F["F-Step"]
P["Prediction matrix"]
M["Meta-model"]
Y["Final prediction"]
K --> F --> P --> M --> Y
The stacking combiner does not use the original KFC feature matrix directly.
It receives only the F-Step prediction matrix and the target values supplied to the C-Step.
Regression stacking
The regression implementation is:
and is registered as:
The class documentation describes it as:
Stacking combiner using a regression meta-model.
Its purpose is to learn a mapping from base predictions to target values.
Constructor
If no meta-model is supplied, the current source uses:
through:
It also initializes:
Regression fit flow
The fit() method first converts the prediction matrix:
Then it requires two-dimensional input:
Next it clones the configured meta-model:
and fits the clone:
Finally:
and the method returns:
Why the meta-model is cloned
The source does not fit:
directly.
Instead:
remains the configured template while:
becomes the fitted estimator.
This is useful when inspecting configuration versus learned state.
Regression prediction
The combine() method first checks:
If stacking has not been fitted, it raises:
Otherwise prediction is:
Because BaseCombiner.predict() delegates to combine(), both:
and:
use the fitted meta-regressor.
Direct regression example
from kfc_procedure.core.combiner.regression import (
StackingRegressorCombiner,
)
combiner = StackingRegressorCombiner()
combiner.fit(
P_train,
y_train,
)
y_pred = combiner.predict(
P_test
)
With the default constructor, the fitted model is a cloned:
instance.
Inspect the fitted regression meta-model
For the default linear regression model:
The coefficients correspond to the prediction-matrix columns.
Classification stacking
The classification implementation is:
and is registered as:
The source describes it as a stacking-based classification combiner that learns a mapping from base predictions to final class labels.
Constructor
The default meta-classifier is:
through:
The source also initializes:
Classification fit flow
Like regression, fitting begins with:
and validates:
Then:
followed by:
Finally:
Classification prediction
Before prediction:
Then:
Direct classification example
from kfc_procedure.core.combiner.classification import (
StackingClassifierCombiner,
)
combiner = StackingClassifierCombiner()
combiner.fit(
P_train,
y_train,
)
y_pred = combiner.predict(
P_test
)
Inspect the fitted classifier
For the default logistic regression classifier:
print(
combiner.meta_model_.classes_
)
print(
combiner.meta_model_.coef_
)
print(
combiner.meta_model_.intercept_
)
Prediction matrix shape
Both stacking classes expect:
In KFC, this means:
For example, if KFC uses:
the stacking meta-model receives four features per sample.
Regression matrix example
euclidean gkl logistic is
sample 1 12.4 12.8 12.1 12.5
sample 2 20.7 21.0 20.4 20.8
sample 3 8.3 8.1 8.5 8.2
Classification matrix example
The current stacking classes do not transform or encode the prediction matrix themselves.
They pass it directly to the configured meta-model.
Important classification detail
For classification, divergence-level class predictions are passed directly as features.
For example:
is presented to the default logistic-regression meta-classifier as a numeric feature vector.
The stacking implementation does not one-hot encode those divergence-specific class predictions.
Note
This means the numeric representation of class labels becomes part of the meta-classifier input when using the current stacking implementation.
Default regression meta-model
The default regression stacking configuration is equivalent to:
This learns a linear mapping:
Unlike WeightedMeanCombiner, the default LinearRegression() used by
StackingRegressorCombiner uses scikit-learn's normal default
fit_intercept=True.
Difference from weighted_mean
Both default regression stacking and weighted_mean use
LinearRegression, but their source defaults differ.
WeightedMeanCombiner creates:
by default.
StackingRegressorCombiner creates:
which uses the estimator's default intercept behavior.
So even before custom meta-models are introduced, the two classes are not identical in their default configuration.
Default classification meta-model
The classification combiner uses:
when no custom model is supplied.
The stacking source does not add any further default parameters.
Custom regression meta-model
Pass any compatible cloneable regressor through:
For example:
from sklearn.ensemble import (
RandomForestRegressor,
)
from kfc_procedure.core.combiner.regression import (
StackingRegressorCombiner,
)
combiner = StackingRegressorCombiner(
meta_model=RandomForestRegressor(
n_estimators=200,
random_state=42,
)
)
Then:
clones and fits the configured random forest.
Custom classification meta-model
Likewise:
from sklearn.ensemble import (
RandomForestClassifier,
)
from kfc_procedure.core.combiner.classification import (
StackingClassifierCombiner,
)
combiner = StackingClassifierCombiner(
meta_model=RandomForestClassifier(
n_estimators=200,
random_state=42,
)
)
The source clones the supplied estimator before training it.
Clone compatibility
Both stacking implementations use:
Therefore a custom meta-model must be compatible with scikit-learn cloning.
In practice, it should behave like a scikit-learn estimator and expose its constructor configuration through the normal estimator parameter interface.
If clone() cannot reconstruct the supplied object from its parameters,
stacking fitting will fail before the meta-model's own fit() call.
KFC regression usage
Conceptually, the intended string configuration is:
from kfc_procedure import KFCRegressor
model = KFCRegressor(
divergences=[
"euclidean",
"gkl",
],
local_model="ridge",
combiner="stacking_regressor",
)
However, the current C-Step implementation injects random_state into every
string-based combiner constructor.
StackingRegressorCombiner.__init__() currently accepts only:
and does not accept:
Therefore the string path is affected by the current constructor mismatch.
Current KFC regression workaround
Pass an instance:
from kfc_procedure import KFCRegressor
from kfc_procedure.core.combiner.regression import (
StackingRegressorCombiner,
)
model = KFCRegressor(
divergences=[
"euclidean",
"gkl",
],
local_model="ridge",
combiner=StackingRegressorCombiner(),
random_state=42,
)
Because the combiner is already an object, C-Step returns it directly rather
than reconstructing it through CombinerFactory.
KFC classification usage
The intended string name is:
but the same current C-Step issue applies because:
does not accept random_state.
Use an instance with the current source version:
from kfc_procedure import KFCClassifier
from kfc_procedure.core.combiner.classification import (
StackingClassifierCombiner,
)
model = KFCClassifier(
divergences=[
"euclidean",
"gkl",
],
local_model="logistic_regression",
combiner=StackingClassifierCombiner(),
random_state=42,
)
Custom meta-model in KFC
Regression:
from sklearn.ensemble import (
RandomForestRegressor,
)
stacker = StackingRegressorCombiner(
meta_model=RandomForestRegressor(
n_estimators=200,
random_state=42,
)
)
model = KFCRegressor(
divergences=["euclidean"],
local_model="ridge",
combiner=stacker,
random_state=42,
)
Classification:
from sklearn.ensemble import (
RandomForestClassifier,
)
stacker = StackingClassifierCombiner(
meta_model=RandomForestClassifier(
n_estimators=200,
random_state=42,
)
)
model = KFCClassifier(
divergences=["euclidean"],
local_model="logistic_regression",
combiner=stacker,
random_state=42,
)
How KFC trains stacking
KFC internally separates the supplied training data into two subsets.
Conceptually:
D_k
│
├── K-Step
└── F-Step
│
▼
fitted local models
D_l
│
└── pass through fitted K-Step and F-Step
│
▼
P_l
│
▼
stacking fit
The stacking combiner therefore fits on:
and:
rather than on the same rows used to fit the cluster-local F-Step estimators.
Reconstruct stacking input
After fitting a KFC model, create the same kind of prediction representation for new data:
Then the fitted C-Step does:
Inspect the F-Step column order
The stacking meta-model sees columns in the order returned by F-Step.
Inspect them with:
This is especially useful for interpreting:
in linear stacking models.
Interpret regression stacking coefficients
Suppose:
and the fitted default linear meta-model has:
Then the learned stacking rule has the form:
The coefficients are not constrained by the stacking class.
Their behavior is determined by the selected meta-model.
Inspect classification stacking coefficients
For the default logistic-regression meta-model:
strategy = model.cstep_.strategy_
meta = strategy.meta_model_
print(
meta.classes_
)
print(
meta.coef_
)
print(
meta.intercept_
)
Interpretation follows scikit-learn's LogisticRegression representation.
The stacking combiner itself adds no additional coefficient transformation.
No stacking predict_proba()
The classification stacking implementation does not expose:
even though its default:
supports probabilities.
The combiner only defines:
and inherits:
from BaseCombiner.
Therefore:
does not find a predict_proba method on StackingClassifierCombiner.
Direct access to meta-model probabilities
If you already have a fitted StackingClassifierCombiner, you can technically
access the fitted underlying meta-model directly:
when the configured meta-classifier supports that method.
This is direct use of the underlying estimator, not a probability API exposed
by StackingClassifierCombiner itself.
Fit-before-predict requirement
Both stacking classes use their own flag:
rather than scikit-learn's check_is_fitted() inside combine().
Immediately after construction:
After successful fitting:
Calling:
too early raises the task-specific RuntimeError.
Input validation scope
During fit(), both classes explicitly check only:
The stacking classes themselves do not add explicit checks for:
Those conditions are left to the selected meta-model or NumPy/scikit-learn operations.
During combine(), the source converts with:
but does not explicitly repeat the ndim == 2 check before calling the fitted
meta-model.
One divergence
If KFC uses one divergence:
then the stacking matrix has shape:
A meta-model can still be trained on this single prediction feature.
For default regression stacking, that means fitting a linear relationship from one F-Step prediction column to the target.
For default classification stacking, it means fitting logistic regression on one numeric prediction feature.
Several divergences
With several divergences, stacking can learn interactions only to the extent that the chosen meta-model supports them.
The default regression meta-model is linear:
The default classification meta-model is also linear in its input features:
If nonlinear meta-level relationships are needed, supply a different clone-compatible meta-model.
Stacking is supervised
Unlike:
stacking requires target values during fit().
Regression:
Classification:
The target values determine the fitted meta_model_.
Stacking vs weighted mean
The current regression implementations differ in structure.
| Property | weighted_mean |
stacking_regressor |
|---|---|---|
| Default learner | LinearRegression(fit_intercept=False) |
LinearRegression() |
| Custom learner | No constructor hook | meta_model= |
| Fitted estimator attribute | model |
meta_model_ |
| Clone configured estimator | No | Yes |
| Explicit fitted flag | No | Yes |
Both operate on the same kind of prediction matrix, but stacking_regressor
is the customizable meta-regression abstraction.
Stacking vs majority vote
For classification:
majority_vote
no training
counts row labels
stacking_classifier
supervised training
learns mapping from prediction rows to labels
Stacking can learn that different divergence columns carry different information, subject to the selected meta-model.
Stacking vs CombinedClassifier
Both are learned classification C-Step strategies, but the implementations are different.
stacking_classifier:
combined_classifier:
For the second approach, see:
Direct regression experiment
import numpy as np
from kfc_procedure.core.combiner.regression import (
StackingRegressorCombiner,
)
P_train = np.array([
[10.0, 10.5],
[12.0, 11.7],
[18.0, 18.4],
[25.0, 24.8],
])
y_train = np.array([
10.2,
11.9,
18.3,
25.1,
])
P_test = np.array([
[14.0, 14.3],
[20.0, 19.8],
])
stacker = StackingRegressorCombiner()
stacker.fit(
P_train,
y_train,
)
prediction = stacker.predict(
P_test
)
print(
prediction
)
Direct classification experiment
import numpy as np
from kfc_procedure.core.combiner.classification import (
StackingClassifierCombiner,
)
P_train = np.array([
[0, 0, 1],
[1, 1, 1],
[0, 1, 0],
[1, 0, 1],
[0, 0, 0],
[1, 1, 0],
])
y_train = np.array([
0,
1,
0,
1,
0,
1,
])
P_test = np.array([
[0, 0, 1],
[1, 1, 1],
])
stacker = StackingClassifierCombiner()
stacker.fit(
P_train,
y_train,
)
prediction = stacker.predict(
P_test
)
print(
prediction
)
Debugging stacking
Check the matrix shape
Expected:
Check fitted state
After successful fitting:
Inspect the fitted meta-model
Inspect KFC column order
Reconstruct the matrix
clusters = model.kstep_.predict(
X_test
)
P = model.fstep_.predict(
X_test,
clusters,
)
print(
P[:5]
)
Check the current string-path error
If KFC raises:
while using:
or:
pass a pre-instantiated stacking combiner instead.
Current source limitations
| Area | Current behavior |
|---|---|
| regression default meta-model | LinearRegression() |
| classification default meta-model | LogisticRegression(max_iter=1000) |
| custom meta-model | supported |
| meta-model cloning | supported |
| fit input validation | only explicit 2D X check |
| regression probability output | not applicable |
classification combiner predict_proba() |
not implemented |
| classification F-Step labels | passed directly as meta-features |
| one-hot encoding of F-Step labels | not implemented |
| string KFC integration | affected by C-Step random_state injection |
| combiner instance integration | supported |
| nonlinear stacking | possible through custom meta-model |
Quick reference
| Feature | Regression | Classification |
|---|---|---|
| Registry name | stacking_regressor |
stacking_classifier |
| Class | StackingRegressorCombiner |
StackingClassifierCombiner |
| Default model | LinearRegression() |
LogisticRegression(max_iter=1000) |
| Fitted model | meta_model_ |
meta_model_ |
| Clones meta-model | Yes | Yes |
Requires target in fit() |
Yes | Yes |
predict_proba() on combiner |
— | No |
Current string path affected by random_state injection |
Yes | Yes |
Mental model
Stacking treats the F-Step predictions as a new feature space and learns a second-level model on top of them.
The regression and classification implementations differ mainly in their default meta-models; their fitting structure is otherwise closely parallel.