TablePipeline
Note
This page is a reference documentation. It only explains the class signature, and not how to use it. Please refer to the Habitat Guide and Python API guide (v2.0) for usage.
- class TablePipeline(steps: Sequence[Any], model: Classifier | Regressor | SurvivalModel | None = None, *, classifier: Classifier | None = None, **pipeline_options: Any)[source]
Bases:
PipelineFitted preprocessing/selection chain plus model over feature tables.
The structural answer to the train/predict leakage class of bugs: the preprocessing and feature-selection steps are fitted ONCE on the training table and their fitted state is what
predict/transformapply to any later table – the prediction data is normalised with the TRAINING statistics and reduced with the TRAINING selection, never re-fitted.The fitted pipeline is also the artefact a study publishes for external validation of its tabular model, which is why
save()persists the steps and the model together in one versioned, self-describing file (a JSON manifest recording every component’sSpecalongside the pickled fitted state).This IS an ``sklearn.pipeline.Pipeline``. Subclassing rather than re-implementing composition is what gives HABIT’s tabular models
clone,get_params/set_params, nested parameter addressing and thereforeGridSearchCV/RandomizedSearchCV/cross_val_scorefor free, instead of a second composition engine that would drift from the one the rest of the ecosystem uses.Two consequences a caller must know:
.stepshas sklearn’s meaning –List[Tuple[str, estimator]], where the estimators are the interop adapters. It is NOT overridden, because sklearn’s_iter/_validate_steps/get_params/set_paramsall read and WRITE it directly. The HABIT components are reached throughcomponents(transformation steps) andmodel(the terminal one).The step list always begins with a
FrameToTablehead named"frame_to_table"and ends with the outcome-model adapter named"model". The head is what lets an sklearn cross-validation driver pass a plain frame asX(aFeatureTableis a frozen dataclass and deliberately not row-sliceable); when the pipeline is handed aFeatureTabledirectly – HABIT’s own entry point – it passes straight through, with no frame round-trip and therefore no dtype promotion that could shift a later z-score.
HABIT’s verbs are kept as overrides, because a
FeatureTablein must give a HABIT type out:fit(),transform(),predict()andpredict_proba()return tables / labelled Series / labelled frames forFeatureTableinput, and plain arrays for frame input (what an sklearn scorer expects).evaluate(),predict_survival_function(),set_random_state(),spec(),save()andload()have no sklearn equivalent and are unchanged.- Parameters:
steps – Either the HABIT form – ordered transformation components (
TablePreprocessorand/orFeatureSelectorimplementations), optionally preceded by aFrameToTabledeclaring the frame schema; may be empty, in which case the pipeline is the bare model – or the sklearn form[(name, estimator), ...], which is whatclone,set_params(steps=...)and slicing pass back in.model – The terminal outcome model – a
Classifier,Regressor, orSurvivalModel, matched to the endpoint family of the tables it will be fitted on. Must be omitted whenstepsis already in sklearn form (the terminal step carries it).classifier – Deprecated alias for
model(binary/multiclass endpoints); kept so existing call sites keep working.**pipeline_options – Forwarded verbatim to
sklearn.pipeline.Pipeline(memory,verbose, andtransform_inputon scikit-learn >= 1.6).
Examples
Nested hyperparameter search over a HABIT component’s own parameter:
from sklearn.model_selection import GridSearchCV from habit.pipeline.sklearn_interop import FrameToTable pipe = TablePipeline( steps=[FrameToTable.from_table(train), ZScorePreprocessor()], model=LogisticRegressionClassifier(), ) search = GridSearchCV(pipe, {"model__component__C": [0.1, 1, 10]}) search.fit(train.frame, outcome_series(train))
- __init__(steps: Sequence[Any], model: Classifier | Regressor | SurvivalModel | None = None, *, classifier: Classifier | None = None, **pipeline_options: Any) None[source]
- property components: Tuple[TablePreprocessor | FeatureSelector, ...]
Return the ordered HABIT transformation components.
This is the successor of the pre-v1.1
.stepsproperty..stepsnow means what sklearn means by it, so the HABIT components – the objects carryingspec, the fitted statistics and the selected column names – are read here instead. TheFrameToTablehead and the terminal model adapter are excluded: the head is interop plumbing, and the model ismodel.- Returns:
The unwrapped components, in execution order.
- Return type:
Tuple
- property model: Classifier | Regressor | SurvivalModel
Return the terminal outcome model.
- Returns:
The HABIT
Classifier/Regressor/SurvivalModel.- Raises:
HABITAPIError – When the pipeline does not end in a HABIT outcome model – which happens for a slice such as
pipe[:-1].
- property classifier: Classifier
Return the terminal model, asserted to be a classifier.
- property frame_schema: FrameToTable
Return the
FrameToTablehead step.The one place to read or re-declare the column schema an sklearn driver’s frames follow. Prefer
pipe.set_params(frame_to_table=FrameToTable.from_table(table))to replace it, so the change goes through sklearn’s own parameter machinery and survivesclone.- Raises:
HABITAPIError – When the pipeline has no
FrameToTablehead.
- property spec: Spec
Return the composed specification of every stage.
The payload shape –
{"steps": [...], "model": {...}}– is the FINGERPRINTED one and is deliberately unchanged by the move tosklearn.pipeline.Pipeline: theFrameToTablehead and the adapters are interop plumbing, not scientific definition, so they do not appear. Renaming or reshaping this payload would move every recorded provenance fingerprint in the repository.- Raises:
HABITAPIError – When a step carries no
Spec, i.e. the pipeline holds a foreign estimator that HABIT cannot describe.
- set_random_state(seed: int) None[source]
Seed every stochastic component of the pipeline.
Propagates to each transformation component and the terminal model implementing
Seedable; deterministic components are untouched (v1.0 naming decisions: one seeding verb, never a constructor parameter).- Parameters:
seed – The seed to install.
- fit(X: Any, y: Any | None = None, *, repeat_tables: Sequence[FeatureTable] | None = None, **params: Any) TablePipeline[source]
Fit every step in order, then the terminal model.
Each step is fitted on the table produced by the previous step, so learned statistics compose exactly as they will at predict time.
- Parameters:
X – Training data. A
FeatureTable(HABIT’s entry point: the outcome rides inside it and passes through the head step untouched) or a plain frame carrying the identifier, feature and outcome columns theFrameToTablehead declares.y – Training targets. Normally
Nonefor aFeatureTable, whose outcome column already supplies them; sklearn’s cross-validation drivers pass the sliced label array, which is cross-checked against the table’s own outcome so a misalignedyfails loudly.repeat_tables – Optional aligned repeat-measurement tables. Routed ONLY to the steps whose
fitdeclaresrepeat_tables(the test-retest / ICC selectors); the rest never see the keyword.**params – scikit-learn step-scoped fit parameters in
stepname__paramform, forwarded unchanged.
- Returns:
self, fitted.
- transform(X: Any, **params: Any) FeatureTable[source]
Apply the fitted transformation chain to a table.
Deliberately narrower than
sklearn.pipeline.Pipeline.transform, which also calls the FINAL step: aTablePipelinealways ends in an outcome model, which has notransform, so sklearn’s version is never available on this class anyway. What callers have always meant bypipeline.transform(table)– “the classifier-ready table” – is what this returns.- Parameters:
X – Table (or frame) carrying the feature columns seen at fit time; each fitted step validates its own input schema.
**params – Accepted for signature compatibility; must be empty.
- Returns:
The table after every fitted transformation step.
- Return type:
- Raises:
HABITAPIError – If the pipeline is not fitted, or
paramsis non-empty (per-step transform parameters would silently do nothing here).
- predict(X: Any, **params: Any) Any[source]
Predict the terminal model’s output for a table’s rows.
Class labels for a classifier, values for a regressor, risk scores for a survival model (routed through
predict_risk).- Parameters:
X – Data to predict; transformed with the fitted state first.
**params – scikit-learn predict parameters, forwarded to the terminal adapter on the array path only.
- Returns:
pd.Seriesindexed by the table’s identifier columns forFeatureTableinput (HABIT semantics), or a plainndarrayfor frame input, which is what an sklearn scorer expects.
- predict_proba(X: Any, **params: Any) Any[source]
Predict class probabilities for a table’s rows.
Only meaningful for a classifier terminal model; regressors and survival models have no class-probability output.
- Parameters:
X – Data to predict; transformed with the fitted state first.
**params – scikit-learn predict parameters, forwarded to the terminal adapter on the array path only.
- Returns:
A probability frame indexed by the identifier columns, one column per class, for
FeatureTableinput; a plainndarraywith columns aligned toself.classes_for frame input.- Raises:
HABITAPIError – If the terminal model is not a classifier.
- predict_survival_function(table: FeatureTable, times: ndarray) DataFrame[source]
Predict per-subject survival functions at the requested times.
- Parameters:
table – Table to predict; transformed with the fitted state first.
times – Ascending 1-D grid of evaluation times.
- Returns:
Survival probabilities, one row per subject, one column per time.
- Raises:
HABITAPIError – If the terminal model is not a survival model.
- evaluate(table: FeatureTable, metrics: Sequence[Metric | RegressionMetric | SurvivalMetric]) Dict[str, float][source]
Score the pipeline on a labelled table.
Dispatches by the table’s endpoint family:
binary / multiclass – classification
Metricobjects; probability metrics receive the positive-class scores (column"1"for a 0/1 outcome, else the last class column).continuous –
RegressionMetricobjects on (true, predicted).survival –
SurvivalMetricobjects; risk-based metrics getpredict_risk, function-based ones getpredict_survival_functionevaluated on a grid derived from the follow-up range.
- Parameters:
table – Evaluation table carrying the endpoint column(s).
metrics – Metrics to compute, keyed in the result by
metric.spec.name. Must match the endpoint family.
- Returns:
Mapping of metric name to value.
- Raises:
HABITAPIError – If
metricsis empty, the table has no endpoint, or a metric family does not match the endpoint.
- save(path: str | Path) Path[source]
Persist the fitted pipeline in a versioned, self-describing format.
The
.habitpipelinefile is a ZIP archive holding a JSON manifest (format name, format version, producing HABIT version, and every component’s spec and class path) plus the pickled fitted state. The manifest keeps the artefact inspectable without deserialising it.What is pickled is the HABIT COMPONENTS, not the sklearn adapters wrapping them: the components are the fitted science, the adapters are interop plumbing that
load()rebuilds. Keeping the payload at the component level is also what lets one loader read both format version 1 (written before this class became ansklearn.pipeline.Pipeline) and version 2.- Parameters:
path – Destination file path.
- Returns:
The path written.
- classmethod load(path: str | Path) TablePipeline[source]
Load a pipeline previously written by
save().Version 3 is the first v2 archive format. Versions 1 and 2 pickle v1
habit.domainclasses, so they are explicitly rejected before unpickling with migration guidance. A file whoseformat_versionthis build does not know is never guessed at: silently loading a wrong-but-plausible pipeline would produce numbers nobody could trace.Security note: the fitted state is pickle-serialised (the standard serialisation for sklearn estimators), so only ever load pipeline files from sources you trust.
- Parameters:
path – Source file path.
- Returns:
The loaded pipeline, fitted exactly as when saved.
- Raises:
CompatibilityError – If the file is not a HABIT table pipeline, was written with a newer format version, or its manifest does not match its payload.
- set_fit_request(*, repeat_tables: bool | None | str = '$UNCHANGED$') TablePipeline
Request metadata passed to the
fitmethod.Note that this method is only relevant if
enable_metadata_routing=True(seesklearn.set_config()). Please see User Guide on how the routing mechanism works.The options for each parameter are:
True: metadata is requested, and passed tofitif provided. The request is ignored if metadata is not provided.False: metadata is not requested and the meta-estimator will not pass it tofit.None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.str: metadata should be passed to the meta-estimator with this given alias instead of the original name.
The default (
sklearn.utils.metadata_routing.UNCHANGED) retains the existing request. This allows you to change the request for some parameters and not others.Added in version 1.3.
Note
This method is only relevant if this estimator is used as a sub-estimator of a meta-estimator, e.g. used inside a
Pipeline. Otherwise it has no effect.
- set_score_request(*, sample_weight: bool | None | str = '$UNCHANGED$') TablePipeline
Request metadata passed to the
scoremethod.Note that this method is only relevant if
enable_metadata_routing=True(seesklearn.set_config()). Please see User Guide on how the routing mechanism works.The options for each parameter are:
True: metadata is requested, and passed toscoreif provided. The request is ignored if metadata is not provided.False: metadata is not requested and the meta-estimator will not pass it toscore.None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.str: metadata should be passed to the meta-estimator with this given alias instead of the original name.
The default (
sklearn.utils.metadata_routing.UNCHANGED) retains the existing request. This allows you to change the request for some parameters and not others.Added in version 1.3.
Note
This method is only relevant if this estimator is used as a sub-estimator of a meta-estimator, e.g. used inside a
Pipeline. Otherwise it has no effect.