In [2]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.ensemble import RandomForestClassifier, HistGradientBoostingClassifier
from sklearn.metrics import (classification_report, accuracy_score, confusion_matrix)
from sklearn.inspection import permutation_importance

# Load Training Set file
file_path = 'kdd_train.csv'  # Finds training data
df = pd.read_csv(file_path)

# Handle missing values
df.replace(" ", np.nan, inplace=True)
df.dropna(inplace=True)

for col in df.select_dtypes(include=['object']).columns:
    df[col] = LabelEncoder().fit_transform(df[col])

target_col = df.columns[-1]

counts = df[target_col].value_counts()
small_classes = counts[counts < 10].index # Only counts classes with 10+ samples
df = df[~df[target_col].isin(small_classes)]

normal_label = df[target_col].value_counts().idxmax()
df["binary_label"] = (df[target_col] != normal_label).astype(int)
x = df.drop([target_col, "binary_label"], axis=1)
y = df ["binary_label"]

# Train-test split
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42, stratify=y)

# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

# ///////////////////////////////////////////////// RandForest ///////////////////////////////////////////////////

rf = RandomForestClassifier(random_state=42)

rf_params = {"n_estimators": [50, 100], "max_depth": [None, 10, 20], "min_samples_split": [2, 5]} # Parameters

rf_grid = GridSearchCV(rf, rf_params, cv=2, n_jobs=-1, scoring="f1_macro")
print("\nBeginning grid search (RandForest):") # Training takes a long time - this verifies the program is actually running
rf_grid.fit(X_train, y_train)
print("Done") # Verifies training is finished
rf_best = rf_grid.best_estimator_

# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

# ///////////////////////////////////////////////// GradBoost ////////////////////////////////////////////////////

gb = HistGradientBoostingClassifier(random_state=42)

gb_params = {"max_iter": [50, 100], "max_depth": [None, 10], "learning_rate": [0.05, 0.1]} # Parameters

gb_grid = GridSearchCV(gb, gb_params, cv=2, scoring="f1_macro")
print("\nBeginning grid search (GradBoost):") # Training takes a long time - this verifies the program is actually running
gb_grid.fit(X_train, y_train)
print("Done") # Verifies training is finished
gb_best = gb_grid.best_estimator_

# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

# Evaluating Model
def evaluate_model(model, X_test, y_test, model_name):
    y_pred = model.predict(X_test)

    print(f"\n{model_name}")
    print("Accuracy:", accuracy_score(y_test, y_pred))
    print("\nClassification Report:\n", classification_report(y_test, y_pred))

    cm = confusion_matrix(y_test, y_pred) # Creates confusion matrix

    sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=["Negative", "Positive"], yticklabels=["Negative", "Positive"]) # Formatting for conf. matrix
    plt.title(f"{model_name} Confusion Matrix") # Title
    plt.xlabel("Predicted") # X Label
    plt.ylabel("Actual") # Y Label
    plt.show()

evaluate_model(rf_best, X_test, y_test, "Random Forest")
evaluate_model(gb_best, X_test, y_test, "Gradient Boosting")

rf_importance = pd.Series(rf_best.feature_importances_, index=X_train.columns).sort_values(ascending=False) # Importance chart - RandForest
plt.figure(figsize = (10, 6))
rf_importance.head(10).plot(kind="bar") # Bar chart
plt.title("10 Most Important Features (Random Forest)")
plt.ylabel("Importance Score")
plt.xticks(rotation=45, ha="right") # Chart formatting
plt.tight_layout()
plt.show()

permutation_importance = permutation_importance(gb_best, X_test, y_test, n_repeats=5, random_state=42, scoring="f1") # Importance chart - GradBoost (Hist)
gb_importance = pd.Series(permutation_importance.importances_mean, index=X_train.columns).sort_values(ascending=False)
plt.figure(figsize = (10, 6))
gb_importance.head(10).plot(kind="bar") # Bar chart
plt.title("10 Most Important Features (Gradient Boosting)")
plt.ylabel("Importance Score")
plt.xticks(rotation=45, ha="right") # Chart formatting
plt.tight_layout()
plt.show()
Beginning grid search (RandForest):
Done

Beginning grid search (GradBoost):
C:\Users\w4rr1\anaconda3\Lib\site-packages\joblib\externals\loky\backend\context.py:136: UserWarning: Could not find the number of physical cores for the following reason:
[WinError 2] The system cannot find the file specified
Returning the number of logical cores instead. You can silence this warning by setting LOKY_MAX_CPU_COUNT to the number of cores you want to use.
  warnings.warn(
  File "C:\Users\w4rr1\anaconda3\Lib\site-packages\joblib\externals\loky\backend\context.py", line 257, in _count_physical_cores
    cpu_info = subprocess.run(
        "wmic CPU Get NumberOfCores /Format:csv".split(),
        capture_output=True,
        text=True,
    )
  File "C:\Users\w4rr1\anaconda3\Lib\subprocess.py", line 554, in run
    with Popen(*popenargs, **kwargs) as process:
         ~~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\w4rr1\anaconda3\Lib\subprocess.py", line 1039, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                        pass_fds, cwd, env,
                        ^^^^^^^^^^^^^^^^^^^
    ...<5 lines>...
                        gid, gids, uid, umask,
                        ^^^^^^^^^^^^^^^^^^^^^^
                        start_new_session, process_group)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\w4rr1\anaconda3\Lib\subprocess.py", line 1554, in _execute_child
    hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
                       ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
                             # no special security
                             ^^^^^^^^^^^^^^^^^^^^^
    ...<4 lines>...
                             cwd,
                             ^^^^
                             startupinfo)
                             ^^^^^^^^^^^^
Done

Random Forest
Accuracy: 0.9990471653168176

Classification Report:
               precision    recall  f1-score   support

           0       1.00      1.00      1.00     13469
           1       1.00      1.00      1.00     11719

    accuracy                           1.00     25188
   macro avg       1.00      1.00      1.00     25188
weighted avg       1.00      1.00      1.00     25188

No description has been provided for this image
Gradient Boosting
Accuracy: 0.9990471653168176

Classification Report:
               precision    recall  f1-score   support

           0       1.00      1.00      1.00     13469
           1       1.00      1.00      1.00     11719

    accuracy                           1.00     25188
   macro avg       1.00      1.00      1.00     25188
weighted avg       1.00      1.00      1.00     25188

No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [ ]: