Skip to content

Migrate CyclicalFeatures to narwhals, add polars support - #991

Merged
solegalli merged 3 commits into
narwhals-migrationfrom
narwhals-cyclical-features
Aug 24, 2026
Merged

Migrate CyclicalFeatures to narwhals, add polars support#991
solegalli merged 3 commits into
narwhals-migrationfrom
narwhals-cyclical-features

Conversation

@solegalli

@solegalli solegalli commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

fit(): unified across backends via .to_numpy().max(axis=0) instead of
pandas' .max().to_dict() (~1.55x faster for pandas, ~1.28x for polars,
benchmarked). .tolist() keeps the returned dict's values as plain Python
int/float, matching the old .to_dict() dtype.

transform(): kept as two branches rather than one narwhals-only path -
benchmarked running narwhals expressions against a pandas-backed frame and
it was consistently 1.24x-2.06x slower than the pandas-native loop across
variable counts and row counts, worse at small scale. The pandas branch is
therefore left as the original, unmodified loop (an earlier numpy-vectorized
version of it was only a 1.0x-1.4x gain, not worth it once the branches
stay separate anyway). The narwhals branch uses column expressions, the
only approach that stayed competitive with pandas-native as variable count
grows (a numpy-array round-trip loses to expressions on polars once there
is more than 1 variable).

Verified no legacy numpy-array-input code remains in this file or its base
classes. Tests rewritten to parametrize pandas and polars via make_df;
error-matching tightened per AGENTS.md except where the message
legitimately differs by backend. Docstring and user-guide example gained a
polars walkthrough per the new AGENTS.md doc-sync rule.
Style: removed the now-unused narwhals.dependencies import (flake8 F401)
left over from dropping the is_pandas_dataframe branch. Also fixed 7
pre-existing flake8 issues (line length, unused variable) in
test_get_feature_names_out_mixin.py that predate this branch.

Docs: docs/user_guide/creation/CyclicalFeatures.rst's polars output block
was under `.. code:: python`, and Sphinx's Pygments highlighter can't lex
the box-drawing table as Python (misc.highlighting_failure), which -W
promotes to a build error. Switched to `.. code:: text`, matching the
convention already used elsewhere (PowerTransformer.rst, MeanImputer.rst)
for output-only blocks. Pre-existing bug in my own doc addition, unrelated
to the branch unification.

Two correctness issues surfaced by testing the unification:
- max_values_ lost its .tolist() call, so it held numpy scalars
  (np.int64) instead of plain Python int/float - restored.
- narwhals' .select([]) collapses row count to 0 (not just columns),
  so routing pandas through the narwhals numpy path broke
  return_empty=True (empty variables_) with a "zero-size array to
  reduction operation maximum" error. Guarded for it explicitly, since
  return_empty=True is a real, designed-for case, not a hypothetical.
@solegalli
solegalli merged commit 0d32d83 into narwhals-migration Aug 24, 2026
4 of 10 checks passed
@solegalli
solegalli deleted the narwhals-cyclical-features branch August 24, 2026 17:02
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