← Back to DevBytes

Scikit-learn from Scratch: Hands-On Tutorial:

Introduction to Scikit-learn

Scikit-learn is one of the most widely used machine learning libraries in Python. Built on top of NumPy, SciPy, and matplotlib, it provides a clean, consistent API for a wide range of supervised and unsupervised learning algorithms. Whether you are building a simple linear regression model or a complex ensemble classifier, Scikit-learn offers the tools to do it efficiently.

This tutorial walks you through the essentials of Scikit-learn from scratch, covering installation, data preparation, model training, evaluation, and best practices. By the end, you will have a solid foundation to build and deploy machine learning models confidently.

Why Scikit-learn Matters

Scikit-learn matters because it abstracts away the complex mathematics behind machine learning algorithms while still giving developers control over the important parameters. Its unified API means that once you learn how to train one model, you can train dozens of others with minimal changes to your code.

Installation and Setup

Before writing any code, you need to install Scikit-learn and its dependencies. The easiest way is to use pip or conda. We also recommend installing pandas and matplotlib, which are commonly used alongside Scikit-learn.

# Using pip
pip install scikit-learn pandas numpy matplotlib

# Using conda
conda install scikit-learn pandas numpy matplotlib

Once installed, verify the installation by importing the library and checking its version:

import sklearn
import pandas as pd
import numpy as np

print("Scikit-learn version:", sklearn.__version__)

Understanding the Core API

The Scikit-learn API is built around a few core concepts that repeat across almost every module. Understanding these concepts is the key to mastering the library.

Estimators

An estimator is any object that learns from data. All estimators implement a fit() method that takes a dataset (usually a 2D array of features X and optionally a 1D array of targets y) and learns parameters from it.

Predictors

A predictor is an estimator that also implements a predict() method. Classification and regression models are predictors. They take new data and return predictions.

Transformers

A transformer is an estimator that implements a transform() method. Preprocessing steps like scaling, encoding, and imputation are transformers. Many transformers also implement fit_transform() as a convenience.

Loading and Preparing Data

Scikit-learn comes with several built-in datasets that are perfect for learning. For this tutorial, we will use the famous Iris dataset, which contains measurements of iris flowers and their species.

from sklearn.datasets import load_iris

iris = load_iris()
X = iris.data
y = iris.target

print("Feature shape:", X.shape)
print("Target shape:", y.shape)
print("Feature names:", iris.feature_names)
print("Target names:", iris.target_names)

In real-world projects, you will usually load data from files using pandas. Here is how you might load a CSV file and prepare it for Scikit-learn:

import pandas as pd

# Load data from a CSV file
df = pd.read_csv("data.csv")

# Separate features and target
X = df.drop("target_column", axis=1)
y = df["target_column"]

print(X.head())
print(y.head())

Splitting Data into Train and Test Sets

Before training a model, you should split your data into training and testing sets. The training set is used to fit the model, while the testing set is used to evaluate its performance on unseen data.

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, stratify=y
)

print("Training samples:", X_train.shape[0])
print("Testing samples:", X_test.shape[0])

The stratify parameter ensures that the class distribution in the split matches the original dataset, which is important for classification problems with imbalanced classes.

Preprocessing Your Data

Most machine learning algorithms perform better when features are on a similar scale. Scikit-learn provides several preprocessing transformers to help with this.

Feature Scaling

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

print("Mean of scaled features:", X_train_scaled.mean(axis=0))
print("Std of scaled features:", X_train_scaled.std(axis=0))

Notice that we use fit_transform() on the training data but only transform() on the testing data. This is a critical best practice: the scaler should only learn parameters from the training data to prevent data leakage.

Encoding Categorical Variables

Machine learning models require numerical input. If your dataset contains categorical variables, you need to encode them before training.

from sklearn.preprocessing import LabelEncoder, OneHotEncoder

# Label encoding for ordinal or target variables
le = LabelEncoder()
y_encoded = le.fit_transform(y)

# One-hot encoding for nominal categorical features
# Using pandas get_dummies for simplicity
df_encoded = pd.get_dummies(df, columns=["category_column"])
print(df_encoded.head())

Handling Missing Values

from sklearn.impute import SimpleImputer

imputer = SimpleImputer(strategy="mean")
X_imputed = imputer.fit_transform(X)

print("Any NaN remaining?", np.isnan(X_imputed).any())

Building Your First Classifier

Now that the data is prepared, let us build a classification model. We will start with a simple logistic regression model and then try a more powerful random forest classifier.

Logistic Regression

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# Initialize and train the model
model = LogisticRegression(max_iter=200, random_state=42)
model.fit(X_train_scaled, y_train)

# Make predictions
y_pred = model.predict(X_test_scaled)

# Evaluate
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)
print("\nClassification Report:")
print(classification_report(y_test, y_pred, target_names=iris.target_names))

Random Forest Classifier

from sklearn.ensemble import RandomForestClassifier

rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)

y_pred_rf = rf_model.predict(X_test)

print("Random Forest Accuracy:", accuracy_score(y_test, y_pred_rf))
print("\nClassification Report:")
print(classification_report(y_test, y_pred_rf, target_names=iris.target_names))

Notice how switching from logistic regression to random forest required only changing the import and the model initialization. The rest of the workflow remains identical. This consistency is one of the greatest strengths of Scikit-learn.

Building a Regression Model

Regression is used when the target variable is continuous. Let us use the California Housing dataset to demonstrate a regression workflow.

from sklearn.datasets import fetch_california_housing
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, r2_score

# Load dataset
housing = fetch_california_housing()
X_h, y_h = housing.data, housing.target

