fix(imputer): keep all-NaN columns instead of crashing (#124) - #257
fix(imputer): keep all-NaN columns instead of crashing (#124)#257jaideeppyne wants to merge 3 commits into
Conversation
`imputer` with the default `placeholder_value=None` crashed whenever any column in `columns_to_impute` was entirely NaN in the training data. scikit-learn's SimpleImputer silently drops all-NaN features on `fit`, so at transform time the output had fewer columns than `columns_imputable` and `pd.DataFrame(data=new_data, columns=columns_imputable)` raised `ValueError: Shape of passed values ... indices imply ...`. Passing `keep_empty_features=True` (scikit-learn >= 1.2, within the pinned range) keeps those columns and imputes a default value (0), matching the behaviour requested in the issue. The explicit `placeholder_value` path is unaffected, since all-NaN columns are split off into `columns_to_fill` there. Adds a regression test covering the default-placeholder all-NaN case.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR addresses a regression where imputer crashed when columns_to_impute contained an entirely-NaN column and placeholder_value=None, by ensuring empty features are preserved during imputation.
Changes:
- Added a regression test covering all-NA columns with default
placeholder_value=None. - Updated
SimpleImputerinitialization to keep empty features instead of dropping them.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/training/test_imputation.py | Adds regression test to verify all-NA columns are retained and imputed (defaulting to 0.0). |
| src/fklearn/training/imputation.py | Configures SimpleImputer to retain empty/all-NA features during fit/transform. |
Suppressed comments (1)
src/fklearn/training/imputation.py:42
- With
keep_empty_features=True, the behavior for entirely-NA columns changes even whenplaceholder_value=None(they are no longer dropped and will be imputed with a default value per scikit-learn behavior). The docstring currently implies onlyplaceholder_valuecontrols the behavior for all-NA features; please update this docstring to reflect the new default behavior and how callers can control it (e.g., usingplaceholder_value/strategy='constant').
placeholder_value : Any, (default=None)
if not None, use this as default value when some features only contains
NA values on training. For transformation, NA values on those features
will be replaced by `fill_value`.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Thanks for the review. Addressing both points:
|
…rt true per-strategy behavior Address Copilot review on nubank#257: 1. keep_empty_features requires scikit-learn>=1.2; fklearn's declared floor is scikit-learn>=1.5, so it is always available and no version guard / TypeError fallback is needed. Documented this at the call site. (A silent fallback constructing SimpleImputer without keep_empty_features would just reintroduce the nubank#124 crash on unsupported sklearn.) 2. Correct the parametrized all-NaN regression test. keep_empty_features affects each strategy's handling of fully-missing columns differently: an all-None column is object-dtyped, so mean/median fill the empty feature with 0.0 while most_frequent (no modal value) keeps it as a NaN/None sentinel. The previous test asserted a uniform 0.0 and failed for most_frequent. Assert the concrete per-strategy behavior; the nubank#124 fix (column preserved, no crash) holds for all three.
|
Thanks @copilot — both addressed in 1af7688: 1. 2. Cover |
What
Fixes #124.
imputerwith the defaultplaceholder_value=Nonecrashes whenever any column incolumns_to_imputeis entirely NaN in the training data.Why
scikit-learn's
SimpleImputersilently drops all-NaN features duringfit. So at transform timeimp.transform(...)returns fewer columns thancolumns_imputable, and:raises
ValueError: Shape of passed values is (N, k-1), indices imply (N, k).Minimal repro on current
master:The existing
placeholder_valuemechanism only rescues all-NaN columns when a placeholder is explicitly supplied; the default code path routes every column (including all-NaN ones) intocolumns_imputableand breaks.How
Pass
keep_empty_features=TruetoSimpleImputer(available since scikit-learn 1.2, within the pinned>=1.5,<1.8range). This keeps all-NaN features in the output and imputes them with a default value (0), matching the behaviour requested in the issue. The explicitplaceholder_valuepath is unaffected — all-NaN columns are split off intocolumns_to_fillthere, so the flag is a no-op for it.Tests
test_imputer_all_na_column_without_placeholder— asserts an all-NaN column with the defaultplaceholder_value=Noneis imputed to0.0(both in the training output and on new data) instead of raising.tests/training/test_imputation.pystill passes (test_imputer_with_fill_valueconfirms theplaceholder_valuepath is unchanged).Disclosure: this change was prepared with AI assistance and reviewed/verified by me before submission.