Files
labs/Lab-3/Lab-3-Solution/03_Random_Forest_Pipeline_Solution.ipynb
T

6.2 KiB

Module 3 — Lab 3: A Random Forest Security Pipeline

Topics: Scikit-learn Pipeline, imputation, Random Forest, fit, predict

Solution version: This notebook contains the complete solution. Run the cells in order and compare the results with your Lab notebook.

Learning objectives

After completing this lab, you will be able to:

  • create one reusable preprocessing-and-model pipeline;
  • train a Random Forest binary classifier;
  • generate predictions for unseen data;
  • explain why tree models do not require feature standardization.
In [ ]:
from pathlib import Path
import numpy as np
import pandas as pd

DATA_PATH = Path("data/cicids2017_binary_sample.csv")
RANDOM_STATE = 42

from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier

1. Prepare the binary classification data

In [ ]:
df = pd.read_csv(DATA_PATH)
df.columns = df.columns.str.strip()
df = df.drop_duplicates().replace([np.inf, -np.inf], np.nan)

X = df.drop(columns="Label").select_dtypes(include="number")
y = df["Label"].astype(str).str.strip().str.upper().ne("BENIGN").astype(int)

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=RANDOM_STATE,
    stratify=y,
)

2. Build one pipeline

In [ ]:
pipeline = Pipeline([
    ("imputer", SimpleImputer(strategy="median")),
    ("model", RandomForestClassifier(
        n_estimators=100,
        max_depth=12,
        random_state=RANDOM_STATE,
        n_jobs=-1,
    )),
])

print(pipeline)

Why there is no StandardScaler

Random Forest makes decisions by comparing feature values with thresholds. Scaling a column does not change the ordering of its values, so standardization is not required for this model family. The imputer remains inside the pipeline because the model needs finite values.

3. Train and predict

In [ ]:
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)

print("Predictions:", y_pred[:20])
print("Number of test samples:", len(y_pred))

4. Predict one flow

In [ ]:
one_flow = X_test.iloc[[0]]
one_prediction = int(pipeline.predict(one_flow)[0])

print("Prediction:", one_prediction)
print("Meaning:", "ATTACK" if one_prediction == 1 else "BENIGN")

Self-check

In [ ]:
assert list(pipeline.named_steps) == ["imputer", "model"]
assert pipeline.named_steps["model"].n_estimators == 100
assert len(y_pred) == len(y_test)
assert set(np.unique(y_pred)).issubset({0, 1})
assert one_prediction in {0, 1}
print("✓ Lab 3 completed")

Reflection questions

  1. What problem does the imputer solve inside the pipeline?
  2. Why is a pipeline safer than manually transforming train and test data in separate cells?
  3. What does random_state=42 contribute to the experiment?
In [ ]:
In [ ]:
In [ ]:
In [ ]: