DEV Community

EricMWaimiri
EricMWaimiri

Posted on

Build Your First Scikit-learn Pipeline

If you're new to scikit-learn, "Pipelines" can sound like an advanced topic to save for later. They're not. In this tutorial, we'll build one from scratch using the classic Titanic dataset, explaining every line along the way.
By the end, you'll have a single object that cleans your data, encodes it, and makes predictions — all in one call.

Step 1: Load the Data

We'll use the Titanic dataset from seaborn, which comes bundled with the library.

import seaborn as sns

titanic = sns.load_dataset("titanic")
titanic.head()
Enter fullscreen mode Exit fullscreen mode

We're trying to predict survived (0 or 1) using features like pclass, sex, age, and fare.

features = ["pclass", "sex", "age", "fare", "embarked"]
X = titanic[features]
y = titanic["survived"]
Enter fullscreen mode Exit fullscreen mode

Step 2: Split Before You Touch Anything Else

This is the step beginners skip, and it's the most important one. Split your data before any cleaning or scaling.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
Enter fullscreen mode Exit fullscreen mode

Why first? Because any preprocessing (like filling missing ages) should learn its parameters only from training data. If you clean the full dataset first, information from the test set leaks into training.

Step 3: Look at What Needs Cleaning

X_train.isnull().sum()
Enter fullscreen mode Exit fullscreen mode

You'll see age has missing values, and embarked has a couple too. sex and embarked are text, not numbers — models can't use those directly. This is exactly what a pipeline will handle for us.

Step 4: Build a Mini-Pipeline for Numeric Columns

Numeric columns (pclass, age, fare) need two things: fill missing values, then scale them.

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler

numeric_features = ["pclass", "age", "fare"]

numeric_pipeline = Pipeline([
    ("imputer", SimpleImputer(strategy="median")),
    ("scaler", StandardScaler())
])
Enter fullscreen mode Exit fullscreen mode

Read this like a recipe: "First impute, then scale." Each named step runs in order.

Step 5: Build a Mini-Pipeline for Categorical Columns

Text columns (sex, embarked) need missing values filled differently, then need to become numbers via one-hot encoding.

from sklearn.preprocessing import OneHotEncoder

categorical_features = ["sex", "embarked"]

categorical_pipeline = Pipeline([
    ("imputer", SimpleImputer(strategy="most_frequent")),
    ("onehot", OneHotEncoder(handle_unknown="ignore"))
])
Enter fullscreen mode Exit fullscreen mode

handle_unknown="ignore" prevents errors if the test set ever contains a category the training set didn't have.

Step 6: Combine Both with ColumnTransformer

Now we tell scikit-learn which pipeline applies to which columns using ColumnTransformer.

from sklearn.compose import ColumnTransformer

preprocessor = ColumnTransformer([
    ("num", numeric_pipeline, numeric_features),
    ("cat", categorical_pipeline, categorical_features)
])
Enter fullscreen mode Exit fullscreen mode

This single object now knows: numeric columns go through one path, categorical columns go through another.

Step 7: Add a Model to Make the Full Pipeline

Finally, we chain the preprocessor into a full pipeline with a classifier as the last step.

from sklearn.ensemble import RandomForestClassifier

full_pipeline = Pipeline([
    ("preprocessing", preprocessor),
    ("classifier", RandomForestClassifier(random_state=42))
])
Enter fullscreen mode Exit fullscreen mode

Step 8: Fit and Predict — One Call Each

full_pipeline.fit(X_train, y_train)
predictions = full_pipeline.predict(X_test)
Enter fullscreen mode Exit fullscreen mode

That's it. One .fit() call trains the imputers, the scaler, the encoder, and the model together. One .predict() call applies all of them to new data in the correct order.

Step 9: Check the Score

from sklearn.metrics import accuracy_score

accuracy = accuracy_score(y_test, predictions)
print(f"Accuracy: {accuracy:.2f}")
Enter fullscreen mode Exit fullscreen mode

You should see something around 0.80–0.83 depending on the random split.

Why This Matters

Without a pipeline, you'd need to manually remember to: fill missing ages the same way on both train and test, scale using train-set statistics only, one-hot encode consistently, and apply all of it in the right order every single time you touch the data — including in production. The pipeline does all of this for you, automatically, and prevents the subtle bugs that come from doing it by hand.

What's Next

Once this feels comfortable, the natural next step is plugging this same full_pipeline into GridSearchCV to tune the RandomForestClassifier's hyperparameters, or into cross_val_score for more reliable accuracy estimates — no changes needed to the pipeline itself.

Top comments (0)