Skip to content

Conversation

@crocmons
Copy link
Contributor

@crocmons crocmons commented Nov 27, 2025

Reference Issues/PRs

Fixes #9122 - ColumnwiseTransformer failed with sklearn transformers due to incompatible interfaces.
This PR implements the TabularToSeriesAdaptor pattern as suggested by mentor to seamlessly support both sklearn and sktime transformers.

What does this implement/fix? Explain your changes.

This PR fixes a bug where ColumnwiseTransformer could not be instantiated with sklearn transformers like PowerTransformer.

###📌Problem:
ColumnwiseTransformer failed when used with sklearn transformers like PowerTransformer:

from sktime.transformations.compose import ColumnwiseTransformer
from sklearn.preprocessing import PowerTransformer

# This failed with AttributeError
transformer = ColumnwiseTransformer(PowerTransformer())

Root Causes:

  • sklearn transformers lack sktime's .clone() method
  • sklearn transformers don't have sktime's tag system (get_tag(), _get_flags)
  • sklearn transformers expect 2D DataFrame input, but ColumnwiseTransformer passed 1D Series_

Solution (Mentor-Recommended Approach):

Implemented the TabularToSeriesAdaptor pattern with the following key changes:

1. Centralized sklearn/sktime handling in init:_

if hasattr(transformer, "get_tag"):
     # sktime transformer - use directly
     self._transformer = transformer
else:
    # sklearn transformer - wrap with adaptor
    self._transformer = TabularToSeriesAdaptor(transformer)

Changes:

  • Modified ColumnwiseTransformer.__init__ to check for get_tag method before cloning tags
  • Added explanatory comments about the difference between sktime and sklearn transformer tag systems
  • Preserves all existing functionality for both sktime and sklearn transformers

📌 I'm using self.transformer here because:
- clone_tags() expects a sktime transformer with get_tag() method
- self._transformer is guaranteed to have this method
- self.transformer might be sklearn (no get_tag() method)_

Summary

  • self.transformer: What the user gave us (could be sklearn/sktime)
  • self._transformer: What we use internally (always sktime-compatible)_

2. Use internal transformer throughout:

  • All methods now use self._transformer (guaranteed sktime-compatible)
  • Removed manual data format conversion
  • Uses sklearn.base.clone consistent with sktime codebase_

Files Changed:

sktime/transformations/compose/_column.py
- Added TabularToSeriesAdaptor import
- Modified init with conditional wrapping
- Updated methods to use self._transformer
- Enhanced get_test_params() with sklearn case
- Removed manual data conversion logic_

Mentor Feedback Implementation:

This PR implements the @fkiraly mentor's suggested approach:

  • ✅ Use TabularToSeriesAdaptor to wrap sklearn transformers
  • ✅ Handle sklearn/sktime distinction in init method
  • ✅ Use self._transformer internally (guaranteed sktime)
  • ✅ Add sklearn test case to get_test_params()
  • ✅ Use sklearn.base.clone consistent with sktime codebase

✨Fixes -

Does your contribution introduce a new dependency? If yes, which one?

No. This fix uses existing functionality and doesn't introduce any new dependencies.

What should a reviewer concentrate their feedback on?

  • Verify that the fix correctly handles both sktime and sklearn transformers
  • Ensure that existing sktime transformer functionality is preserved
  • Check that the hasattr(transformer, 'get_tag') check is the appropriate way to distinguish transformer types
  • Confirm the fix resolves the reported issue with PowerTransformer

Did you add any tests for the change?

No new tests were added. The fix is minimal and preserves existing behavior. The issue can be verified by running:

from sktime.transformations.compose import ColumnwiseTransformer
from sklearn.preprocessing import PowerTransformer
ColumnwiseTransformer(PowerTransformer())  # Should now work without error

Any other comments?

This is a minimal, targeted fix that addresses the root cause while maintaining backward compatibility. The solution follows sktime's pattern of checking for interface compatibility before using sktime-specific functionality.

PR checklist

For all contributions
  • I've added myself to the list of contributors with any new badges I've earned :-)
    How to: add yourself to the all-contributors file in the sktime root directory (not the CONTRIBUTORS.md). Common badges: code - fixing a bug, or adding code logic. doc - writing or improving documentation or docstrings. bug - reporting or diagnosing a bug (get this plus code if you also fixed the bug in the PR).maintenance - CI, test framework, release.
    See here for full badge reference
  • Optionally, for added estimators: I've added myself and possibly to the maintainers tag - do this if you want to become the owner or maintainer of an estimator you added.
    See here for further details on the algorithm maintainer role.
  • The PR title starts with either [ENH], [MNT], [DOC], or [BUG]. [BUG] - bugfix, [MNT] - CI, test framework, [ENH] - adding or improving code, [DOC] - writing or improving documentation or docstrings.
For new estimators
  • I've added the estimator to the API reference - in docs/source/api_reference/taskname.rst, follow the pattern.
  • I've added one or more illustrative usage examples to the docstring, in a pydocstyle compliant Examples section.
  • If the estimator relies on a soft dependency, I've set the python_dependencies tag and ensured
    dependency isolation, see the estimator dependencies guide.

Copy link
Collaborator

@fkiraly fkiraly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

  • to test that this works, please add a scikit-learn transformer case to get_test_params
  • I would handle this differently: in __init__, check if an sklearn transformer is passed; if yes, wrap it internally in TabularToSeriesAdapter, and save it to self._transformer. If not, clone transformer simply to self._transformer; internally, and in the tag setting, then use self._transformer which is guaranteed to be an sktime transformer

@crocmons
Copy link
Contributor Author

Thanks!

* to test that this works, please add a `scikit-learn` transformer case to `get_test_params`

* I would handle this differently: in `__init__`, check if an `sklearn` transformer is passed; if yes, wrap it internally in `TabularToSeriesAdapter`, and save it to `self._transformer`. If not, clone `transformer` simply to `self._transformer`; internally, and in the tag setting, then use `self._transformer` which is guaranteed to be an `sktime` transformer

sure I will fix this soon

@crocmons crocmons changed the title [BUG] Fix ColumnwiseTransformer incompatibility with sklearn transformers [BUG] Fix ColumnwiseTransformer to work with sklearn transformers using TabularToSeriesAdaptor Nov 28, 2025
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.

[BUG] ColumnwiseTransformer does not work with scikit-learn transformers

2 participants