Base Estimators
The base estimator layer provides the predictive models used by the F-Step of the KFC Procedure.
The F-Step does not hard-code one regression model or one classifier. Instead, it resolves local learners through a registry:
and trains one model inside every divergence-specific cluster.
The main implementation lives in:
Main components
The estimator layer contains three important pieces.
-
BaseLocalModel
Abstract interface used by F-Step local models.
Requires:
-
LocalModelFactory
Registry and factory used to resolve estimator names.
Models are categorized as:
-
SklearnLocalModel
Adapter that wraps scikit-learn estimators so they can be used by the F-Step.
BaseLocalModel
All local-model implementations inherit from:
which itself inherits:
and ABC.
The abstract interface is:
class BaseLocalModel(BaseEstimator, ABC):
@abstractmethod
def fit(self, X, y):
...
@abstractmethod
def predict(self, X):
...
def predict_proba(self, X):
raise NotImplementedError
The base class is intentionally task-agnostic.
Task separation is handled by the factory registry.
Required methods
A local model must implement:
and:
The F-Step relies on exactly these methods when training and generating the prediction matrix consumed by the C-Step.
Optional probability method
The base class also defines:
but its default behavior is:
So probability prediction is optional at the local-model level.
The current F-Step itself does not expose a predict_proba() method, so
end-to-end KFC classification probabilities are not currently available even
when a local classifier supports probabilities.
LocalModelFactory
The registry used by F-Step is:
It subclasses the package's general-purpose:
and keeps its own independent registry.
The class documentation defines the categories:
although the current built-in registrations primarily use:
Why use a registry?
Instead of requiring users to instantiate every estimator manually, KFC can resolve a model from a string:
or:
F-Step then asks the factory to create the matching implementation.
Conceptually:
Automatic scikit-learn registration
When this module is imported:
the package automatically calls:
The registration function uses:
to discover available scikit-learn estimators.
It keeps estimator classes that:
Those estimators are then registered automatically with
LocalModelFactory.
Registration categories
A discovered estimator is registered as:
if it subclasses:
and otherwise as:
if it subclasses:
This category information is later used by F-Step to prevent task mismatch.
Estimator names
Scikit-learn class names are converted to lower-case snake case.
The conversion is performed by:
Examples:
| Scikit-learn class | Registry name |
|---|---|
LinearRegression |
linear_regression |
LogisticRegression |
logistic_regression |
RandomForestRegressor |
random_forest_regressor |
RandomForestClassifier |
random_forest_classifier |
KNeighborsRegressor |
k_neighbors_regressor |
KNeighborsClassifier |
k_neighbors_classifier |
DecisionTreeClassifier |
decision_tree_classifier |
RidgeCV |
ridge_cv |
LassoCV |
lasso_cv |
SVC |
svc |
SVR |
svr |
All-uppercase names are simply lowercased.
For example:
The exact available model list depends on scikit-learn
Because KFC discovers estimators dynamically with:
the complete set of model names depends on the installed scikit-learn version.
For that reason, application code and documentation should not rely on a permanently fixed exhaustive list.
Instead, inspect the registry in the installed environment.
List all registered local models
This returns a sorted list of all registered names and aliases.
List regression models
List classification models
This is the recommended way to discover the models actually available in the installed package.
Common regression estimators
The dynamically registered estimator set commonly includes names such as:
linear_regression
ridge
ridge_cv
lasso
lasso_cv
elastic_net
elastic_net_cv
decision_tree_regressor
random_forest_regressor
extra_trees_regressor
gradient_boosting_regressor
hist_gradient_boosting_regressor
k_neighbors_regressor
svr
dummy_regressor
Note
This is an illustrative subset.
The exact available names should be obtained from:
Common classification estimators
Typical dynamically registered names include:
logistic_regression
decision_tree_classifier
random_forest_classifier
extra_trees_classifier
gradient_boosting_classifier
hist_gradient_boosting_classifier
k_neighbors_classifier
svc
linear_svc
gaussian_nb
dummy_classifier
Again, use the registry to inspect the actual installed set.
Built-in MeanRegressor
In addition to dynamically registered scikit-learn models, the source explicitly registers:
as aliases for:
The registration is:
The model wraps:
Mean-regressor behavior
Its implementation is:
class MeanRegressor(BaseLocalModel):
def __init__(self):
self.estimator = DummyRegressor(
strategy="mean"
)
def fit(self, X, y):
self.estimator.fit(
X,
y,
)
return self
def predict(self, X):
return np.asarray(
self.estimator.predict(X),
dtype=float,
)
So each local cluster predicts the mean target learned from that cluster.
Current MeanRegressor integration issue
The current F-Step automatically injects:
when a local model is resolved from a string.
However:
currently accepts no parameters.
Therefore a string-based configuration such as:
can receive an unsupported random_state keyword when created by F-Step.
Current source behavior
In this source version, mean_regressor / dummy_mean may raise a
constructor TypeError when selected through F-Step.
This is an implementation issue, not a conceptual limitation of a cluster-wise mean predictor.
SklearnLocalModel
Scikit-learn estimators are not registered directly.
Instead, each dynamically registered name points to a small builder that returns:
This adapter gives scikit-learn models the BaseLocalModel interface expected
by F-Step.
Constructor
The adapter receives:
and arbitrary keyword arguments:
It then inspects:
using:
and retains only keyword arguments that are explicitly present in the constructor signature.
Parameter filtering
The implementation performs:
and then:
This has an important user-facing consequence.
Unknown parameters are silently removed instead of raising an error at this adapter layer.
Example
Suppose:
and the selected estimator only accepts alpha.
The adapter keeps:
and discards:
Check parameter spelling
A typo in a scikit-learn constructor parameter can therefore be silently ignored.
Inspect the fitted local estimator's parameters if configuration accuracy matters.
Inspect estimator parameters
After KFC has fitted local models, retrieve one:
Then:
For SklearnLocalModel, get_params() delegates directly to:
Change parameters with set_params()
The adapter also delegates:
to the underlying scikit-learn estimator.
This matches the standard scikit-learn parameter API.
Access the wrapped estimator
The underlying estimator is stored as:
Example:
You can then inspect estimator-specific fitted state:
when the selected estimator defines that attribute.
Probability capability
During initialization, SklearnLocalModel records whether the wrapped
estimator exposes:
with:
Then:
delegates to the wrapped estimator when available.
Otherwise it raises:
Example
A model such as logistic regression normally supports:
while some classifiers do not.
The adapter handles this capability check dynamically.
Important
This local capability does not currently make
KFCClassifier.predict_proba() functional, because the current FStep
itself has no predict_proba() method.
random_state handling
The F-Step resolves string models with:
params = dict(
self.local_model_params
)
if "random_state" not in params:
params["random_state"] = self.random_state
Therefore the top-level KFC seed is attempted for every string-based local model.
For scikit-learn-backed estimators, the adapter filters it out when the
constructor does not accept random_state.
Example
model = KFCRegressor(
divergences=["euclidean"],
local_model="random_forest_regressor",
local_model_params={
"n_estimators": 300,
},
combiner="gradientcobra",
random_state=42,
)
F-Step creates each random forest using the equivalent of:
Local seed overrides top-level seed
If you explicitly pass:
the F-Step does not replace it.
So:
takes precedence over:
Task validation
Before creating a string-based local model, F-Step checks:
This prevents incompatible estimator categories.
Regression mismatch example
This is invalid:
KFCRegressor(
divergences=["euclidean"],
local_model="logistic_regression",
combiner="gradientcobra",
)
because:
is registered as:
Classification mismatch example
This is invalid:
because:
is registered as:
Check whether a model supports a task
from kfc_procedure.core.ml import (
LocalModelFactory,
)
print(
LocalModelFactory.supports(
"ridge",
"regression",
)
)
Expected:
For:
expected:
Check whether a model exists
This returns a Boolean rather than raising for invalid input names.
Inspect registry metadata
The underlying factory provides:
Example:
The result contains:
For dynamically registered scikit-learn estimators, the registered target is the builder function created by the registration loop.
Registry normalization
BaseFactory normalizes registration names by:
So lookups are case-insensitive with respect to registry normalization.
Conceptually:
resolves the normalized key:
Registry aliases
The factory can register multiple names for the same target.
For example:
refer to the same built-in MeanRegressor class.
The general factory also provides:
to retrieve aliases registered for a target class.
Registry categories
Inspect all categories:
For the current local-model registry, the important categories are:
F-Step creates one estimator per cluster
When local_model is a string, F-Step calls:
inside the loop over divergence/cluster pairs.
Therefore each cluster receives a new local-model instance.
This is an important property.
For:
the F-Step can create:
euclidean / cluster 0 -> new estimator
euclidean / cluster 1 -> new estimator
euclidean / cluster 2 -> new estimator
gkl / cluster 0 -> new estimator
gkl / cluster 1 -> new estimator
gkl / cluster 2 -> new estimator
The estimators have the same class and constructor configuration but learn independently from different subsets.
One model type across all clusters
The current F-Step accepts one global:
and one global:
Therefore you cannot currently configure:
within one F-Step instance.
All divergence/cluster combinations use the same estimator type and parameter configuration.
Pre-instantiated estimator objects
F-Step also accepts a non-string local model object:
The relevant source logic is:
This means the exact same object instance is returned for every cluster.
Important reuse behavior
Suppose:
my_model = MyEstimator()
model = KFCRegressor(
divergences=["euclidean"],
local_model=my_model,
combiner="gradientcobra",
)
During F-Step fitting, the same object can be fitted repeatedly:
cluster 0 -> my_model.fit(...)
cluster 1 -> same my_model.fit(...)
cluster 2 -> same my_model.fit(...)
The current F-Step does not clone the object.
Prefer registered string estimators
For independent cluster models, use a registered string name.
Pre-instantiated local-model objects are reused rather than cloned in the current implementation.
Custom local estimator
A custom estimator can subclass:
and implement:
For example:
import numpy as np
from kfc_procedure.core.ml import (
BaseLocalModel,
)
class MedianRegressor(
BaseLocalModel
):
def fit(
self,
X,
y,
):
self.value_ = float(
np.median(y)
)
return self
def predict(
self,
X,
):
return np.full(
len(X),
self.value_,
dtype=float,
)
Register a custom estimator
Register it with:
using a task category.
from kfc_procedure.core.ml import (
LocalModelFactory,
)
@LocalModelFactory.register(
"median_regressor",
categories={"regression"},
)
class MedianRegressor(
BaseLocalModel
):
...
Then use:
model = KFCRegressor(
divergences=["euclidean"],
local_model="median_regressor",
combiner="gradientcobra",
)
Custom constructor compatibility
Remember that F-Step adds:
to every string-based local-model constructor unless it is already present in
local_model_params.
Therefore a directly registered custom estimator should normally support:
or accept arbitrary keyword arguments.
Otherwise factory creation can fail with:
The scikit-learn adapter avoids this problem by filtering unsupported kwargs, but directly registered custom classes do not receive that filtering automatically.
Register multiple aliases
The factory supports multiple registration names:
@LocalModelFactory.register(
"median_regressor",
"median",
categories={"regression"},
)
class MedianRegressor(
BaseLocalModel
):
...
Then both names create the same class.
Duplicate-name protection
BaseFactory.register() normalizes names and checks for conflicts before
registration.
Attempting to register a name that already exists raises:
This protects the estimator registry from silent replacement.
Registration names are normalized
The factory:
- strips surrounding whitespace;
- converts names to lower case;
- rejects empty names;
- rejects duplicates in the same registration call.
So:
becomes:
Creating an estimator directly from the factory
Although normal KFC users let F-Step do this, you can create a model directly.
from kfc_procedure.core.ml import (
LocalModelFactory,
)
model = LocalModelFactory.create(
"ridge",
alpha=2.0,
)
For a dynamically registered scikit-learn estimator, this returns a
SklearnLocalModel wrapper.
Then:
Inspect the created wrapper
The wrapper type is:
The underlying estimator can be accessed through:
Example: regression estimator
from kfc_procedure.core.ml import (
LocalModelFactory,
)
ridge = LocalModelFactory.create(
"ridge",
alpha=1.5,
)
ridge.fit(
X_train,
y_train,
)
y_pred = ridge.predict(
X_test,
)
Example: classification estimator
logit = LocalModelFactory.create(
"logistic_regression",
C=1.0,
max_iter=1000,
)
logit.fit(
X_train,
y_train,
)
y_pred = logit.predict(
X_test,
)
If supported:
Estimator parameters in KFC
Use:
to configure a string-based estimator.
Regression:
model = KFCRegressor(
divergences=["euclidean"],
local_model="random_forest_regressor",
local_model_params={
"n_estimators": 300,
"max_depth": 8,
"min_samples_leaf": 3,
},
combiner="gradientcobra",
random_state=42,
)
Classification:
model = KFCClassifier(
divergences=["euclidean"],
local_model="logistic_regression",
local_model_params={
"C": 1.0,
"max_iter": 1000,
"class_weight": "balanced",
},
combiner="combined_classifier",
random_state=42,
)
For more detail, see:
Choosing a regression estimator
The source does not prescribe one estimator as universally best.
The F-Step architecture is designed so that a local model can be selected according to the application.
A practical code-oriented interpretation is:
-
Linear models
Examples:
Useful when relationships inside clusters are approximately simple.
-
Tree models
Examples:
Useful when local relationships remain nonlinear.
-
Neighborhood models
Example:
-
Kernel / margin models
Example:
These are usage categories, not package-imposed rankings.
Choosing a classification estimator
Likewise, classification can use any registered classifier compatible with the cluster-level target distribution.
Common choices include:
Remember that some classifiers cannot fit when a local cluster contains only one class.
Small-cluster behavior
Every F-Step model is trained only on its assigned cluster.
Therefore the effective sample size can be much smaller than the full training sample.
If:
is large, local estimators may receive very few observations.
This can cause:
- unstable regression models;
- one-class classification clusters;
- neighbor-based models with too few samples;
- estimator-specific validation errors.
The F-Step catches ValueError raised during local-model fitting and rethrows
it with divergence and cluster information.
F-Step error message
The source wraps fitting errors as:
[FSTEP ERROR] divergence='...', cluster=... failed.
Reason: ...
Hint: cluster contains invalid label distribution.
The hint is always included, even if the original ValueError is not related
to classification.
Inspect the underlying Reason: text for the actual estimator failure.
Scikit-learn estimator version sensitivity
Because registration is dynamic:
the exact local-model registry can change when the installed scikit-learn version changes.
This affects:
- available estimator names;
- estimator constructor parameters;
- default values;
- supported capabilities such as
predict_proba().
For stable production configurations, pin the scikit-learn dependency version.
Quick registry inspection
A useful diagnostic script is:
from kfc_procedure.core.ml import (
LocalModelFactory,
)
print("Categories:")
print(
LocalModelFactory.available_categories()
)
print("\nRegression:")
print(
LocalModelFactory.available_by_category(
"regression"
)
)
print("\nClassification:")
print(
LocalModelFactory.available_by_category(
"classification"
)
)
Inspect one registration
and:
Quick reference
| Component | Role |
|---|---|
BaseLocalModel |
abstract local-estimator interface |
LocalModelFactory |
name/category registry |
SklearnLocalModel |
scikit-learn adapter |
register_all_sklearn_models() |
dynamic estimator registration |
clean_sklearn_name() |
converts sklearn class names to registry names |
MeanRegressor |
explicitly registered local mean baseline |
Important current-source behaviors
| Behavior | Current implementation |
|---|---|
| sklearn estimator discovery | dynamic via all_estimators() |
| task classification | ClassifierMixin / RegressorMixin |
| estimator naming | snake-case class names |
| unsupported sklearn kwargs | silently filtered |
top-level random_state |
injected by F-Step |
unsupported random_state on sklearn class |
filtered by adapter |
| pre-instantiated local model | reused, not cloned |
| local model type per cluster | one shared configuration for all clusters |
local predict_proba() |
supported by adapter when underlying model supports it |
F-Step predict_proba() |
not currently implemented |
mean_regressor alias |
mean_regressor, dummy_mean |
mean_regressor through F-Step |
currently affected by random_state constructor mismatch |
Mental model
The estimator registry answers “what model should each cluster use?”; the F-Step answers “which fitted instance should handle this observation?”