6.8 KiB
6.8 KiB
In [ ]:
from pathlib import Path
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
DATA_PATH = Path("data/malware_features.csv")
if not DATA_PATH.exists():
raise FileNotFoundError(
"Missing data/malware_features.csv. Follow data/README.md, place the three "
"official UCI CSV files under data/raw/, and run: python data/prepare_dataset.py"
)
from sklearn.dummy import DummyClassifier
from sklearn.impute import SimpleImputer
from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score, accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_text, plot_tree
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),
"malware_precision": precision_score(y_true, y_pred, zero_division=0),
"malware_recall": recall_score(y_true, y_pred, zero_division=0),
"malware_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,
}In [ ]:
# TODO 1: load data, define X/y, and make an 80/20 stratified split.
df = None
feature_cols = None
X = None
y = None
X_train, X_test, y_train, y_test = None, None, None, None
# TODO 2: implement make_tree and fit a bounded tree (depth 4, leaf 10)
# and an unrestricted tree (no maximum depth, leaf 1).
def make_tree(max_depth, min_samples_leaf):
pass
bounded_tree = None
unrestricted_tree = NoneIn [ ]:
# TODO 3: create complexity_comparison with depth, leaves, train/test F1,
# F1 gap, test recall, and test false-positive rate for both trees.
complexity_comparison = None
display(complexity_comparison)In [ ]:
# TODO 4: obtain transformed feature names, plot the bounded tree, and
# export its rules as text with max_depth=4.
imputer = None
estimator = None
transformed_names = None
rule_text = None
print(rule_text)In [ ]:
# TODO 5: create a descending importance Series using transformed names,
# display the top 12, and plot a horizontal bar chart.
importance = None
top_importance = None
display(top_importance)In [ ]:
assert bounded_tree.named_steps["tree"].get_depth() <= 4
assert unrestricted_tree.named_steps["tree"].get_depth() >= bounded_tree.named_steps["tree"].get_depth()
assert complexity_comparison.loc["unrestricted", "leaves"] >= complexity_comparison.loc["bounded", "leaves"]
assert isinstance(rule_text, str) and "class:" in rule_text
assert np.isclose(importance.sum(), 1.0)
assert len(top_importance) <= 12
print("✓ Lab 5 completed")