Skip to content

fix(preprocessor): keep the internal ColumnTransformer on default output - #114

Open
ChrisW09 wants to merge 1 commit into
mainfrom
fix/76-transform-output-pandas
Open

ChrisW09 wants to merge 1 commit into
mainfrom
fix/76-transform-output-pandas

Conversation

@ChrisW09

@ChrisW09 ChrisW09 commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #76.

With scikit-learn's global output set to pandas or polars (sklearn.set_config(transform_output="pandas")), a Preprocessor that one-hot encodes a column (categorical_method="one-hot", a "one-hot" entry in feature_preprocessing, or preset="expanded") failed in fit with "Pandas output does not support sparse data". A one-hot Preprocessor fitted before the setting was switched on failed the same way in transform.

Root cause

Preprocessor.fit built and fitted its internal ColumnTransformer without an output configuration of its own, so the global transform_output applied to it and to every step inside it. The one-hot steps use a OneHotEncoder with the default sparse_output=True, and scikit-learn refuses pandas and polars output for sparse data. sparse_output is not exposed through Preprocessor, so users had no way around it other than switching the global setting off.

Fix

  • Preprocessor.fit calls self.column_transformer_.set_output(transform="default") before fitting the internal ColumnTransformer. This also pins its steps, so they always produce plain arrays and the global setting no longer reaches them. The configuration is stored on the fitted ColumnTransformer, so transform of a Preprocessor fitted before the global setting was switched on works as well.
  • Preprocessor.transform is unchanged: it still reads the requested container from its own output configuration (set_output or the global setting) and builds the pandas or polars frame from the stacked array itself, so it keeps returning a DataFrame under the global setting.

Behaviour changes

  • Under a global transform_output="pandas" or "polars", one-hot encoding and preset="expanded" now fit, and transform returns a float64 DataFrame with the get_feature_names_out() columns and the same values as with the default configuration.
  • fingerprint_ of a newly fitted Preprocessor changes, because the fitted internal ColumnTransformer now records its output configuration. The transformed output is unchanged, and no golden regression baseline pins a fingerprint.

Documentation

  • docs/core_concepts/outputs_and_inspection.md ("DataFrame output"): a global sklearn.set_config(transform_output=...) is honoured like set_output and applies to the Preprocessor's own output only; the internal per-column steps always produce arrays, so every method, including the sparse one-hot encoding, works under it.
  • Preprocessor.transform docstring (Returns): the pandas / polars DataFrame is also returned under the global setting, which applies to this output only.
  • The README and the docs homepage do not describe the global output setting, so they are unchanged.

Tests

  • test_one_hot_works_under_a_global_pandas_output_config[options0, options1] (categorical_method="one-hot", preset="expanded"): inside sklearn.config_context(transform_output="pandas"), fit and transform return a DataFrame with the get_feature_names_out() columns, all float64, and values equal to the default-configuration output. Fails on main (raises), passes here.
  • test_global_polars_output_config_is_honoured: the same under transform_output="polars": a polars frame with the right column names and values (skipped when polars is not installed). Fails on main (raises), passes here.

Reproduction

Output of the script from #76 on this branch. The loop also calls transform and prints the output type, shape and dtypes, and the script adds the two other cases from the description: transform of a one-hot Preprocessor fitted before the global setting was switched on, and transform_output="polars".

(40, 8)
{'categorical_method': 'one-hot'} -> DataFrame (40, 10) ['float64']
{'preset': 'expanded'} -> DataFrame (40, 13) ['float64']
fitted before, transform -> DataFrame (40, 10)
polars -> polars DataFrame (40, 10)

On main, the last four lines are each "Pandas output does not support sparse data. Set sparse_output=False ..." ("Polars output ..." for the last).

Checks

  • just test: 1441 passed, 59 skipped, 7 xfailed; coverage 93.65% (gate 90%).
  • Minimum dependencies (CI job: Python 3.10, numpy 1.24.4, pandas 2.0.3, scipy 1.10.1, scikit-learn 1.6.0): 1427 passed, 73 skipped, 7 xfailed; scripts/quickstart.py passes.
  • just docs: strict build succeeds.
  • just check: all pre-commit and pre-push hooks pass (ruff format, ruff lint, prettier, file hygiene, pyright with 0 errors).
  • Import direction between subpackages is unchanged.

Merge notes

This change was previously part of #86, which is closed in favour of one pull request per issue.

A global sklearn.set_config(transform_output="pandas") (or "polars")
reached the steps of the internal ColumnTransformer. The sparse
OneHotEncoder refuses pandas and polars output, so
categorical_method="one-hot" and preset="expanded" failed to fit with
"Pandas output does not support sparse data", and users could not work
around it because the encoder's sparse_output is not exposed.

The internal ColumnTransformer is now pinned to
set_output(transform="default"), so its steps always produce plain
arrays. The Preprocessor still wraps its stacked output in the
requested container itself, so transform keeps returning a pandas or
polars DataFrame under the global setting.

Fixes #76

This branch has not been deployed

No deployments
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.

Preprocessor with one-hot encoding or preset="expanded" fails under set_config(transform_output="pandas")

1 participant