8.7 KiB
8.7 KiB
In [ ]:
from pathlib import Path
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
TRAIN_PATH = Path("data/nsl_kdd_train.csv")
TEST_PATH = Path("data/nsl_kdd_test.csv")
missing_files = [str(path) for path in (TRAIN_PATH, TEST_PATH) if not path.exists()]
if missing_files:
raise FileNotFoundError(
"Missing prepared NSL-KDD files: " + ", ".join(missing_files) +
". Follow data/README.md and run: python data/prepare_dataset.py"
)
TARGET_COLUMNS = ["attack_label", "attack_group", "binary_label", "difficulty"]
CATEGORICAL_FEATURES = ["protocol_type", "service", "flag"]
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import IsolationForest
from sklearn.impute import SimpleImputer
from sklearn.metrics import ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import (
accuracy_score, average_precision_score, confusion_matrix,
f1_score, precision_score, recall_score,
)
def security_metrics(y_true, y_pred):
tn, fp, fn, tp = confusion_matrix(y_true, y_pred, labels=[0, 1]).ravel()
return {
"accuracy": accuracy_score(y_true, y_pred),
"attack_precision": precision_score(y_true, y_pred, zero_division=0),
"attack_recall": recall_score(y_true, y_pred, zero_division=0),
"attack_f1": f1_score(y_true, y_pred, zero_division=0),
"false_positives": int(fp),
"false_negatives": int(fn),
"false_positive_rate": fp / (fp + tn) if fp + tn else 0.0,
"alerts_per_10000": 10000 * (fp + tp) / len(y_true),
}
OUTPUT_DIR = Path("output")
OUTPUT_DIR.mkdir(exist_ok=True)In [ ]:
# TODO 1: load the fixed split and build the supervised feature matrices.
train_df = None
test_df = None
feature_cols = None
numeric_features = None
X_train, y_train, X_test, y_test = None, None, None, None
# TODO 2: fit the bounded, balanced Decision Tree pipeline from Lab 5.
tree_model = None
tree_predictions = None
tree_probabilities = NoneIn [ ]:
# TODO 3: define anomaly_features, split normal training data, fit an
# Isolation Forest pipeline, and select the 99th validation percentile.
anomaly_features = None
normal_fit = None
normal_valid = None
anomaly_model = None
validation_scores = None
anomaly_scores = None
anomaly_threshold = None
anomaly_predictions = NoneIn [ ]:
# TODO 4: create Classifier, Anomaly, and Hybrid_OR predictions/scores.
policy_predictions = None
policy_scores = None
# TODO 5: build metrics_table and select the highest-recall policy with
# FPR <= 0.10, breaking ties by F1 then lower FPR.
metrics_table = None
selected_policy = None
selected_predictions = None
display(metrics_table)In [ ]:
# TODO 6: calculate per-group recall for every policy.
group_recall = None
# TODO 7: build alert_table, derive alert_reason, and keep the top 200
# selected alerts ordered by anomaly score and tree probability.
alert_table = None
top_alerts = None
display(top_alerts)In [ ]:
# TODO 8: save a confusion matrix and anomaly-score distribution chart.
# TODO 9: write an English SOC summary covering the selected policy,
# metrics, alert volume, detector roles, weak groups, and limitations.
analyst_summary = None
# TODO 10: export the metrics, group recall, top alerts, and summary.
print(analyst_summary)In [ ]:
expected_files = {
"hybrid_ids_metrics.csv", "hybrid_ids_group_recall.csv",
"hybrid_ids_top_alerts.csv", "hybrid_ids_confusion_matrix.png",
"hybrid_ids_score_distribution.png", "hybrid_ids_analyst_summary.md",
}
assert set(policy_predictions) == {"Classifier", "Anomaly", "Hybrid_OR"}
assert selected_policy in policy_predictions
assert len(alert_table) == len(test_df)
assert set(group_recall["attack_group"]) == {"DoS", "Probe", "R2L", "U2R"}
assert expected_files.issubset({path.name for path in OUTPUT_DIR.iterdir()})
assert "NSL-KDD" in analyst_summary
print("✓ Lab 6 completed")