Skip to content

Exposing transformations applied by Cleaner and TableVectorizer - #2122

Open
emassoulie wants to merge 21 commits into
skrub-data:mainfrom
emassoulie:issue-1265-expose-cleaner-and-tablevectorizer-transformations
Open

Exposing transformations applied by Cleaner and TableVectorizer#2122
emassoulie wants to merge 21 commits into
skrub-data:mainfrom
emassoulie:issue-1265-expose-cleaner-and-tablevectorizer-transformations

Conversation

@emassoulie

Copy link
Copy Markdown
Contributor

Closes #1265
Adds a method to the Cleaner and TableVectorizer transformers enabling them to give a human-readable list of the transformations (DropUninformative, ToFloat, ToDatetime) they are set to apply once fitted.

@emassoulie

Copy link
Copy Markdown
Contributor Author

I've got something going with the transformation lists for both transformers! I feel the TableVectorizer transformations could be equally relevant to expose by raw transformer type (ToFloat, ToDatetime etc, like the Cleaner), or by transformer category ("numeric", "low cardinality" etc, since they are customisable). I'm thinking of going towards the latter, but I wanted to ask for a second opinion before I go ahead.

@emassoulie
emassoulie marked this pull request as ready for review July 16, 2026 12:53
@emassoulie

Copy link
Copy Markdown
Contributor Author

It's starting to come together! The direction chosen is to output a string viewable in any terminal, and to list columns grouped by transformation. On this second point, I've been having thoughts on doing it the other way, adding a way of describing the pipeline each individual column goes through: does that seem relevant or does the current way work fine?

I've attached the output to TableVectorizer.list_transformations() after running fit on two different examples, one on the employee dataset and one on the custom-made dataset created for the test. Does it look like the kind of output we want?

Capture d’écran du 2026-07-16 14-59-52 Capture d’écran du 2026-07-16 15-09-32

Eloi Massoulié added 2 commits July 16, 2026 15:27

@rcap107 rcap107 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you very much for the PR @emassoulie ! I did a review of the current material.

In general, I think we're on the right path. I think the main thing to decide is the actual format of the returned string. I think there is too much whitespace, so we may want to investigate how other symbols may make it easier to parse the output.

Other than that, good job!

Comment thread skrub/_table_vectorizer.py Outdated
Comment thread skrub/_table_vectorizer.py Outdated
Comment thread skrub/_table_vectorizer.py Outdated
Comment thread skrub/_table_vectorizer.py
Comment thread skrub/_table_vectorizer.py Outdated
check_is_fitted(self, "all_outputs_")
return np.asarray(self.all_outputs_)

def list_transformations(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a public method so it should have a docstring

Comment thread skrub/_table_vectorizer.py Outdated
Comment thread skrub/_table_vectorizer.py Outdated
Comment thread skrub/tests/test_table_vectorizer.py
Comment thread skrub/tests/test_table_vectorizer.py Outdated
Comment thread skrub/tests/test_table_vectorizer.py Outdated
Eloi Massoulié added 2 commits July 28, 2026 12:33

@rcap107 rcap107 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks a lot for improving the PR!

I think we're getting close to the end, though I think the code can still be improved and simplified in places.

I opened a PR targeting this branch in emassoulie#2 to propose some changes in that direction

Could you also add a mention of list_transformations in the docstring of TableVectorizer and Cleaner? Without printing the entire thing, only the first few lines followed by ... to elide the rest

Comment on lines +1230 to +1233
"""Returns a string reporting the transformations applied by the table
vectorizer, and the columns they are each applied to. This covers every
preprocessing step, each of the `numeric`, `datetime`, `low cardinality`
and `high cardinality` transformations and any specific transformer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

numpy formatting requires a single line

Suggested change
"""Returns a string reporting the transformations applied by the table
vectorizer, and the columns they are each applied to. This covers every
preprocessing step, each of the `numeric`, `datetime`, `low cardinality`
and `high cardinality` transformations and any specific transformer.
"""Returns a string reporting the transformations applied by the TableVectorizer \
and the columns they are each applied to.
This covers every preprocessing step, each of the `numeric`, `datetime`, `low cardinality`
and `high cardinality` transformations and any specific transformer.



def _limit_cols(col_names, max_cols=10):
list_cols = col_names[:max_cols]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I realize I suggested this version, but thinking about it again it could be simplified further to

list_cols = col_names[:max_cols] + ["..."] if len(col_names) > max_cols else col_names

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

though it's not a big problem since this is wrapped into a function anyway

Comment on lines +1264 to +1270
"""
For each column type (numeric, datetime etc.), there is a
dedicated transformer in the TableVectorizer that must be
displayed (for instance, self.numeric = Passthrough()).
The corresponding attribute is therefore fetched
and its class name printed.
"""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd rather have the regular comments with # even though it's a multi-line comment. It's how we do it in the rest of the codebase, and this is being rendered as a string so at a glance I was wondering if it would be printed

check_is_fitted(self, "all_outputs_")
return np.asarray(self.all_outputs_)

def list_transformations(self, max_cols=10):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this needs to have a docstring

)

t_post = self._postprocessors[0]
postprocessing_transformations += (

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

maybe we can remove this section on postprocessing, since it's done to all columns anyway

it should be mentioned clearly in the docstring (I realize now it's not)



def test_list_transformations(df_module):
def list_category(line_name, key, column_type="", with_specific=True, max_cols=3):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

please add a comment here to explain what the function is doing


return header + full_list

passthrough_line = [

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

please add a small comment explaining what the test dataset looks like

All float columns"""
assert vectorizer_output == expected_vectorizer_output

vectorizer = Cleaner(drop_if_constant=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the cleaner should be moved to a separate test, or the test should be parametrized to have both the cleaner and the tablevectorizer

in this case it may be simpler to have two separate tests, though that means repeating a lot of the code

either way, list_category should be moved outside of the test

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the reason I prefer having two separate tests (or a parametrized test) is that I was debugging this, and the test was failing on the Cleaner part

I did not notice that was the case because the diff was very long, so I was looking for the failure in the part about the TableVectorizer when it was in the Cleaner

+ list_category("DropUninformative", "uninformative", with_specific=False)
+ list_category("Datetime", "datetime", with_specific=False)
)
"""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same comment about using # rather than triple quotes

Datetime (1 columns):
- datetime
"""
assert cleaner_output == expected_cleaner_output

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same comment about testing line by line

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.

Expose the transformations done by the TableVectorizer

2 participants