Files
labs/Lab-2/Lab-2-Solution/04_NumPy_Security_Metrics_Solution.ipynb
T

4.7 KiB

Module 2 — Lab 4: NumPy for Security Metrics

Topics: array, vectorization, statistics, boolean mask

Solution version: This notebook contains the complete solution. Run the cells in order and compare the results with your Lab notebook.

Scenario

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.

In [ ]:
import numpy as np

packet_sizes = np.array([64, 128, 1500, 512, 1514, 256, 1400, 80])
latency_ms = np.array([12.5, 18.0, 250.0, 33.5, 180.0, 25.0, 95.0, 10.0])
failed_attempts = np.array([0, 1, 8, 2, 10, 1, 6, 0])

print(packet_sizes.shape, packet_sizes.dtype)

1. Unit conversion and descriptive statistics

In [ ]:
packet_kb = packet_sizes / 1024
mean_latency = latency_ms.mean()
p95_latency = np.percentile(latency_ms, 95)

print("Packet sizes (KB):", np.round(packet_kb, 3))
print(f"Mean latency: {mean_latency:.2f} ms")
print(f"P95 latency: {p95_latency:.2f} ms")

2. Filter with a Boolean mask

In [ ]:
suspicious_mask = (packet_sizes > 1400) | (latency_ms > 150) | (failed_attempts >= 8)
suspicious_indices = np.where(suspicious_mask)[0]

print("Mask:", suspicious_mask)
print("Suspicious indices:", suspicious_indices)
print("Suspicious packet sizes:", packet_sizes[suspicious_mask])

3. Normalize values and create a risk score

In [ ]:
def min_max(values):
    values = np.asarray(values, dtype=float)
    value_range = values.max() - values.min()
    if value_range == 0:
        return np.zeros_like(values)
    return (values - values.min()) / value_range


latency_score = min_max(latency_ms)
failure_score = min_max(failed_attempts)
risk_score = 0.4 * latency_score + 0.6 * failure_score

print("Risk scores:", np.round(risk_score, 3))
print("Highest-risk index:", int(np.argmax(risk_score)))

Self-check

In [ ]:
assert packet_sizes.shape == (8,)
assert np.isclose(mean_latency, 78.0)
assert suspicious_indices.tolist() == [2, 4]
assert int(np.argmax(risk_score)) == 4
assert np.all((risk_score >= 0) & (risk_score <= 1))
print("✓ Lab 4 completed")

Extension challenge

Change the weights assigned to latency and failed attempts. Observe whether the highest-risk element changes and explain why.