Repository navigation
Conversation
Preprocessor recorded n_features_in_ at fit but never checked it. Array columns are named feature_0, feature_1, ... by position, and the inner ColumnTransformer selects those names, so an array with an extra leading column was shifted by one (dropping the last feature) and a trailing extra column was ignored, with no error. An array with fewer columns raised an indirect 'columns are missing' error. transform now raises the usual 'X has n features, but Preprocessor is expecting m features as input.' error (a PretabDataError, which is a ValueError) for NumPy input whose width differs from n_features_in_. DataFrame input is still matched by column name. Fixes #72
This was referenced Oct 16, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #72.
A
Preprocessorfitted on a NumPy array accepted a transform-time array with extra columns without an error. A leading extra column (for example an accidental ID column) shifted every feature and dropped the last one, and a trailing extra column was ignored, so downstream predictions were silently wrong.Root cause
Preprocessor.transformnever compared the input width withn_features_in_. Array columns are namedfeature_0,feature_1, ... by position, and the innerColumnTransformer, fitted on a DataFrame, selects those names and ignores any further columns. An array with extra columns therefore still contained every fitted name. A narrower array raised only an indirectcolumns are missingerror.Fix
Preprocessor.transformchecks 2-D NumPy input before converting it to a DataFrame. If the number of columns differs fromn_features_in_, it raises scikit-learn's usualX has n features, but Preprocessor is expecting m features as input.as aPretabDataError, which is aValueError. DataFrame and dict input is still matched by column name.Behaviour changes
transformwith a NumPy array of a different width than atfitnow raisesPretabDataErrorwith the scikit-learn message. Before, a wider array was accepted and misaligned, and a narrower one raisedValueError: columns are missing: {...}. Code that catchesValueErrorstill catches the new error.Documentation
Preprocessor.transformdocstring: newRaisessection for an array whose width differs fromn_features_in_.docs/core_concepts/configuration.md("NumPy array input"): array columns are matched by position, sotransformraises the usual scikit-learn error for an array with a different number of columns.Tests
test_transform_rejects_an_ndarray_of_a_different_width[2],[4]: a narrower and a wider array both raise the scikit-learn-style message. Fails onmain(width 2 raisescolumns are missing, width 4 is accepted), passes here.test_transform_accepts_an_ndarray_of_the_fitted_width: an array of the fitted width is still accepted. Guard test: passes on both by design.Reproduction
Output of the script from #72 on this branch:
Checks
just test: 1441 passed, 59 skipped, 7 xfailed; coverage 93.65% (gate 90%).scripts/quickstart.pypasses.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).Merge notes
main.Preprocessor._align_inputand extends it to a DataFrame passed after an array fit.pretab/preprocessor.pyconflicts intransform, in both the inline check and theRaisestext. Take Preprocessor fitted on a DataFrame rejects a same-width NumPy array at transform (and vice versa) #78's side (X = self._align_input(X)and itsRaisestext), which keeps this PR's behaviour. This PR's tests pass unchanged on the result, and the full suite passes (1444 passed, 59 skipped, 7 xfailed).docs/core_concepts/configuration.mdmerges without a conflict but then states the width error twice, so drop this PR's sentence when both land.tests/integration/test_preprocessor.pyhas an append/append conflict: keep both blocks.tests/integration/test_preprocessor.py, so expect an append/append conflict: keep both blocks.np.ndarray, so on a trial merge a list of rows with an extra column is still accepted after an array fit. When Preprocessor rejects polars DataFrames, so pipelines with set_output(transform="polars") crash #94 lands, the check should cover all input without column labels (Preprocessor rejects polars DataFrames, so pipelines with set_output(transform="polars") crash #94'shas_column_labels), not only arrays.This change was previously part of #75, which is closed in favour of one pull request per issue.