Skip to content

Preprocessor crashes on an all-missing column at fit (numerical, one-hot) or silently drops it (int) #95

Open

Description

@ChrisW09

Description

A column that is entirely missing at fit breaks the default Preprocessor. This is realistic: an optional field can be empty in a training window, a sample or a cross-validation training fold.

  • Numerical column: fit crashes inside scikit-learn with Found array with 0 feature(s). This happens with the default PLE and also with minmax, the splines, the feature maps and every other numerical method except "none", which silently drops the column as described for "int" below. The error names MinMaxScaler because the default scaling="minmax" step is the first to receive the empty array; with scaling=None the method itself fails the same way.
  • Categorical column with the default "int" encoding: the column silently disappears from the output, output_dims_, the dict blocks and get_feature_lineage(). It is still listed in categorical_features_ and counted in n_features_in_.
  • get_feature_info() and Preprocessor(verbose=2).fit then raise IndexError.
  • categorical_method="one-hot": crashes like the numerical case.
  • missing_policy="separate_state": a categorical column keeps only the __missing column and its representation disappears; a numerical column crashes as above.

Affected code

Reproduction

import warnings
import numpy as np, pandas as pd
from pretab import Preprocessor

warnings.simplefilter("ignore")  # hides sklearn's "Skipping features without any observed values" UserWarning
rng = np.random.default_rng(0)
n = 100
y = rng.normal(size=n)
age, city = rng.normal(40, 10, n), rng.choice(["a", "b", "c"], n)

X_num = pd.DataFrame({"age": age, "income": np.nan, "city": city})
try:
    Preprocessor().fit(X_num, y)
except Exception as e:
    print("numerical all-NaN column ->", type(e).__name__ + ":", e)

X_cat = pd.DataFrame({"age": age, "city": city, "segment": pd.Series([np.nan] * n, dtype=object)})
pre = Preprocessor().fit(X_cat, y)
print("categorical all-NaN column -> categorical_features_:", pre.categorical_features_,
      "| output_dims_:", pre.output_dims_, "| blocks:", sorted(pre.transform(X_cat, return_array=False)))
try:
    pre.get_feature_info(verbose=False)
except Exception as e:
    print("   get_feature_info() ->", type(e).__name__ + ":", e)
try:
    Preprocessor(categorical_method="one-hot").fit(X_cat, y)
except Exception as e:
    print("one-hot, all-NaN column ->", type(e).__name__ + ":", e)

Output (PreTab 1.0.0 (6bacaba), Python 3.12, numpy 2.5.3, pandas 2.3.3, scikit-learn 1.9.1, scipy 1.18.1):

numerical all-NaN column -> ValueError: Found array with 0 feature(s) (shape=(100, 0)) while a minimum of 1 is required by MinMaxScaler.
categorical all-NaN column -> categorical_features_: ['city', 'segment'] | output_dims_: {'age': 7, 'city': 1} | blocks: ['cat_city', 'num_age']
   get_feature_info() -> IndexError: list index out of range
one-hot, all-NaN column -> ValueError: Found array with 0 feature(s) (shape=(100, 0)) while a minimum of 1 is required.

Expected behavior

Every detected column keeps a stable output block, and the metadata (n_features_in_, *_features_, output_dims_, names, lineage, get_feature_info) agrees with the output. Alternatively, fit raises a clear PretabDataError naming the column.

The docs promise that "PreTab is explicit about degenerate inputs rather than failing silently".

Actual behavior

An opaque scikit-learn error, or a column that is silently dropped while the metadata still lists it.

Impact

A crash on the default path for a common data situation. Where it does not crash, the output width depends on whether a column happened to be observed in the training rows.

Root cause

SimpleImputer drops features without any observed value unless keep_empty_features=True, and each per-column pipeline holds exactly one column.

Suggested fix direction

  • Build the imputers with keep_empty_features=True, so the column is filled with a constant and keeps its block. Warn at fit, naming the column.
  • Or check for columns without observed values at fit and raise a typed error.
  • Either way, make build_feature_info robust to an empty block.

Related issues

Activity

  1. changed the title [-]A column with no observed values at fit crashes the Preprocessor (numerical, one-hot) or silently disappears from the output (int)[/-] [+]Preprocessor crashes on an all-missing column at fit (numerical, one-hot) or silently drops it (int)[/+] on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions