Skip to content

Migrate WoEEncoder to narwhals, add polars support - #1032

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

Migrate WoEEncoder to narwhals, add polars support#1032
solegalli wants to merge 2 commits into
narwhals-migrationfrom
narwhals-woe-encoder

Conversation

@solegalli

Copy link
Copy Markdown
Collaborator

Migrates WoEEncoder to narwhals with polars support.

fit() splits by backend: pandas keeps _calculate_woe()'s existing two-groupby implementation unchanged (it's directly unit-tested for that exact pandas-Series-with-category-index contract); polars/other narwhals backends use one group_by(), deriving the negative-class count as the complement of the positive-class count per category — benchmarked competitive with, and often faster than, pandas-native at 50k–100k rows. Zero-count-per-class fill_value handling preserved exactly.

Bug fix: _check_fit_input() assumed y was always a pandas Series (y.nunique()/y.min()/y.max()), breaking on a numpy y (list/array-like target, which sklearn's check_X_y converts via column_or_1d). Wrapped numpy y into a narwhals Series aligned to X's backend; for pandas, also aligned it to X's actual index, since _calculate_woe()'s y.groupby(X[var]) aligns by index and a mismatched default RangeIndex silently drops every row instead of raising, leaving encoder_dict_ empty. Fixes test_encoders_when_x_pandas_y_numpy's WoEEncoder case (was failing on the unmigrated file — confirmed pre-existing).

Verified: 44/44 own tests; full encoding suite 342 passed / 16 failed (was 17 pre-existing on the narwhals-encoding-base baseline — one fewer here since this branch's own numpy-y bug is now fixed, rest confirmed unrelated). flake8 / mypy clean, sphinx -W clean.


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

fit() splits by backend: pandas keeps _calculate_woe()'s existing
two-groupby implementation unchanged (it's directly unit-tested for that
exact pandas-Series-with-category-index contract); polars/other narwhals
backends use one group_by() instead of two, deriving the negative-class
count as the complement of the positive-class count per category -
benchmarked competitive with, and often faster than, pandas-native at
50k-100k rows. Zero-count-per-class fill_value handling preserved exactly.

Bug fix: _check_fit_input() previously assumed y was always a pandas
Series (y.nunique()/y.min()/y.max()), breaking on a numpy y (e.g. a plain
list/array-like target, which sklearn's check_X_y machinery converts via
column_or_1d). Wrapped numpy y into a narwhals Series aligned to X's
backend; for pandas specifically, also had to line the wrapped Series up
with X's actual index, since _calculate_woe()'s y.groupby(X[var]) aligns
by index and a mismatched default RangeIndex silently drops every row
instead of raising, leaving encoder_dict_ empty. Fixes
test_encoders_when_x_pandas_y_numpy's WoEEncoder case (was failing on the
unmigrated file, confirmed pre-existing).

Verified: 44/44 own tests, full encoding suite 342 passed/16 failed (was
17 pre-existing on the narwhals-encoding-base baseline - one less here
since this branch's own numpy-y bug is now fixed, rest confirmed
unrelated), flake8 and mypy clean, sphinx -W build clean (only the
pre-existing unrelated linkcode_resolve warning).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@solegalli
solegalli force-pushed the narwhals-woe-encoder branch from b1b7c2f to 6505e37 Compare August 30, 2026 22:48
check_X_y now returns a narwhals frame. In _check_fit_input, bind that to
nw_X and keep the original native X: the nwd.is_pandas_dataframe(X) check,
the native_y.index = X.index alignment and the returned X all need native
input, and fit()'s pandas _calculate_woe fast path and nwd checks are then
unchanged (X stays native so no rehydration is needed). Take the y-series
backend from nw_X.implementation instead of re-wrapping X. In transform(),
bind _check_transform_input_and_state to nw_X, keep native X for
_check_contains_na, and pass nw_X to _encode (which now expects narwhals).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@solegalli
solegalli force-pushed the narwhals-woe-encoder branch from 6505e37 to 2397f9a Compare August 30, 2026 22:52
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