# Split data
X_h_train, X_h_test, y_h_train, y_h_test = train_test_split(
    X_h, y_h, test_size=0.2, random_state=42
)

# Train a linear regression model
lr = LinearRegression()
lr.fit(X_h_train, y_h_train)
y_h_pred = lr.predict(X_h_test)

print("Linear Regression MSE:", mean_squared_error(y_h_test, y_h_pred))
print("Linear Regression R2:", r2_score(y_h_test, y_h_pred))

# Train a gradient boosting model
gbr = GradientBoostingRegressor(n_estimators=200, random_state=42)
gbr.fit(X_h_train, y_h_train)
y_h_pred_gbr = gbr.predict(X_h_test)

print("Gradient Boosting MSE:", mean_squared_error(y_h_test, y_h_pred_gbr))
print("Gradient Boosting R2:", r2_score(y_h_test, y_h_pred_gbr))

Model Evaluation and Cross-Validation

Evaluating a model on a single train-test split can be misleading, especially with small datasets. Cross-validation provides a more robust estimate of model performance by splitting the data multiple times.

from sklearn.model_selection import cross_val_score, KFold

# 5-fold cross-validation
cv_scores = cross_val_score(
    rf_model, X, y, cv=5, scoring="accuracy"
)

print("Cross-validation scores:", cv_scores)
print("Mean CV accuracy:", cv_scores.mean())
print("Std CV accuracy:", cv_scores.std())

Hyperparameter Tuning with Grid Search

Most models have hyperparameters that control their behavior. Grid search systematically tries combinations of hyperparameters to find the best configuration.

from sklearn.model_selection import GridSearchCV

# Define the parameter grid
param_grid = {
    "n_estimators": [50, 100, 200],
    "max_depth": [None, 5, 10],
    "min_samples_split": [2, 5, 10]
}

# Set up grid search
grid_search = GridSearchCV(
    RandomForestClassifier(random_state=42),
    param_grid,
    cv=5,
    scoring="accuracy",
    n_jobs=-1
)

grid_search.fit(X_train, y_train)

print("Best parameters:", grid_search.best_params_)
print("Best cross-validation score:", grid_search.best_score_)

# Evaluate the best model on the test set
best_model = grid_search.best_estimator_
y_pred_best = best_model.predict(X_test)
print("Test accuracy:", accuracy_score(y_test, y_pred_best))

Building Pipelines

Pipelines are one of the most powerful features in Scikit-learn. They chain multiple steps together, ensuring that preprocessing and modeling are applied consistently and preventing data leakage.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

# Build a pipeline
pipeline = Pipeline([
    ("scaler", StandardScaler()),
    ("classifier", SVC(kernel="rbf", random_state=42))
])

# Train the pipeline
pipeline.fit(X_train, y_train)

# Evaluate
y_pred_pipe = pipeline.predict(X_test)
print("Pipeline accuracy:", accuracy_score(y_test, y_pred_pipe))

You can also use pipelines with grid search to tune hyperparameters of multiple steps simultaneously:

pipeline_gs = Pipeline([
    ("scaler", StandardScaler()),
    ("classifier", SVC(random_state=42))
])

param_grid_pipe = {
    "classifier__C": [0.1, 1, 10],
    "classifier__kernel": ["linear", "rbf"],
    "classifier__gamma": ["scale", "auto"]
}

grid_pipe = GridSearchCV(pipeline_gs, param_grid_pipe, cv=5, scoring="accuracy")
grid_pipe.fit(X_train, y_train)

print("Best pipeline params:", grid_pipe.best_params_)
print("Best pipeline score:", grid_pipe.best_score_)

Unsupervised Learning: Clustering and Dimensionality Reduction

Scikit-learn also excels at unsupervised learning tasks where there is no labeled target variable.

K-Means Clustering

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

# Apply K-Means
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
clusters = kmeans.fit_predict(X)

print("Cluster centers shape:", kmeans.cluster_centers_.shape)
print("Silhouette score:", silhouette_score(X, clusters))

Principal Component Analysis

from sklearn.decomposition import PCA

# Reduce to 2 dimensions for visualization
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)

print("Original shape:", X.shape)
print("Reduced shape:", X_pca.shape)
print("Explained variance ratio:", pca.explained_variance_ratio_)

Saving and Loading Models

Once you have trained a model, you will want to save it for later use or deployment. The recommended approach is to use joblib, which is optimized for Scikit-learn objects that contain NumPy arrays.

import joblib

# Save the model and scaler
joblib.dump(best_model, "best_model.pkl")
joblib.dump(scaler, "scaler.pkl")

# Load them later
loaded_model = joblib.load("best_model.pkl")
loaded_scaler = joblib.load("scaler.pkl")

# Make predictions with the loaded model
new_prediction = loaded_model.predict(X_test[:5])
print("Predictions from loaded model:", new_prediction)

Best Practices

Conclusion

Scikit-learn provides a powerful yet accessible framework for machine learning in Python. Its consistent API, rich collection of algorithms, and integration with the broader data science ecosystem make it an essential tool for developers and data scientists alike. In this tutorial, you learned how to load and preprocess data, build classification and regression models, evaluate them with cross-validation, tune hyperparameters, construct pipelines, perform unsupervised learning, and persist trained models. The best way to deepen your understanding is to apply these concepts to your own datasets, experiment with different algorithms, and gradually incorporate more advanced techniques like custom transformers, ensemble methods, and feature selection. With the foundation you now have, you are well equipped to tackle real-world machine learning projects using Scikit-learn.

— Ad —

Google AdSense will appear here after approval

← Back to all articles