205 lines
4.8 KiB
Plaintext
205 lines
4.8 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "2444933d",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Module 2 — Lab 4: NumPy for Security Metrics\n",
|
|
"\n",
|
|
"**Topics:** array, vectorization, statistics, boolean mask\n",
|
|
"\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": "0f43f1b4",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Scenario\n",
|
|
"\n",
|
|
"A network sensor reports packet sizes, latency, and failed authentication attempts for each time window. We use NumPy to calculate efficiently across the entire array.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "0b917960",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"packet_sizes = np.array([64, 128, 1500, 512, 1514, 256, 1400, 80])\n",
|
|
"latency_ms = np.array([12.5, 18.0, 250.0, 33.5, 180.0, 25.0, 95.0, 10.0])\n",
|
|
"failed_attempts = np.array([0, 1, 8, 2, 10, 1, 6, 0])\n",
|
|
"\n",
|
|
"print(packet_sizes.shape, packet_sizes.dtype)\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ca8c8c19",
|
|
"metadata": {
|
|
"tags": [
|
|
"exercise"
|
|
]
|
|
},
|
|
"source": [
|
|
"## 1. Unit conversion and descriptive statistics\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "01b704ef",
|
|
"metadata": {
|
|
"tags": [
|
|
"exercise"
|
|
]
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# TODO 1: convert packet_sizes from bytes to KB with a vectorized operation\n",
|
|
"packet_kb = None\n",
|
|
"\n",
|
|
"# TODO 2: calculate the mean and 95th percentile of latency_ms\n",
|
|
"mean_latency = None\n",
|
|
"p95_latency = None\n",
|
|
"\n",
|
|
"print(\"Packet sizes (KB):\", packet_kb)\n",
|
|
"print(\"Mean latency:\", mean_latency)\n",
|
|
"print(\"P95 latency:\", p95_latency)\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "34dfe8cd",
|
|
"metadata": {
|
|
"tags": [
|
|
"exercise"
|
|
]
|
|
},
|
|
"source": [
|
|
"## 2. Filter with a Boolean mask\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "070dc425",
|
|
"metadata": {
|
|
"tags": [
|
|
"exercise"
|
|
]
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# TODO 3: True when size > 1400 OR latency > 150 OR failures >= 8\n",
|
|
"suspicious_mask = None\n",
|
|
"\n",
|
|
"# TODO 4: obtain the indices matching the mask with np.where\n",
|
|
"suspicious_indices = None\n",
|
|
"\n",
|
|
"print(\"Mask:\", suspicious_mask)\n",
|
|
"print(\"Suspicious indices:\", suspicious_indices)\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "d5e6d529",
|
|
"metadata": {
|
|
"tags": [
|
|
"exercise"
|
|
]
|
|
},
|
|
"source": [
|
|
"## 3. Normalize values and create a risk score\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "4f126015",
|
|
"metadata": {
|
|
"tags": [
|
|
"exercise"
|
|
]
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def min_max(values):\n",
|
|
" values = np.asarray(values, dtype=float)\n",
|
|
" # TODO 5: return a zero array when max == min; otherwise apply min-max normalization\n",
|
|
" pass\n",
|
|
"\n",
|
|
"\n",
|
|
"latency_score = min_max(latency_ms)\n",
|
|
"failure_score = min_max(failed_attempts)\n",
|
|
"\n",
|
|
"# TODO 6: calculate 40% latency_score + 60% failure_score\n",
|
|
"risk_score = None\n",
|
|
"\n",
|
|
"print(\"Risk scores:\", risk_score)\n",
|
|
"print(\"Highest-risk index:\", None if risk_score is None else int(np.argmax(risk_score)))\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a4dcff69",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Self-check\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "a329c7f0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"assert packet_sizes.shape == (8,)\n",
|
|
"assert np.isclose(mean_latency, 78.0)\n",
|
|
"assert suspicious_indices.tolist() == [2, 4]\n",
|
|
"assert int(np.argmax(risk_score)) == 4\n",
|
|
"assert np.all((risk_score >= 0) & (risk_score <= 1))\n",
|
|
"print(\"✓ Lab 4 completed\")\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "915b1cef",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Extension challenge\n",
|
|
"\n",
|
|
"Change the weights assigned to latency and failed attempts. Observe whether the highest-risk element changes and explain why.\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
|
|
}
|