Skip to content

Migrate OneHotEncoder to narwhals, add polars support - #1028

Open
solegalli wants to merge 2 commits into
narwhals-migrationfrom
narwhals-one-hot-encoder
Open

Migrate OneHotEncoder to narwhals, add polars support#1028
solegalli wants to merge 2 commits into
narwhals-migrationfrom
narwhals-one-hot-encoder

Conversation

@solegalli

Copy link
Copy Markdown
Collaborator

Migrates OneHotEncoder to narwhals with polars support.

Uses narwhals' to_dummies() for the expansion rather than a manual numpy/dict loop (it's a real vectorized one-hot op on both backends). Two edge cases to_dummies() doesn't cover directly:

  • A fixed-length prefix placeholder ("__ohe_tmp__") swapped back out by slicing, not by the real column name: to_dummies() only prefixes with the Series name when it's truthy, so a falsy real name (e.g. an int column literally named 0) would silently drop the prefix.
  • Learned categories absent from a given transform batch get an explicit all-0 column, so unseen categories encode as 0 across the board — matching pre-narwhals behaviour exactly.

fit()'s value_counts()/unique() and transform()'s reassembly are a single unified narwhals path — no pandas/polars split, verified identical dummy columns/values on both backends for identical input.

Tests rewritten to the cross-backend-parametrized convention (local dict fixtures over make_df in [pd.DataFrame, pl.DataFrame], narwhals-based column/sum assertions). test_variables_cast_as_category stays pandas-only.

Verified: 43/43 own tests; full encoding suite 340 passed / 17 pre-existing failures (matches the narwhals-encoding-base baseline exactly); flake8 / mypy clean; sphinx -W clean; no pandas import in this file.


Stacked on #999 (narwhals-encoding-base). Until that merges this PR's diff also contains the shared CategoricalMethodsMixin commit; review #999 first.

solegalli and others added 2 commits August 31, 2026 00:09
Uses narwhals' to_dummies() for the actual expansion rather than a manual
numpy/dict loop, since it's a real vectorized one-hot op on both backends.
Handles two edge cases to_dummies() doesn't cover directly: a fixed-length
prefix placeholder ("__ohe_tmp__") swapped back out by slicing rather than
by using the real column name, since to_dummies() only prefixes with the
Series name when it's truthy - a falsy real name (e.g. an int column
literally named 0) would otherwise silently drop the prefix; and learned
categories absent from (or present-but-unlearned in) a given transform
batch, filled with an explicit all-0 column so unseen categories are
encoded as 0 across the board, matching the pre-narwhals behavior exactly.

fit()'s value_counts()/unique() calls and transform()'s reassembly are a
single unified narwhals path - no pandas/polars split needed, verified
directly on both backends (identical dummy columns/values for identical
input).

Rewrote tests/test_encoding/test_onehot_encoder.py to the single
cross-backend-parametrized-test convention: local dict fixtures (dropping
the pandas-only global df_enc_big/df_enc_numeric/df_enc_binary fixtures)
parametrized over make_df in [pd.DataFrame, pl.DataFrame], with narwhals-
based column/sum assertions replacing pd.testing.assert_frame_equal.
test_variables_cast_as_category stays pandas-only (pandas category dtype
has no polars equivalent under test there).

Verified: 43/43 own tests, full encoding suite 340 passed/17 pre-existing
failures (matches the narwhals-encoding-base baseline exactly), flake8
and mypy clean, sphinx -W build clean (only the pre-existing unrelated
linkcode_resolve warning), no pandas import in this file itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bind check_X / _check_transform_input_and_state results to nw_X and keep
the original native X for _check_or_select_variables, _check_contains_na
and _get_feature_names_in (those helpers still expect native input,
matching the CategoricalImputer migration on narwhals-migration). Drop
the now-redundant nw.from_native(X) round-trips in fit() and transform();
they reuse the narwhals frame returned by check_X /
_check_transform_input_and_state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@solegalli
solegalli force-pushed the narwhals-one-hot-encoder branch from 630817c to 54d6c81 Compare August 30, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant