Model Sources¶
ModelSource / ComparedModelSource — fitted-model adapters that feed the diagnostics.
Ferrum — a statistical visualization library with a Rust core.
ComparedModelSource ¶
Multi-model wrapper exposing the same surface as ModelSource.
Every derived-data method is proxied through each underlying
ModelSource and the per-model outputs are concatenated with a
model: Utf8 column stamped on each frame, so downstream chart
builders can route color="model" to render one curve per model.
The read-only BaseSource properties (X / y /
feature_names / capabilities) and their _-prefixed aliases
resolve to the first source's values — every wrapped source shares
X / y by construction in ModelSource.compare, so any one
will do. The proxied set is derived from BaseSource's property
descriptors (see _collect_compared_proxied_attrs), so a new public
property proxies automatically. Accessing model / _model raises
since there is no single estimator. model_names reports the
configured ordering. stack is the callable-form sibling of the
auto-dispatch, for chart builders that need to compose several
method calls (e.g. class selection before aggregation) before
stacking per-model frames.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sources
|
dict[str, ModelSource]
|
Mapping from model name (used for the |
required |
Examples:
>>> import ferrum as fm
>>> cms = fm.ModelSource.compare({"ridge": ridge, "lasso": lasso}, X, y)
>>> fm.roc_chart(cms) # overlay both curves
>>> cms.model_names
['ridge', 'lasso']
>>> cms.roc_curve() # long-form frame with `model` column
model_names
property
¶
Ordered list of model display names.
Returns the keys of the sources dict supplied at construction time,
in insertion order. Each name corresponds to the value written into the
model column on every derived-data DataFrame.
Returns:
| Type | Description |
|---|---|
list[str]
|
Model names in the order they were registered. |
items ¶
Ordered (name, ModelSource) pairs for each wrapped model.
The public accessor over the wrapped sources, in registration
order. Chart builders iterate this to compose one panel per model
without reaching into the private _sources mapping.
Returns:
| Type | Description |
|---|---|
list[tuple[str, ModelSource]]
|
|
stack ¶
Build one frame per wrapped model via frame_fn and stack them.
The callable-form sibling of the auto-dispatch in _dispatch:
_dispatch calls a fixed ModelSource method name per model,
while stack accepts an arbitrary per-model callable, for chart
builders that need to compose several method calls (e.g. class
selection before aggregation) before stacking. Both share the
same iteration-and-stamping idiom, in registration order, with a
model: Utf8 column recording each source's registered name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frame_fn
|
callable
|
|
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
Vertical concatenation of every model's frame with a trailing
|
ModelSource ¶
Bases: PredictionsMixin, ClassificationCurvesMixin, FeatureImportanceMixin, ModelSelectionMixin, ClusteringMixin, RankingMixin, BaseSource
Wrap a fitted estimator + dataset and expose model-diagnostic derived data as polars DataFrames.
Constructing a ModelSource is sklearn-free — only attribute
introspection runs at __init__ time. Derived-data methods that
need sklearn / shap lazy-import on call, so import ferrum
never pulls those packages into the user's process unless they
actually compute a diagnostic that requires them. (UMAP embeddings
run in Rust via _core.umap_embedding; there is no Python
umap dependency.)
Each derived-data method returns a long-form polars DataFrame
whose schema is documented in ferrum.diagnostics._internal.schemas —
chart builders and Visualizers consume the same frames.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
Any
|
A fitted estimator. Must expose at least |
required |
X
|
DataFrame | DataFrame | Table | ndarray
|
Feature matrix. Coerced internally to a polars DataFrame; any
|
required |
y
|
array - like
|
Target. Required by methods that depend on ground truth (every
method except |
None
|
feature_names
|
sequence of str
|
Column labels. Defaults to |
None
|
class_names
|
sequence of str
|
Per-class display labels for classification diagnostics.
Defaults to |
None
|
sample_weight
|
array - like
|
Per-row weights forwarded to sklearn scorers that accept them. |
None
|
random_state
|
int
|
Seed propagated to every derived-data method whose underlying compute consumes randomness (importances permutation, SHAP background sampling, UMAP / t-SNE / MDS embeddings, cross-validation curves, partial-dependence sampling). Deterministic methods ignore the value. |
None
|
Examples:
>>> import ferrum as fm
>>> source = fm.ModelSource(model, X, y, random_state=0)
>>> fm.roc_chart(source) # use directly with a figure function
>>> source.predictions() # access derived data as a DataFrame
>>> source.confusion_matrix(normalize="true")
X
property
¶
Feature matrix coerced to a polars DataFrame.
Returns the value supplied to __init__ (after coercion).
Use this for read-only access from chart builders and external
callers — source._X is an internal alias preserved for
back-compat.
y
property
¶
Target series, or None when no y was supplied.
Returns the polars Series the constructor coerced from the
y argument. None means unsupervised — methods that
need ground truth raise on call.
model
property
¶
The wrapped fitted estimator.
Returns the model object supplied at construction time unchanged.
Chart builders use it for occasional native introspection (e.g.
model.classes_, model.n_clusters); prefer the public
derived-data methods when one exists.
feature_names
property
¶
capabilities
property
¶
Protocol attributes present on the wrapped estimator.
A frozen subset of _PROTOCOL_ATTRS ("predict",
"predict_proba", "coef_", "feature_importances_", …)
detected at construction time via hasattr. Derived-data methods
gate on this set to pick the appropriate code path and raise
AttributeError with a clear message when a required attribute
is absent.
Returns:
| Type | Description |
|---|---|
frozenset[str]
|
Attribute names that are present on the wrapped model. |
predictions ¶
Return y_true, y_pred, residual, studentized_residual, cooks_distance, leverage.
leverage is the diagonal of the hat matrix
H = X (XᵀX)⁻¹ Xᵀ for linear estimators (those exposing
coef_); NaN otherwise. Used by the residuals-vs-leverage
panel of multi-panel residuals charts.
probabilities ¶
Return y_true + one column per class with predicted probability.
rank1d ¶
Univariate feature ranking.
The Shapiro-Wilk and variance algorithms operate on X alone;
"covariance" ranks features by absolute sample covariance with
y and therefore requires y to be present.
Output schema (SCHEMA_RANK1D): feature: Utf8,
score: Float64, rank: Int64. Rows are pre-sorted by descending
score so rank=1 is always the top feature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
algorithm
|
('shapiro', 'variance', 'covariance')
|
Univariate ranking statistic. |
"shapiro"
|
rank2d ¶
Pairwise feature ranking — long-form correlation matrix.
All algorithms run in Rust (Kendall uses Knight's O(n log n)).
Output schema (SCHEMA_RANK2D): feature_x: Utf8,
feature_y: Utf8, correlation: Float64 — one row per
ordered pair of features, p × p rows total.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
algorithm
|
('pearson', 'spearman', 'kendall', 'covariance')
|
Correlation / association statistic computed for each feature pair. |
"pearson"
|
silhouette ¶
Per-sample silhouette values, sorted within cluster descending.
Returns one row per sample with columns sample_id (original X
index), y_position (sequential 0..n-1 stack order — used by
mark_silhouette to render bars in a tightly-packed Rousseeuw
layout), cluster, and silhouette_value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
Informational cluster count. When provided, the result is
filtered to clusters in |
None
|
pca_variance ¶
Explained-variance ratio per principal component plus the cumulative running sum.
If the wrapped model exposes explained_variance_ratio_ (e.g.
sklearn.decomposition.PCA), reads it directly (backward compat).
Otherwise computes from raw X via Rust SVD.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_components
|
int
|
Truncate the result to the first |
None
|
embeddings ¶
Low-dimensional embedding of X via UMAP / t-SNE / PCA.
Returns dim_0 … dim_{n_components-1} plus a label column
(y when provided, else zeros — used to color the scatter).
random_state is taken from the source's random_state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
('umap', 'tsne', 'pca')
|
Dimensionality-reduction algorithm. |
"umap"
|
n_components
|
int
|
Number of embedding dimensions to emit ( |
2
|
**method_kwargs
|
Any
|
Algorithm-specific options forwarded to the Rust kernel.
|
{}
|
intercluster_distance ¶
2D embedding of cluster centers + cluster size.
Returns one row per cluster with cluster (Utf8 — a stringified
0..k-1 index, matching SCHEMA_INTERCLUSTER_DISTANCE and the
emitted column), x / y (Float64, the 2D embedded coordinate),
and size (Int64, sample count). Requires the wrapped model to
expose cluster_centers_.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
Number of clusters to embed. Clamped to the number of available
|
required |
method
|
('mds', 'tsne')
|
Embedding algorithm for projecting cluster centers to 2D.
|
"mds"
|
learning_curve ¶
Learning curve: score per (train_size, fold, split).
Returns long-form rows — one per (train_size, fold, split). Each
row carries the per-fold score plus the per-(train_size, split)
aggregates mean_score, std_score, lower, upper (95%
CI on the mean). Chart builders dedupe by (train_size, split) to
render a ribbon + line; the per-fold rows enable per-fold strip
overlays if a future caller wants them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cv
|
int
|
Number of cross-validation folds. |
5
|
scoring
|
str or callable
|
Scorer passed to sklearn's |
None
|
train_sizes
|
array - like
|
Training-set sizes (absolute or fractional) to evaluate.
Defaults to |
None
|
validation_curve ¶
Return validation-curve scores per (param_value, fold, split).
Same shape as learning_curve but parameterized by an estimator
hyperparameter sweep.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
param
|
str
|
Estimator hyperparameter to sweep — the kwarg name on the
wrapped estimator (e.g. |
required |
values
|
array - like
|
Hyperparameter values to evaluate. |
required |
cv
|
int
|
Number of cross-validation folds. |
5
|
scoring
|
str or callable
|
Scorer passed to sklearn's |
None
|
cv_scores ¶
Per-fold cross-validation scores.
Returns one row per (fold, split) — train and test scores for each cross-validation fold. Chart builders use this for boxplot / bar / strip distributions across folds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cv
|
int
|
Number of cross-validation folds. |
5
|
scoring
|
str or callable
|
Scorer passed to sklearn's |
None
|
alpha_selection ¶
Regularization-strength sweep for linear models.
Returns one row per (alpha, fold) — the per-fold test score on the
held-out split — plus per-alpha mean_score / std_score
aggregates. Chart builders dedupe by alpha to render a single
line, and use argmax(mean_score) to mark the best alpha.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alphas
|
array - like
|
Regularization strengths to evaluate. |
required |
cv
|
int
|
Number of cross-validation folds. |
5
|
scoring
|
str or callable
|
Scorer passed to the underlying sweep. |
None
|
importances ¶
importances(*, method: str = 'builtin', n_repeats: int = 30, scoring: Any = None, random_state: int | None = None) -> pl.DataFrame
Feature importance per feature, sorted by descending |importance|.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
('builtin', 'permutation')
|
|
"builtin"
|
n_repeats
|
int
|
Number of permutation repeats ( |
30
|
scoring
|
str or callable
|
Scorer passed to |
None
|
random_state
|
int
|
Seed for the permutation shuffles. Falls back to the source's
|
None
|
shap_values ¶
Long-form SHAP values per (sample, feature, class).
Returns a DataFrame with sample_id, feature, shap_value,
feature_value, feature_value_normalized, class_label.
- Regression:
class_labelis the constant"target"on every row. - Binary classifiers:
class_labelis the positive-class name on every row; SHAP values are for the positive class. - Multi-class classifiers: one row per (sample, feature, class);
class_labelcarries the class name. The result hasn_samples * n_features * n_classesrows total.
Explainer is auto-picked by model capability:
coef_:shap.LinearExplainer(deterministic, fast).feature_importances_:shap.TreeExplainer(deterministic for tree ensembles).- otherwise:
shap.KernelExplainer(model-agnostic).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
background
|
array - like
|
Background dataset for the model-agnostic
|
None
|
max_evals
|
int
|
Reserved for future use (no-op today). Participates only in the result cache key; not yet forwarded to the SHAP explainer. |
500
|
partial_dependence ¶
partial_dependence(features: list[str | int], *, grid_resolution: int = 100, kind: str = 'average') -> pl.DataFrame
Partial dependence per feature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
features
|
list of str or int
|
Feature names or column indices to compute partial dependence for. One set of rows is emitted per feature. |
required |
grid_resolution
|
int
|
Number of grid points sampled across each feature's range. |
100
|
kind
|
('average', 'individual', 'both')
|
|
"average"
|
roc_curve ¶
ROC curve(s). One row per (class, threshold). auc repeats per class.
For binary classifiers, returns a single curve on the positive (second) class. For multiclass, returns one-vs-rest curves per class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
average
|
(None, 'micro', 'macro', 'weighted')
|
Multiclass averaging. |
None
|
drop_intermediate
|
bool
|
Drop collinear ROC points that do not change the curve's shape
(sklearn's |
True
|
pr_curve ¶
Precision-recall curve(s). One row per (class, threshold).
For binary classifiers, returns a single curve on the positive
(second) class. For multiclass, average=None returns
one-vs-rest curves per class, while average in
{"micro", "macro", "weighted"} returns a single summary curve with
class="<average>" and no per-class rows. Macro / weighted
variants interpolate per-class precision over a shared recall grid
(100 points); micro ravels the binarized labels into one curve.
threshold is NaN at the final (recall=0) point of every
per-class curve per sklearn's convention. For macro / weighted
summaries it is NaN on every row (recall-grid interpolation
discards thresholds); micro follows sklearn's padding convention.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
average
|
(None, 'micro', 'macro', 'weighted')
|
Multiclass averaging strategy. Accepted but inert for binary classifiers, which have only one curve to draw. |
None
|
calibration_curve ¶
Calibration (reliability) curve for binary classifiers.
Returns one row per non-empty bin with mean_predicted,
fraction_positive, and count. Delegates to the
calibration_kernel Rust kernel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_bins
|
int
|
Number of bins used to group predicted probabilities. |
10
|
strategy
|
('uniform', 'quantile')
|
Bin-edge strategy (matches |
"uniform"
|
cumulative_gain ¶
Cumulative-gain curve per class. Appends a 2-row class='baseline'
diagonal for plotting reference.
lift_curve ¶
Lift curve per class. Appends a 2-row class='baseline' line at
lift=1.0.
discrimination_threshold ¶
Discrimination threshold sweep — binary classifiers only.
Sweeps n_thresholds evenly-spaced thresholds in [0, 1] and
reports precision, recall, F1, and queue_rate at each. queue_rate
is the hand-computed fraction (y_score >= t).mean().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_thresholds
|
int
|
Number of evenly-spaced thresholds swept across [0, 1]. |
50
|
cv
|
int or cross-validation splitter
|
When an int, runs the same sweep on each fold's held-out scores
from a freshly-cloned + re-fit estimator and averages
per-threshold metrics across folds. Pass a splitter object with
a |
None
|
confusion_matrix ¶
Confusion matrix in long form: one row per (actual, predicted) cell.
value is the (possibly normalized) count; value_fmt is a
stringified label suitable for mark_text overlay (integer counts
when unnormalized, two-decimal fractions when normalized).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
normalize
|
(None, 'true', 'pred', 'all')
|
Normalization mode. |
None
|
compare
classmethod
¶
Build a ComparedModelSource over one ModelSource per model.
Each value in models is wrapped in its own ModelSource with the
shared X and y. The returned ComparedModelSource proxies
every derived-data method through all wrapped sources and stamps the
model name as a model column on the concatenated output, so
downstream chart builders can route color="model".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
models
|
dict[str, Any]
|
Mapping from display name to fitted estimator. Each estimator is
wrapped in its own |
required |
X
|
array - like
|
Feature matrix shared by all models. Accepted types match
|
required |
y
|
array - like
|
Target shared by all models. Required by most derived-data
methods (same constraints as |
None
|
**kwargs
|
Any
|
Keyword arguments forwarded verbatim to each |
{}
|
Returns:
| Type | Description |
|---|---|
ComparedModelSource
|
Multi-model wrapper whose derived-data methods return long-form
DataFrames with an extra |
Examples: