'MultiOutputClassifier' object is not iterable when creating a Pipeline (Python)

Viewed 186

I want to create a pipeline that continues encoding, scaling then the xgboost classifier for multilabel problem. The code block;

# Create a boolean mask for categorical columns
categorical_columns = X.columns[X.dtypes == 'O'].tolist()

#Distinct columns for to find catagories
unique_list = [X[c].unique().tolist() for c in categorical_columns]

# Create a boolean mask for numerical columns
numerical_columns = X.columns[X.dtypes != 'O'].tolist()

#Encoding & Scaling objects
scaler = StandardScaler()
ohe = OneHotEncoder(categories=unique_list, sparse=False)

#Define a pipeline
pipeline  = Pipeline([("ohe_onestep", ohe.fit_transform(X[categorical_columns])),  
         ("scaler_onestep", scaler.fit_transform(X[numerical_columns])),
         MultiOutputClassifier(xgb.XGBClassifier(objective='binary:logistic'))])

# Cross-validate the model
cross_val_scores = cross_val_score(pipeline, X, y, 
                                   scoring='accuracy', cv=5)

But when i run the code this error appears ; Row is;

> pipeline = Pipeline([("ohe_onestep", ohe.fit_transform(X[categorical_columns])),

'MultiOutputClassifier' object is not iterable

How can i solve this problem?

1 Answers

Two things: first, you need to pass the transformers or the estimators themselves to the pipeline, not the result of fitting/transforming them (that would give the resultant arrays to the pipeline not the transformers, and it'd fail). Pipeline itself will be fitting/transforming. Second, since you have specific transformations to the specific columns, ColumnTransformer is needed.

Putting these together:

from sklearn.compose import ColumnTransformer

col_transformers = ColumnTransformer([
                          # name, transformer itself, columns to apply
                          ("scaler_onestep", scaler, numerical_columns),
                          ("ohe_onestep", ohe, categorical_columns)])

model = MultiOutputClassifier(xgb.XGBClassifier(objective="binary:logistic"))

pipeline = Pipeline([("preprocessing", col_transformers), ("XGB", model)])

Now you can do

cross_val_scores = cross_val_score(pipeline, X, y, 
                                   scoring="accuracy", cv=5)

As an extra, in general you could use make_column_selector with dtype option to let it infer the numericals and categoricals as exemplified here.

Lastly, the reason of the error you got: Pipeline expects a list of tuples. You did pass tuples for the first 2 items, i.e., for scaler and ohe, but you didn't pass a (<name>, model) tuple as the third item; instead you gave it the model directly and it tried to iterate over it to get these names etc. and failed.

Related