A scikit-learn pipeline keeps preprocessing and modeling inside one estimator object. That matters when training code scales, selects, encodes, or imputes features before fitting, because the same ordered transformations must run again before scoring or prediction.

Pipeline stores named steps in order. Every step before the last one must transform the data, while the final estimator supplies methods such as predict(), predict_proba(), or score() when it supports them.

A small Iris run chains StandardScaler, SelectKBest, and LogisticRegression. It fits only the training split, prints the fitted step names and selected features, and confirms that held-out rows reach the classifier through the pipeline.

Steps to create a scikit-learn pipeline:

  1. Save create_pipeline.py with a named preprocessing and classifier chain.
    create_pipeline.py
    from sklearn import __version__ as sklearn_version
    from sklearn.datasets import load_iris
    from sklearn.feature_selection import SelectKBest, f_classif
    from sklearn.linear_model import LogisticRegression
    from sklearn.metrics import accuracy_score
    from sklearn.model_selection import train_test_split
    from sklearn.pipeline import Pipeline
    from sklearn.preprocessing import StandardScaler
     
     
    iris = load_iris()
     
    X_train, X_test, y_train, y_test = train_test_split(
        iris.data,
        iris.target,
        test_size=0.25,
        stratify=iris.target,
        random_state=42,
    )
     
    model = Pipeline(
        steps=[
            ("scale", StandardScaler()),
            ("select", SelectKBest(score_func=f_classif, k=2)),
            ("classify", LogisticRegression(C=0.8, max_iter=300)),
        ]
    )
     
    model.fit(X_train, y_train)
     
    predictions = model.predict(X_test)
    accuracy = accuracy_score(y_test, predictions)
    selected_features = model[:-1].get_feature_names_out(iris.feature_names)
    sample_prediction = model.predict(X_test[[0]])[0]
    sample_probability = model.predict_proba(X_test[[0]])[0]
    probability_map = {
        str(iris.target_names[index]): round(float(probability), 3)
        for index, probability in enumerate(sample_probability)
    }
     
    print(f"scikit-learn {sklearn_version}")
    print(f"pipeline steps: {list(model.named_steps)}")
    print(f"selected features: {selected_features.tolist()}")
    print(f"classifier C: {model.named_steps['classify'].C}")
    print(f"held-out accuracy: {accuracy:.3f}")
    print(f"first prediction: {iris.target_names[sample_prediction]}")
    print(f"first probabilities: {probability_map}")

    The step names become keys in named_steps. Nested estimator parameters use the same names with double underscores, such as classify__C during tuning.
    Related: How to run grid search with scikit-learn

  2. Run the pipeline smoke test.
    $ python create_pipeline.py
    scikit-learn 1.9.0
    pipeline steps: ['scale', 'select', 'classify']
    selected features: ['petal length (cm)', 'petal width (cm)']
    classifier C: 0.8
    held-out accuracy: 0.921
    first prediction: setosa
    first probabilities: {'setosa': 0.962, 'versicolor': 0.038, 'virginica': 0.0}
  3. Check the fitted step order.

    scale transforms the raw feature values, select keeps the two strongest features, and classify receives the transformed rows for fitting and prediction.

  4. Verify the selected feature names.

    model[:-1] slices off the classifier and asks the preprocessing portion for output feature names. The two petal features are the columns passed into LogisticRegression.

  5. Confirm prediction runs through the pipeline.

    The held-out accuracy and probability map come from model.predict() and model.predict_proba(), so the scaler and selector were applied before the classifier made the decision.

  6. Remove the scratch script after the smoke test.
    $ rm create_pipeline.py