Question: I wanted to find out the correct naming convention when referring to individual preprocessor included in ColumnTransformer (which is part of a pipeline) in param_grid for grid_search. Environment & sample data: import seaborn as sns from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.impute import SimpleImputer from sklearn.preprocessing import OneHotEncoder, KBinsDiscretizer, MinMaxScaler from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.linear_model import LogisticRegression df = sns.load_dataset('titanic')[['survived', 'age', 'embarked']] X_train, X_test, y_train, y_test = train_test_split(df.drop(columns='survived'), df['survived'], test_size=0.2, random_state=123)  Pipeline: num = ['age'] cat = ['embarked'] num_transformer = Pipeline(steps=[('imputer', SimpleImputer()), ('discritiser', KBinsDiscretizer(encode='ordinal', strategy='uniform')), ('scaler', MinMaxScaler())]) cat_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='constant', fill_value='missing')), ('onehot', OneHotEncoder(handle_unknown='ignore'))]) preprocessor = ColumnTransformer(transformers=[('num', num_transformer, num), ('cat', cat_transformer, cat)]) pipe = Pipeline(steps=[('preprocessor', preprocessor), ('classiffier', LogisticRegression(random_state=1, max_iter=10000))]) param_grid = dict([SOMETHING]imputer__strategy = ['mean', 'median'], [SOMETHING]discritiser__nbins = range(5,10), classiffier__C = [0.1, 10, 100], classiffier__solver = ['liblinear', 'saga']) grid_search = GridSearchCV(pipe, param_grid=param_grid, cv=10) grid_search.fit(X_train, y_train)  Basically, what should I write instead of [SOMETHING] in my code? I have looked at this answer which answered the question for make_pipeline - so using the similar idea, I tried 'preprocessor__num__', 'preprocessor__num_', 'pipeline__num__', 'pipeline__num_' - no luck so far. Thank you

Answer: You were close, the correct way to declare it is like this: param_grid = {'preprocessor__num__imputer__strategy' : ['mean', 'median'], 'preprocessor__num__discritiser__n_bins' : range(5,10), 'classiffier__C' : [0.1, 10, 100], 'classiffier__solver' : ['liblinear', 'saga']}  Here is the full code: import seaborn as sns from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.impute import SimpleImputer from sklearn.preprocessing import OneHotEncoder, KBinsDiscretizer, MinMaxScaler from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.linear_model import LogisticRegression df = sns.load_dataset('titanic')[['survived', 'age', 'embarked']] X_train, X_test, y_train, y_test = train_test_split(df.drop(columns='survived'), df['survived'], test_size=0.2, random_state=123) num = ['age'] cat = ['embarked'] num_transformer = Pipeline(steps=[('imputer', SimpleImputer()), ('discritiser', KBinsDiscretizer(encode='ordinal', strategy='uniform')), ('scaler', MinMaxScaler())]) cat_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='constant', fill_value='missing')), ('onehot', OneHotEncoder(handle_unknown='ignore'))]) preprocessor = ColumnTransformer(transformers=[('num', num_transformer, num), ('cat', cat_transformer, cat)]) pipe = Pipeline(steps=[('preprocessor', preprocessor), ('classiffier', LogisticRegression(random_state=1, max_iter=10000))]) param_grid = {'preprocessor__num__imputer__strategy' : ['mean', 'median'], 'preprocessor__num__discritiser__n_bins' : range(5,10), 'classiffier__C' : [0.1, 10, 100], 'classiffier__solver' : ['liblinear', 'saga']} grid_search = GridSearchCV(pipe, param_grid=param_grid, cv=10) grid_search.fit(X_train, y_train)  One simply way to check the available parameter names is like this: print(pipe.get_params().keys())  This will print out the list of all the available parameters which you can copy directly into your params dictionary. I have written a utility function which you can use to check if a parameter exist in a pipeline/classifier by simply passing in a keyword. def check_params_exist(esitmator, params_keyword): all_params = esitmator.get_params().keys() available_params = [x for x in all_params if params_keyword in x] if len(available_params)==0: return "No matching params found!" else: return available_params  Now if you are unsure of the exact name, just pass imputer as the keyword print(check_params_exist(pipe, 'imputer'))  This will print the following list: ['preprocessor__num__imputer', 'preprocessor__num__imputer__add_indicator', 'preprocessor__num__imputer__copy', 'preprocessor__num__imputer__fill_value', 'preprocessor__num__imputer__missing_values', 'preprocessor__num__imputer__strategy', 'preprocessor__num__imputer__verbose', 'preprocessor__cat__imputer', 'preprocessor__cat__imputer__add_indicator', 'preprocessor__cat__imputer__copy', 'preprocessor__cat__imputer__fill_value', 'preprocessor__cat__imputer__missing_values', 'preprocessor__cat__imputer__strategy', 'preprocessor__cat__imputer__verbose']