Files
labs/Lab-3/Lab-3-Practical/02_Clean_Split_No_Leakage_Lab.ipynb
T

5.5 KiB

Module 3 — Lab 2: Clean, Split, and Prevent Data Leakage

Topics: duplicates, missing values, train-test split, imputation, standardization, leakage

Instructions: Run the cells in order. Complete every TODO, then run the Self-check cell. Do not open the Solution notebook before attempting the tasks yourself.

Learning objectives

After completing this lab, you will be able to:

  • remove duplicate records and normalize invalid numeric values;
  • create a stratified train-test split;
  • fit imputation and scaling operations on training data only;
  • explain how fitting preprocessing on the test set causes leakage.
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.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler

1. Load and clean the raw table

In [ ]:
raw_df = pd.read_csv(DATA_PATH)

# TODO 1: remove surrounding whitespace from every column name
raw_df.columns = None

# TODO 2: remove duplicate rows and store the result in clean_df
clean_df = None

# TODO 3: replace positive and negative infinity with NaN
clean_df = None

print("Raw rows:", len(raw_df))
print("Clean rows:", None)
print("Missing numeric values:", None)

2. Create features, target, and a stratified split

In [ ]:
# TODO 4: select numeric features and create a binary target
X = None
y = None

# TODO 5: create an 80/20 split with random_state=42 and stratify=y
X_train, X_test, y_train, y_test = None, None, None, None

print("Train shape:", None)
print("Test shape:", None)
print("Train attack rate:", None)
print("Test attack rate:", None)

3. Fit preprocessing on training data only

In [ ]:
imputer = SimpleImputer(strategy="median")
scaler = StandardScaler()

# TODO 6: fit the imputer on X_train, then transform train and test
X_train_imputed = None
X_test_imputed = None

# TODO 7: fit the scaler on imputed training data, then transform train and test
X_train_scaled = None
X_test_scaled = None

print("Mean of scaled training columns:", None)
print("Mean of scaled test columns:", None)

Why the test mean is not exactly zero

StandardScaler learned its mean and standard deviation from the training set. The test set is transformed with those same values. A non-zero test mean is expected and is evidence that the test set was not used to fit the scaler.

Self-check

In [ ]:
assert len(clean_df) < len(raw_df)
assert np.isfinite(X_train_scaled).all()
assert np.isfinite(X_test_scaled).all()
assert abs(y_train.mean() - y_test.mean()) < 0.02
assert np.allclose(X_train_scaled.mean(axis=0), 0.0, atol=1e-10)
assert X_train_scaled.shape[1] == X.shape[1]
print("✓ Lab 2 completed")

Reflection questions

  1. Why must the imputer learn medians from the training set only?
  2. What information would leak if the scaler were fit before the train-test split?
  3. Why is stratification useful for an imbalanced security target?