{ "cells": [ { "cell_type": "markdown", "id": "291ef749", "metadata": {}, "source": [ "# Module 3 — Lab 6: Capstone — Binary Intrusion Detection with CIC-IDS2017\n", "\n", "\n", "**Topics:** end-to-end ML workflow, CIC-IDS2017, binary classification, evaluation, reporting\n", "\n", "> **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.\n" ] }, { "cell_type": "markdown", "id": "00c8ff6f", "metadata": {}, "source": [ "## Mission\n", "\n", "Build one complete and leakage-safe intrusion-detection workflow:\n", "\n", "1. load a network-flow table;\n", "2. clean invalid values and duplicate rows;\n", "3. map all attacks to one `ATTACK` class;\n", "4. create one stratified train-test split;\n", "5. train one Random Forest pipeline;\n", "6. evaluate attack precision, recall, F1, and error counts;\n", "7. export a short analyst report.\n", "\n", "The notebook uses `data/cicids2017_binary_sample.csv` when that file is available. Until the instructor prepares the official subset, it uses the included synthetic dataset and prints a clear warning.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "9c2228a9", "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.pipeline import Pipeline\n", "from sklearn.impute import SimpleImputer\n", "from sklearn.ensemble import RandomForestClassifier\n", "from sklearn.metrics import (\n", " ConfusionMatrixDisplay, accuracy_score, confusion_matrix,\n", " precision_score, recall_score, f1_score\n", ")\n", "\n", "REAL_DATA_PATH = Path(\"data/cicids2017_binary_sample.csv\")\n", "DEMO_DATA_PATH = Path(\"data/synthetic_security_flows.csv\")\n", "OUTPUT_DIR = Path(\"output\")\n", "OUTPUT_DIR.mkdir(exist_ok=True)\n", "RANDOM_STATE = 42\n", "\n", "DATA_PATH = REAL_DATA_PATH if REAL_DATA_PATH.exists() else DEMO_DATA_PATH\n", "USING_REAL_CICIDS = REAL_DATA_PATH.exists()\n", "\n", "print(\"Dataset:\", DATA_PATH)\n", "if not USING_REAL_CICIDS:\n", " print(\"WARNING: Using synthetic classroom data. Add the prepared CIC-IDS2017 file for the real capstone.\")\n" ] }, { "cell_type": "markdown", "id": "c61dcfb0", "metadata": {}, "source": [ "## 1. Load, clean, and define the binary target\n" ] }, { "cell_type": "code", "execution_count": null, "id": "a2204759", "metadata": {}, "outputs": [], "source": [ "# TODO 1: load DATA_PATH into raw_df\n", "raw_df = None\n", "\n", "# TODO 2: strip column names, remove duplicates, and replace +/- infinity with NaN\n", "clean_df = None\n", "\n", "# TODO 3: create numeric X and binary y (BENIGN=0, every attack=1)\n", "X = None\n", "y = None\n", "\n", "print(f\"Raw rows: {None}\")\n", "print(f\"Clean rows: {None}\")\n", "print(f\"Numeric features: {None}\")\n", "print(\"Binary class distribution:\")\n", "print(None)\n" ] }, { "cell_type": "markdown", "id": "90e14590", "metadata": {}, "source": [ "## 2. Create one fixed train-test split\n" ] }, { "cell_type": "code", "execution_count": null, "id": "33430abe", "metadata": {}, "outputs": [], "source": [ "# TODO 4: create an 80/20 split with stratify=y and random_state=42\n", "X_train, X_test, y_train, y_test = None, None, None, None\n", "\n", "print(\"Training samples:\", None)\n", "print(\"Test samples:\", None)\n", "print(\"Training attack rate:\", None)\n", "print(\"Test attack rate:\", None)\n" ] }, { "cell_type": "markdown", "id": "b4f6af84", "metadata": {}, "source": [ "## 3. Build and train the baseline pipeline\n" ] }, { "cell_type": "code", "execution_count": null, "id": "aab65468", "metadata": {}, "outputs": [], "source": [ "# TODO 5: create an imputer + Random Forest pipeline\n", "baseline_pipeline = None\n", "\n", "# TODO 6: fit the pipeline and predict X_test\n", "y_pred = None\n" ] }, { "cell_type": "markdown", "id": "2c22c49d", "metadata": {}, "source": [ "## 4. Evaluate the attack class\n" ] }, { "cell_type": "code", "execution_count": null, "id": "b6c6facd", "metadata": {}, "outputs": [], "source": [ "# TODO 7: calculate cm and unpack tn, fp, fn, tp\n", "cm = None\n", "tn, fp, fn, tp = None, None, None, None\n", "\n", "# TODO 8: calculate accuracy, attack precision, recall, and F1\n", "baseline_metrics = None\n", "\n", "print(pd.Series(baseline_metrics).round(3))\n", "print(f\"False positives: {fp} | False negatives: {fn}\")\n", "\n", "# TODO 9: plot and save the confusion matrix to output/capstone_confusion_matrix.png\n" ] }, { "cell_type": "markdown", "id": "dc66b35c", "metadata": {}, "source": [ "## 5. Inspect feature importance\n" ] }, { "cell_type": "code", "execution_count": null, "id": "5d1894b7", "metadata": {}, "outputs": [], "source": [ "# TODO 10: create a descending feature_importance Series\n", "feature_importance = None\n", "\n", "print(feature_importance.head(10))\n", "\n", "# TODO 11: plot the top ten features and save the chart\n" ] }, { "cell_type": "markdown", "id": "9f05106e", "metadata": {}, "source": [ "## 6. Export metrics and write an analyst summary\n" ] }, { "cell_type": "code", "execution_count": null, "id": "8e66b54f", "metadata": {}, "outputs": [], "source": [ "# TODO 12: export baseline_metrics to output/capstone_metrics.csv\n", "\n", "# TODO 13: create a summary with dataset type, row count, feature count,\n", "# attack rate, precision, recall, F1, false positives, false negatives,\n", "# and a recommendation. Save it to output/capstone_summary.txt.\n", "summary = None\n", "\n", "print(summary)\n" ] }, { "cell_type": "markdown", "id": "9b0c0e2f", "metadata": {}, "source": [ "## Self-check\n" ] }, { "cell_type": "code", "execution_count": null, "id": "b28ca2a2", "metadata": {}, "outputs": [], "source": [ "assert isinstance(clean_df, pd.DataFrame)\n", "assert set(y.unique()) == {0, 1}\n", "assert X.shape[1] >= 5\n", "assert abs(y_train.mean() - y_test.mean()) < 0.02\n", "assert cm.shape == (2, 2)\n", "assert len(feature_importance) == X.shape[1]\n", "assert (OUTPUT_DIR / \"capstone_confusion_matrix.png\").exists()\n", "assert (OUTPUT_DIR / \"capstone_feature_importance.png\").exists()\n", "assert (OUTPUT_DIR / \"capstone_metrics.csv\").exists()\n", "assert (OUTPUT_DIR / \"capstone_summary.txt\").exists()\n", "print(\"✓ Capstone lab completed\")\n" ] }, { "cell_type": "markdown", "id": "c7bf86d2", "metadata": {}, "source": [ "## Capstone questions\n", "\n", "1. How many attacks did the model miss, and why does that number matter operationally?\n", "2. Which features received the highest importance? Do they make sense for network flows?\n", "3. Why does random row splitting provide an optimistic estimate for some security datasets?\n", "4. What additional validation would you require before deploying this detector?\n", "5. If the notebook used synthetic data, which conclusions must be rechecked on the official CIC-IDS2017 subset?\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 5 }