CSAI2026 labs: Lab-2..Lab-6 (Practical + Solution, data), Module-2..Module-6 notebooks and datasets
This commit is contained in:
@@ -0,0 +1,709 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cell-001",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Module 6 — Lab 1: Auditing NSL-KDD Flow Records\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Topics:** network flows, fixed split, labels, attack groups, leakage\n",
|
||||
"\n",
|
||||
"> **Solution version:** Run the cells in order, compare the outputs with your work, and read the suggested answers."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cell-002",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Learning objectives\n",
|
||||
"\n",
|
||||
"After completing this lab, you will be able to:\n",
|
||||
"\n",
|
||||
"- distinguish network-flow features from targets and audit fields;\n",
|
||||
"- preserve the predefined NSL-KDD train/test split;\n",
|
||||
"- describe binary labels and the DoS, Probe, R2L, and U2R groups;\n",
|
||||
"- identify attack labels that appear only in the test set;\n",
|
||||
"- document imbalance, duplicates, and benchmark limitations."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "cell-003",
|
||||
"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",
|
||||
"TRAIN_PATH = Path(\"data/nsl_kdd_train.csv\")\n",
|
||||
"TEST_PATH = Path(\"data/nsl_kdd_test.csv\")\n",
|
||||
"\n",
|
||||
"missing_files = [str(path) for path in (TRAIN_PATH, TEST_PATH) if not path.exists()]\n",
|
||||
"if missing_files:\n",
|
||||
" raise FileNotFoundError(\n",
|
||||
" \"Missing prepared NSL-KDD files: \" + \", \".join(missing_files) +\n",
|
||||
" \". Follow data/README.md and run: python data/prepare_dataset.py\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"TARGET_COLUMNS = [\"attack_label\", \"attack_group\", \"binary_label\", \"difficulty\"]\n",
|
||||
"CATEGORICAL_FEATURES = [\"protocol_type\", \"service\", \"flag\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cell-004",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Load and validate the fixed split"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "cell-005",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Train shape: (125973, 45)\n",
|
||||
"Test shape: (22544, 45)\n",
|
||||
"Model features: 41\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>duration</th>\n",
|
||||
" <th>protocol_type</th>\n",
|
||||
" <th>service</th>\n",
|
||||
" <th>flag</th>\n",
|
||||
" <th>src_bytes</th>\n",
|
||||
" <th>dst_bytes</th>\n",
|
||||
" <th>land</th>\n",
|
||||
" <th>wrong_fragment</th>\n",
|
||||
" <th>urgent</th>\n",
|
||||
" <th>hot</th>\n",
|
||||
" <th>...</th>\n",
|
||||
" <th>dst_host_same_src_port_rate</th>\n",
|
||||
" <th>dst_host_srv_diff_host_rate</th>\n",
|
||||
" <th>dst_host_serror_rate</th>\n",
|
||||
" <th>dst_host_srv_serror_rate</th>\n",
|
||||
" <th>dst_host_rerror_rate</th>\n",
|
||||
" <th>dst_host_srv_rerror_rate</th>\n",
|
||||
" <th>attack_label</th>\n",
|
||||
" <th>attack_group</th>\n",
|
||||
" <th>binary_label</th>\n",
|
||||
" <th>difficulty</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>tcp</td>\n",
|
||||
" <td>ftp_data</td>\n",
|
||||
" <td>sf</td>\n",
|
||||
" <td>491</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>0.17</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.05</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>normal</td>\n",
|
||||
" <td>Normal</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>20</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>udp</td>\n",
|
||||
" <td>other</td>\n",
|
||||
" <td>sf</td>\n",
|
||||
" <td>146</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>0.88</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>normal</td>\n",
|
||||
" <td>Normal</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>15</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>tcp</td>\n",
|
||||
" <td>private</td>\n",
|
||||
" <td>s0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>1.00</td>\n",
|
||||
" <td>1.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>neptune</td>\n",
|
||||
" <td>DoS</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>19</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>tcp</td>\n",
|
||||
" <td>http</td>\n",
|
||||
" <td>sf</td>\n",
|
||||
" <td>232</td>\n",
|
||||
" <td>8153</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>0.03</td>\n",
|
||||
" <td>0.04</td>\n",
|
||||
" <td>0.03</td>\n",
|
||||
" <td>0.01</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.01</td>\n",
|
||||
" <td>normal</td>\n",
|
||||
" <td>Normal</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>21</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>tcp</td>\n",
|
||||
" <td>http</td>\n",
|
||||
" <td>sf</td>\n",
|
||||
" <td>199</td>\n",
|
||||
" <td>420</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>...</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>0.00</td>\n",
|
||||
" <td>normal</td>\n",
|
||||
" <td>Normal</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>21</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"<p>5 rows × 45 columns</p>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" duration protocol_type service flag src_bytes dst_bytes land \\\n",
|
||||
"0 0 tcp ftp_data sf 491 0 0 \n",
|
||||
"1 0 udp other sf 146 0 0 \n",
|
||||
"2 0 tcp private s0 0 0 0 \n",
|
||||
"3 0 tcp http sf 232 8153 0 \n",
|
||||
"4 0 tcp http sf 199 420 0 \n",
|
||||
"\n",
|
||||
" wrong_fragment urgent hot ... dst_host_same_src_port_rate \\\n",
|
||||
"0 0 0 0 ... 0.17 \n",
|
||||
"1 0 0 0 ... 0.88 \n",
|
||||
"2 0 0 0 ... 0.00 \n",
|
||||
"3 0 0 0 ... 0.03 \n",
|
||||
"4 0 0 0 ... 0.00 \n",
|
||||
"\n",
|
||||
" dst_host_srv_diff_host_rate dst_host_serror_rate \\\n",
|
||||
"0 0.00 0.00 \n",
|
||||
"1 0.00 0.00 \n",
|
||||
"2 0.00 1.00 \n",
|
||||
"3 0.04 0.03 \n",
|
||||
"4 0.00 0.00 \n",
|
||||
"\n",
|
||||
" dst_host_srv_serror_rate dst_host_rerror_rate dst_host_srv_rerror_rate \\\n",
|
||||
"0 0.00 0.05 0.00 \n",
|
||||
"1 0.00 0.00 0.00 \n",
|
||||
"2 1.00 0.00 0.00 \n",
|
||||
"3 0.01 0.00 0.01 \n",
|
||||
"4 0.00 0.00 0.00 \n",
|
||||
"\n",
|
||||
" attack_label attack_group binary_label difficulty \n",
|
||||
"0 normal Normal 0 20 \n",
|
||||
"1 normal Normal 0 15 \n",
|
||||
"2 neptune DoS 1 19 \n",
|
||||
"3 normal Normal 0 21 \n",
|
||||
"4 normal Normal 0 21 \n",
|
||||
"\n",
|
||||
"[5 rows x 45 columns]"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"train_df = pd.read_csv(TRAIN_PATH, low_memory=False)\n",
|
||||
"test_df = pd.read_csv(TEST_PATH, low_memory=False)\n",
|
||||
"feature_cols = [column for column in train_df.columns if column not in TARGET_COLUMNS]\n",
|
||||
"numeric_features = [column for column in feature_cols if column not in CATEGORICAL_FEATURES]\n",
|
||||
"\n",
|
||||
"assert list(train_df.columns) == list(test_df.columns)\n",
|
||||
"print(\"Train shape:\", train_df.shape)\n",
|
||||
"print(\"Test shape:\", test_df.shape)\n",
|
||||
"print(\"Model features:\", len(feature_cols))\n",
|
||||
"display(train_df.head())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cell-006",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Audit classes, groups, and unseen attack labels"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "cell-007",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>train</th>\n",
|
||||
" <th>test</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>binary_label</th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>67343</td>\n",
|
||||
" <td>9711</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>58630</td>\n",
|
||||
" <td>12833</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" train test\n",
|
||||
"binary_label \n",
|
||||
"0 67343 9711\n",
|
||||
"1 58630 12833"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>train</th>\n",
|
||||
" <th>test</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>attack_group</th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>DoS</th>\n",
|
||||
" <td>45927</td>\n",
|
||||
" <td>7460</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>Normal</th>\n",
|
||||
" <td>67343</td>\n",
|
||||
" <td>9711</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>Probe</th>\n",
|
||||
" <td>11656</td>\n",
|
||||
" <td>2421</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>R2L</th>\n",
|
||||
" <td>995</td>\n",
|
||||
" <td>2885</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>U2R</th>\n",
|
||||
" <td>52</td>\n",
|
||||
" <td>67</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" train test\n",
|
||||
"attack_group \n",
|
||||
"DoS 45927 7460\n",
|
||||
"Normal 67343 9711\n",
|
||||
"Probe 11656 2421\n",
|
||||
"R2L 995 2885\n",
|
||||
"U2R 52 67"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Attack labels seen only in test: ['apache2', 'httptunnel', 'mailbomb', 'mscan', 'named', 'processtable', 'ps', 'saint', 'sendmail', 'snmpgetattack', 'snmpguess', 'sqlattack', 'udpstorm', 'worm', 'xlock', 'xsnoop', 'xterm']\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"train_binary = train_df[\"binary_label\"].value_counts().sort_index()\n",
|
||||
"test_binary = test_df[\"binary_label\"].value_counts().sort_index()\n",
|
||||
"train_groups = train_df[\"attack_group\"].value_counts()\n",
|
||||
"test_groups = test_df[\"attack_group\"].value_counts()\n",
|
||||
"\n",
|
||||
"train_attack_labels = set(train_df.loc[train_df[\"binary_label\"] == 1, \"attack_label\"])\n",
|
||||
"test_attack_labels = set(test_df.loc[test_df[\"binary_label\"] == 1, \"attack_label\"])\n",
|
||||
"unseen_test_attacks = sorted(test_attack_labels - train_attack_labels)\n",
|
||||
"\n",
|
||||
"display(pd.DataFrame({\"train\": train_binary, \"test\": test_binary}).fillna(0).astype(int))\n",
|
||||
"display(pd.DataFrame({\"train\": train_groups, \"test\": test_groups}).fillna(0).astype(int))\n",
|
||||
"print(\"Attack labels seen only in test:\", unseen_test_attacks)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cell-008",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Audit quality and leakage risks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "cell-009",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'train_exact_duplicates': 0, 'test_exact_duplicates': 0}\n",
|
||||
"Columns excluded from modeling: ['attack_group', 'attack_label', 'binary_label', 'difficulty']\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>train_missing</th>\n",
|
||||
" <th>test_missing</th>\n",
|
||||
" <th>train_unique</th>\n",
|
||||
" <th>test_unique</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>num_outbound_cmds</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>is_host_login</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>is_guest_login</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>land</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>logged_in</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>root_shell</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>protocol_type</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>wrong_fragment</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>num_shells</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>4</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>su_attempted</th>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" train_missing test_missing train_unique test_unique\n",
|
||||
"num_outbound_cmds 0 0 1 1\n",
|
||||
"is_host_login 0 0 2 2\n",
|
||||
"is_guest_login 0 0 2 2\n",
|
||||
"land 0 0 2 2\n",
|
||||
"logged_in 0 0 2 2\n",
|
||||
"root_shell 0 0 2 2\n",
|
||||
"protocol_type 0 0 3 3\n",
|
||||
"wrong_fragment 0 0 3 3\n",
|
||||
"num_shells 0 0 3 4\n",
|
||||
"su_attempted 0 0 3 3"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"quality_summary = pd.DataFrame({\n",
|
||||
" \"train_missing\": train_df[feature_cols].isna().sum(),\n",
|
||||
" \"test_missing\": test_df[feature_cols].isna().sum(),\n",
|
||||
" \"train_unique\": train_df[feature_cols].nunique(dropna=True),\n",
|
||||
" \"test_unique\": test_df[feature_cols].nunique(dropna=True),\n",
|
||||
"})\n",
|
||||
"duplicate_counts = {\n",
|
||||
" \"train_exact_duplicates\": int(train_df.duplicated().sum()),\n",
|
||||
" \"test_exact_duplicates\": int(test_df.duplicated().sum()),\n",
|
||||
"}\n",
|
||||
"forbidden_model_columns = sorted(set(TARGET_COLUMNS) & set(train_df.columns))\n",
|
||||
"\n",
|
||||
"print(duplicate_counts)\n",
|
||||
"print(\"Columns excluded from modeling:\", forbidden_model_columns)\n",
|
||||
"display(quality_summary.sort_values(\"train_unique\").head(10))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cell-010",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Benchmark note\n",
|
||||
"\n",
|
||||
"NSL-KDD is useful for learning a reproducible IDS workflow. Its fixed test set includes attacks that are absent from training, but it remains a legacy benchmark and does not represent modern production traffic."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cell-011",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Self-check"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "cell-012",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"✓ Lab 1 completed\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"assert len(feature_cols) == 41\n",
|
||||
"assert set(CATEGORICAL_FEATURES).issubset(feature_cols)\n",
|
||||
"assert set(train_df[\"binary_label\"].unique()) == {0, 1}\n",
|
||||
"assert set(test_df[\"attack_group\"].unique()).issubset({\"Normal\", \"DoS\", \"Probe\", \"R2L\", \"U2R\"})\n",
|
||||
"assert len(unseen_test_attacks) > 0\n",
|
||||
"assert set(feature_cols).isdisjoint(TARGET_COLUMNS)\n",
|
||||
"assert quality_summary.shape[0] == 41\n",
|
||||
"print(\"✓ Lab 1 completed\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cell-013",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Suggested answers\n",
|
||||
"\n",
|
||||
"1. **Why keep the fixed split?** It preserves the benchmark design and exposes attack labels that training never saw.\n",
|
||||
"2. **Why exclude `difficulty`?** It was derived from previous classifiers and is not a network measurement available to a real detector.\n",
|
||||
"3. **Why inspect group counts?** Binary metrics can hide poor detection of rare R2L or U2R records."
|
||||
]
|
||||
}
|
||||
],
|
||||
"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
|
||||
}
|
||||
Reference in New Issue
Block a user