Ensembles¶
Meta-imputers that chain or combine other imputers.
Meta-imputers that combine or chain other imputers.
HybridImputer
¶
HybridImputer(methods: list[BaseImputer] | None = None)
Bases: BaseImputer
Hybrid imputation combining multiple methods with fallback chain.
Tries multiple imputation methods in sequence, falling back to simpler methods if earlier methods fail or produce NaNs. Robust for diverse data.
Strategy Pattern: This imputer implements a cascading fallback strategy where sophisticated methods are tried first, with progressively simpler methods as fallbacks. This approach combines the advantages of multiple methods while ensuring robustness.
Use Cases: - Heterogeneous data: Different columns may need different approaches - Unknown data patterns: Not sure which method will work best - Production systems: Need guaranteed imputation without failures - Exploratory analysis: Want to leverage multiple strategies
Design Principles: 1. Graceful degradation: Complex methods → Simple methods → Always succeed 2. Error resilience: Method failures don't crash the pipeline 3. Early stopping: Stop once all NaNs are filled (efficiency) 4. Completion: A final mean fill covers any NaNs the chain left, except in columns with no observed values, which stay NaN
Recommended Method Ordering: 1. Domain-specific (if applicable): Business rules, external data 2. Sophisticated: ML-based (MICE, MissForest, etc.) 3. Moderate: Statistical (interpolation, regression) 4. Simple: Basic stats (mean, median)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
methods
|
list[BaseImputer] | None
|
List of imputer instances to try in order. Methods should be ordered from most sophisticated/specific to simplest/most general. Default: [InterpolationImputer(), MeanImputer()] |
None
|
Examples:
>>> import pandas as pd
>>> import numpy as np
>>> from imputation_methods import (
... HybridImputer, InterpolationImputer,
... MovingAverageImputer, MeanImputer
... )
>>> df = pd.DataFrame({'a': [1, np.nan, np.nan, 4, np.nan]})
>>> # Cascade: interpolation → moving average → mean
>>> imputer = HybridImputer(methods=[
... InterpolationImputer(), # Try smooth interpolation first
... MovingAverageImputer(window=2), # Fall back to local average
... MeanImputer() # Final fallback: global mean
... ])
>>> imputed = imputer.impute(df)
Notes
- Each method sees the output of the previous method
- If a method fills all NaNs, subsequent methods are skipped
- Exceptions in individual methods are caught and logged
- A final column-mean fill covers any NaNs the chain left. Columns with no
observed values stay NaN; add
ConstantImputerto the chain if you want to fill them with a fixed value
References
Ensemble and cascading strategies for robust machine learning.
Initialize the hybrid imputer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
methods
|
list[BaseImputer] | None
|
List of imputer instances to try in order |
None
|
Source code in src/imputation_methods/ensemble.py
impute
¶
Impute using hybrid fallback chain.
Execution Flow: 1. Start with original data 2. For each method in the chain: - Check if NaNs remain - If yes: try the method - If method succeeds: use its output - If method fails: log warning and try next - If no NaNs remain: stop (early exit) 3. Final safety check: mean fallback for any remaining NaNs
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame
|
Dataframe with missing values. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
Imputed dataframe. NaNs remain only in columns that have no observed |
DataFrame
|
values. |
Source code in src/imputation_methods/ensemble.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | |
StackingImputer
¶
StackingImputer(base_imputers: list[BaseImputer] | None = None, meta_strategy: str = 'mean')
Bases: BaseImputer
Ensemble imputer that combines the outputs of several base imputers.
Every base imputer is run on the same input and their completed dataframes are combined cell by cell. Observed values are identical in every output, so only the imputed cells are affected.
How It Works:
1. Run each base imputer on the dataset (failing imputers are skipped)
2. Combine the completed dataframes with meta_strategy:
- "mean": element-wise average
- "median": element-wise median, robust to one bad imputer
- "weighted": reserved for learned weights; currently the same as
"mean"
Why Stacking Works: - Reduces variance through ensemble averaging - Exploits diversity: Different imputers capture different patterns - More robust than any single method alone - Can outperform individual imputers, especially with complementary methods
Recommended Base Imputer Combinations: - Simple + Complex: [MeanImputer, KNNImputer, RegressionImputer] - Robust mix: [MedianImputer, HuberImputer, TrimmedMeanImputer] - Diverse approaches: [MeanImputer, MICEImputer, MissForestImputer]
When to Use: - When no single imputation method is clearly best - For production systems requiring robust performance - When computational cost is acceptable (runs K imputers) - With heterogeneous data (different columns need different methods)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_imputers
|
list[BaseImputer] | None
|
List of base imputer instances to stack. Default: [MeanImputer(), MedianImputer()] |
None
|
meta_strategy
|
str
|
How to combine predictions ('mean', 'median', 'weighted'). Default: 'mean' |
'mean'
|
Examples:
>>> import pandas as pd
>>> import numpy as np
>>> from imputation_methods import (
... StackingImputer, MeanImputer, MedianImputer, KNNImputer
... )
>>> df = pd.DataFrame({'a': [1, 2, np.nan, 4, 5]})
>>> imputer = StackingImputer(base_imputers=[
... MeanImputer(),
... MedianImputer(),
... KNNImputer(n_neighbors=2)
... ])
>>> imputed = imputer.impute(df)
References
Wolpert, D. H. (1992). Stacked generalization. Ensemble learning approach applied to imputation.
Initialize the stacking imputer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_imputers
|
list[BaseImputer] | None
|
List of base imputers |
None
|
meta_strategy
|
str
|
Strategy for combining predictions |
'mean'
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If meta_strategy is invalid |
Source code in src/imputation_methods/ensemble.py
impute
¶
Impute using stacking ensemble.
Executes all base imputers in parallel and combines their predictions using the specified meta-strategy. This approach leverages the wisdom of crowds - multiple diverse predictions are often better than a single prediction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame
|
Dataframe with missing values. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
Imputed dataframe. |
Source code in src/imputation_methods/ensemble.py
BaggingImputer
¶
BaggingImputer(base_imputer: BaseImputer | None = None, n_estimators: int = 10, max_samples: float = 0.8, random_state: int | None = None)
Bases: BaseImputer
Bootstrap aggregating (bagging) of a base imputer.
Each of the n_estimators runs draws a bootstrap sample of the rows (with
replacement), imputes that sample with its own copy of base_imputer, and
records the values imputed for the rows it contains. Every missing cell is
then set to the average of the values imputed for its row across all runs
whose sample included that row. Averaging over resampled data reduces the
variance of unstable imputers.
Sampled rows keep their original order, so order-dependent imputers such as
:class:~imputation_methods.LOCFImputer still see a time-ordered sequence.
Base imputers that accept random_state get a different seed for every
run, derived from this imputer's random_state. Cells whose row was never
sampled are filled by running base_imputer once on the full data.
Good base imputers for bagging: high-variance methods such as
:class:~imputation_methods.KNNImputer,
:class:~imputation_methods.RegressionImputer or
:class:~imputation_methods.PMMImputer. Simple statistics such as the mean
gain little.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_imputer
|
BaseImputer | None
|
Imputer applied to each bootstrap sample.
Default: |
None
|
n_estimators
|
int
|
Number of bootstrap samples. Default: 10 |
10
|
max_samples
|
float
|
Size of each bootstrap sample as a fraction of the number of rows. Default: 0.8 |
0.8
|
random_state
|
int | None
|
Seed for the bootstrap samples and the base imputer seeds. Default: None |
None
|
Examples:
>>> import numpy as np
>>> import pandas as pd
>>> from imputation_methods import BaggingImputer, KNNImputer
>>> df = pd.DataFrame(
... {
... "a": [1, 2, np.nan, 4, 5, np.nan, 7],
... "b": [2, 4, 6, np.nan, 10, 12, 14],
... }
... )
>>> imputer = BaggingImputer(
... base_imputer=KNNImputer(n_neighbors=2), n_estimators=5, random_state=0
... )
>>> bool(imputer.impute(df).notna().all().all())
True
References
Breiman, L. (1996). Bagging predictors. Machine Learning, 24(2), 123-140.
Initialize the bagging imputer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_imputer
|
BaseImputer | None
|
Imputer applied to each bootstrap sample. |
None
|
n_estimators
|
int
|
Number of bootstrap samples. |
10
|
max_samples
|
float
|
Bootstrap sample size as a fraction of the rows. |
0.8
|
random_state
|
int | None
|
Seed for sampling and base imputer seeds. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/imputation_methods/ensemble.py
impute
¶
Impute using bootstrap aggregating.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame
|
Dataframe with missing values. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
Imputed dataframe with float columns. Cells the base imputer cannot |
DataFrame
|
fill (for example in a column with no observed values) stay NaN. |