In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# Preprocessing and Selection
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
# Models
from sklearn.cluster import KMeans, AgglomerativeClustering
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
# Metrics
from sklearn.metrics import (classification_report, confusion_matrix,
accuracy_score, precision_recall_fscore_support,
silhouette_score, roc_auc_score)
from sklearn.preprocessing import label_binarize
from scipy.cluster.hierarchy import dendrogram, linkage
In [14]:
# ==========================================
# 1. DATA LOADING AND EDA
# ==========================================
def load_and_inspect_data(filepath):
df = pd.read_csv(filepath)
print(f"---------------- Dataset Shape: ---------------- \n{df.shape}")
print(f"\n---------------- Dataset Info: ----------------")
df.info()
print(f"\n---------------- Dataset Head: ---------------- \n{df.head()}")
return df
def perform_exploratory_analysis(df):
print("\n---------------- Exploratory Data Analysis (EDA) ----------------")
numeric_df = df.select_dtypes(include=[np.number])
if 'PlayerID' in numeric_df.columns:
numeric_df = numeric_df.drop(columns=['PlayerID'])
# 1. Descriptive Stats
stats = numeric_df.describe().transpose()
print("---------------- Statistical Summary of Numeric Features: ----------------")
print(stats)
# 2. Correlation Matrix (New Step for Report)
print("\n---------------- Correlation Heatmap ----------------")
plt.figure(figsize=(10, 8))
correlation_matrix = numeric_df.corr()
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', fmt=".2f")
plt.title('Feature Correlation Matrix')
plt.show()
# Check correlation of PlayTimeHours
if 'PlayTimeHours' in correlation_matrix.columns:
print("\n---------------- Correlation of PlayTimeHours to other features: ----------------")
print(correlation_matrix['PlayTimeHours'].sort_values(ascending=False))
return stats
df = load_and_inspect_data("online_gaming_behavior_dataset.csv")
perform_exploratory_analysis(df)
---------------- Dataset Shape: ----------------
(40034, 13)
---------------- Dataset Info: ----------------
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 40034 entries, 0 to 40033
Data columns (total 13 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PlayerID 40034 non-null int64
1 Age 40034 non-null int64
2 Gender 40034 non-null object
3 Location 40034 non-null object
4 GameGenre 40034 non-null object
5 PlayTimeHours 40034 non-null float64
6 InGamePurchases 40034 non-null int64
7 GameDifficulty 40034 non-null object
8 SessionsPerWeek 40034 non-null int64
9 AvgSessionDurationMinutes 40034 non-null int64
10 PlayerLevel 40034 non-null int64
11 AchievementsUnlocked 40034 non-null int64
12 EngagementLevel 40034 non-null object
dtypes: float64(1), int64(7), object(5)
memory usage: 4.0+ MB
---------------- Dataset Head: ----------------
PlayerID Age Gender Location GameGenre PlayTimeHours InGamePurchases \
0 9000 43 Male Other Strategy 16.271119 0
1 9001 29 Female USA Strategy 5.525961 0
2 9002 22 Female USA Sports 8.223755 0
3 9003 35 Male USA Action 5.265351 1
4 9004 33 Male Europe Action 15.531945 0
GameDifficulty SessionsPerWeek AvgSessionDurationMinutes PlayerLevel \
0 Medium 6 108 79
1 Medium 5 144 11
2 Easy 16 142 35
3 Easy 9 85 57
4 Medium 2 131 95
AchievementsUnlocked EngagementLevel
0 25 Medium
1 10 Medium
2 41 High
3 47 Medium
4 37 Medium
---------------- Exploratory Data Analysis (EDA) ----------------
---------------- Statistical Summary of Numeric Features: ----------------
count mean std min \
Age 40034.0 31.992531 10.043227 15.000000
PlayTimeHours 40034.0 12.024365 6.914638 0.000115
InGamePurchases 40034.0 0.200854 0.400644 0.000000
SessionsPerWeek 40034.0 9.471774 5.763667 0.000000
AvgSessionDurationMinutes 40034.0 94.792252 49.011375 10.000000
PlayerLevel 40034.0 49.655568 28.588379 1.000000
AchievementsUnlocked 40034.0 24.526477 14.430726 0.000000
25% 50% 75% max
Age 23.000000 32.000000 41.000000 49.000000
PlayTimeHours 6.067501 12.008002 17.963831 23.999592
InGamePurchases 0.000000 0.000000 0.000000 1.000000
SessionsPerWeek 4.000000 9.000000 14.000000 19.000000
AvgSessionDurationMinutes 52.000000 95.000000 137.000000 179.000000
PlayerLevel 25.000000 49.000000 74.000000 99.000000
AchievementsUnlocked 12.000000 25.000000 37.000000 49.000000
---------------- Correlation Heatmap ----------------
---------------- Correlation of PlayTimeHours to other features: ---------------- PlayTimeHours 1.000000 AchievementsUnlocked 0.003913 Age 0.002462 AvgSessionDurationMinutes -0.001925 SessionsPerWeek -0.003655 PlayerLevel -0.005152 InGamePurchases -0.006067 Name: PlayTimeHours, dtype: float64
Out[14]:
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| Age | 40034.0 | 31.992531 | 10.043227 | 15.000000 | 23.000000 | 32.000000 | 41.000000 | 49.000000 |
| PlayTimeHours | 40034.0 | 12.024365 | 6.914638 | 0.000115 | 6.067501 | 12.008002 | 17.963831 | 23.999592 |
| InGamePurchases | 40034.0 | 0.200854 | 0.400644 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 |
| SessionsPerWeek | 40034.0 | 9.471774 | 5.763667 | 0.000000 | 4.000000 | 9.000000 | 14.000000 | 19.000000 |
| AvgSessionDurationMinutes | 40034.0 | 94.792252 | 49.011375 | 10.000000 | 52.000000 | 95.000000 | 137.000000 | 179.000000 |
| PlayerLevel | 40034.0 | 49.655568 | 28.588379 | 1.000000 | 25.000000 | 49.000000 | 74.000000 | 99.000000 |
| AchievementsUnlocked | 40034.0 | 24.526477 | 14.430726 | 0.000000 | 12.000000 | 25.000000 | 37.000000 | 49.000000 |
In [3]:
# ==========================================
# 2. PREPROCESSING
# ==========================================
def preprocess_data(df):
print("\n---------------- Preprocessing ----------------")
# Drop ID columns
cols_to_drop = ['PlayerID'] if 'PlayerID' in df.columns else []
# ---------------- FEATURE SELECTION DECISION ----------------
# Based on t-SNE observation PlayTimeHours causes noise/blurring in clusters.
# It's likely redundant with SessionsPerWeek & AvgSessionDuration.
# Dropped intentionally here to improve cluster seperation
if 'PlayTimeHours' in df.columns:
print(" -> Dropping 'PlayTimeHours' to reduce multicollinearity and improve cluster separation.")
cols_to_drop.append('PlayTimeHours')
if cols_to_drop:
print(f"Dropping column(s): {cols_to_drop}")
df = df.drop(cols_to_drop, axis=1)
# Outlier Removal (SMART IQR Method)
print("---------------- Extreme Outliers Checking (3.0x IQR Method) ----------------")
numeric_cols = df.select_dtypes(include=[np.number]).columns
Q1 = df[numeric_cols].quantile(0.25)
Q3 = df[numeric_cols].quantile(0.75)
IQR = Q3 - Q1
cols_to_check = IQR[IQR > 0].index.tolist()
if cols_to_check:
print(f" -> Calculating outliers on: {cols_to_check}")
condition = ~((df[cols_to_check] < (Q1[cols_to_check] - 3 * IQR[cols_to_check])) |
(df[cols_to_check] > (Q3[cols_to_check] + 3 * IQR[cols_to_check]))).any(axis=1)
df_clean = df[condition].copy()
print(f" -> Removed {len(df) - len(df_clean)} extreme outlier rows.")
else:
print(" -> No columns suitable for outlier removal.")
df_clean = df.copy()
# Separating Target Feature and other Features
target_col = 'EngagementLevel'
y = df_clean[target_col].copy()
X_raw = df_clean.drop(target_col, axis=1)
# Mapping Categorical Features
# Order matters for difficulty mapping, so manually mapped
difficulty_map = {'Easy': 0, 'Medium': 1, 'Hard': 2}
if 'GameDifficulty' in X_raw.columns:
X_raw['GameDifficulty'] = X_raw['GameDifficulty'].map(difficulty_map)
# Mapping with One-Hot Encoding for Gender, Location, Genre
categorical_cols = ['Gender', 'Location', 'GameGenre']
existing_cat_cols = [col for col in categorical_cols if col in X_raw.columns]
if existing_cat_cols:
print(f" -> One-Hot Encoding columns: {existing_cat_cols}")
X_encoded = pd.get_dummies(X_raw, columns=existing_cat_cols, drop_first=True)
else:
X_encoded = pd.get_dummies(X_raw, drop_first=True)
# Scaling
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_encoded)
X_scaled_df = pd.DataFrame(X_scaled, columns=X_encoded.columns)
# Encode Target
le = LabelEncoder()
y_encoded = le.fit_transform(y)
return X_scaled_df, y_encoded, le, X_raw, X_encoded.columns
X_scaled, y_encoded, label_encoder, X_raw, feature_names = preprocess_data(df)
---------------- Preprocessing ---------------- -> Dropping 'PlayTimeHours' to reduce multicollinearity and improve cluster separation. Dropping column(s): ['PlayerID', 'PlayTimeHours'] ---------------- Extreme Outliers Checking (3.0x IQR Method) ---------------- -> Calculating outliers on: ['Age', 'SessionsPerWeek', 'AvgSessionDurationMinutes', 'PlayerLevel', 'AchievementsUnlocked'] -> Removed 0 extreme outlier rows. -> One-Hot Encoding columns: ['Gender', 'Location', 'GameGenre']
In [15]:
# ==========================================
# 3. HELPER: VISUALIZE PROFILES
# ==========================================
def visualize_cluster_interpretation(X_analysis, clusters):
# Generates visual profiles for the clusters
print("\n---------------- Cluster Interpretation Plots ----------------")
# Work on a copy to avoid SettingWithCopy warnings on the main df
X_vis = X_analysis.copy()
X_vis['Cluster'] = clusters
# ---------------- NUMERIC HEATMAP ----------------
numeric_cols = X_vis.select_dtypes(include=[np.number]).columns.tolist()
if 'Cluster' in numeric_cols: numeric_cols.remove('Cluster')
# Calculate means
cluster_means = X_vis.groupby('Cluster')[numeric_cols].mean()
# Standardize row-wise (Z-score) just for the heatmap so scales match
scaler = StandardScaler()
cluster_means_scaled = pd.DataFrame(
scaler.fit_transform(cluster_means),
index=cluster_means.index,
columns=cluster_means.columns
)
plt.figure(figsize=(12, 6))
sns.heatmap(cluster_means_scaled.transpose(), annot=True, cmap='RdBu', center=0)
plt.title('Cluster Profiles (Numeric Features) | Blue = Higher than Avg, Red = Lower than Avg')
plt.xlabel('Cluster')
plt.tight_layout()
plt.show()
# ---------------- CATEGORICAL DISTRIBUTIONS ----------------
categorical_cols = X_vis.select_dtypes(include=['object', 'category']).columns
for col in categorical_cols:
plt.figure(figsize=(10, 5))
sns.countplot(data=X_vis, x='Cluster', hue=col, palette='viridis')
plt.title(f'Cluster Distribution by {col}')
plt.legend(title=col, bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
# ==========================================
# 4. UNSUPERVISED LEARNING: K-MEANS
# ==========================================
def run_kmeans_analysis(X_scaled_df, X_original_df):
print("\n---------------- Unsupervised Learning: K-Means Clustering ----------------")
wcss = []
silhouette_scores = []
k_range = range(2, 8)
print("Calculating optimal K...")
for k in k_range:
kmeans = KMeans(n_clusters=k, init='k-means++', random_state=42)
kmeans.fit(X_scaled_df)
wcss.append(kmeans.inertia_)
score = silhouette_score(X_scaled_df, kmeans.labels_, sample_size=3000, random_state=42)
silhouette_scores.append(score)
fig, ax1 = plt.subplots(figsize=(10, 5))
ax1.set_xlabel('Number of Clusters (k)')
ax1.set_ylabel('Inertia (WCSS)', color='tab:blue')
ax1.plot(k_range, wcss, marker='o', color='tab:blue')
ax2 = ax1.twinx()
ax2.set_ylabel('Silhouette Score', color='tab:red')
ax2.plot(k_range, silhouette_scores, marker='s', color='tab:red')
plt.title('K-Means Performance: Elbow Method & Silhouette Score')
plt.show()
best_k = k_range[np.argmax(silhouette_scores)]
print(f"Optimal K determined: {best_k}")
kmeans_final = KMeans(n_clusters=best_k, init='k-means++', random_state=42)
clusters = kmeans_final.fit_predict(X_scaled_df)
print("\n---------------- K-Means Cluster Interpretation ----------------")
X_analysis = X_original_df.copy()
X_analysis['Cluster'] = clusters
numeric_cols = X_analysis.select_dtypes(include=[np.number]).columns
feat_cols = [c for c in numeric_cols if c != 'Cluster']
print(X_analysis.groupby('Cluster')[feat_cols].mean().transpose())
# --- CALL VISUALIZATION FUNCTION ---
visualize_cluster_interpretation(X_original_df, clusters)
print("\n---------------- t-SNE Visualization for K-Means ----------------")
sample_size = min(3000, len(X_scaled_df))
indices = np.random.choice(len(X_scaled_df), sample_size, replace=False)
tsne = TSNE(n_components=2, perplexity=40, random_state=42)
tsne_results = tsne.fit_transform(X_scaled_df.iloc[indices])
plt.figure(figsize=(10, 6))
sns.scatterplot(x=tsne_results[:,0], y=tsne_results[:,1], hue=clusters[indices], palette='viridis', s=60)
plt.title(f'K-Means t-SNE Visualization (k={best_k})')
plt.show()
return best_k
# ==========================================
# 5. HIERARCHICAL
# ==========================================
def run_hierarchical_analysis(X_scaled_df, n_clusters, X_original_df):
print("\n---------------- Unsupervised Learning: Hierarchical (Agglomerative) Clustering ----------------")
sample_size = min(3000, len(X_scaled_df))
print(f"Sampling {sample_size} rows for Dendrogram and Clustering...")
X_sample_scaled = X_scaled_df.sample(n=sample_size, random_state=42)
X_sample_original = X_original_df.loc[X_sample_scaled.index]
print("Generating Dendrogram...")
plt.figure(figsize=(12, 6))
plt.title("Hierarchical Clustering Dendrogram")
plt.xlabel("Sample Index")
plt.ylabel("Distance (Ward's Method)")
Z = linkage(X_sample_scaled, method='ward')
dendrogram(Z, leaf_rotation=90., leaf_font_size=8., truncate_mode='lastp', p=30)
plt.axhline(y=30, color='r', linestyle='--')
plt.show()
print(f"---------------- Agglomerative Clustering with k={n_clusters} (from K-Means) ----------------")
hc = AgglomerativeClustering(n_clusters=n_clusters, metric='euclidean', linkage='ward')
clusters_hc = hc.fit_predict(X_sample_scaled)
score = silhouette_score(X_sample_scaled, clusters_hc)
print(f"Hierarchical Clustering Silhouette Score: {score:.4f}")
print("\n---------------- Hierarchial Cluster Interpretation ----------------")
X_analysis = X_sample_original.copy()
X_analysis['Cluster'] = clusters_hc
numeric_cols = X_analysis.select_dtypes(include=[np.number]).columns
feat_cols = [c for c in numeric_cols if c != 'Cluster']
print(X_analysis.groupby('Cluster')[feat_cols].mean().transpose())
# --- CALL VISUALIZATION FUNCTION ---
visualize_cluster_interpretation(X_sample_original, clusters_hc)
print("---------------- t-SNE Visualization for Hierarchical Clustering ----------------")
tsne = TSNE(n_components=2, perplexity=40, random_state=42)
tsne_results = tsne.fit_transform(X_sample_scaled)
plt.figure(figsize=(10, 6))
sns.scatterplot(x=tsne_results[:,0], y=tsne_results[:,1], hue=clusters_hc, palette='cool', s=60)
plt.title(f'Hierarchical Clustering Visualization (k={n_clusters})')
plt.show()
optimal_k = run_kmeans_analysis(X_scaled, X_raw)
run_hierarchical_analysis(X_scaled, optimal_k, X_raw)
---------------- Unsupervised Learning: K-Means Clustering ---------------- Calculating optimal K...
Optimal K determined: 6 ---------------- K-Means Cluster Interpretation ---------------- Cluster 0 1 2 3 \ Age 31.962389 32.102681 31.976197 31.703499 InGamePurchases 0.193139 0.197806 0.208552 0.202185 GameDifficulty 0.696061 0.688956 0.697481 0.710275 SessionsPerWeek 9.442440 9.509885 9.503737 9.443092 AvgSessionDurationMinutes 94.943837 95.332367 95.688486 94.345457 PlayerLevel 50.181957 49.812856 49.901744 49.584566 AchievementsUnlocked 24.154511 24.513301 24.639773 24.747338 Cluster 4 5 Age 32.002712 32.161380 InGamePurchases 0.200292 0.200473 GameDifficulty 0.715210 0.699499 SessionsPerWeek 9.416858 9.469950 AvgSessionDurationMinutes 93.137284 94.635364 PlayerLevel 49.539745 49.057179 AchievementsUnlocked 24.444398 24.466472 ---------------- Cluster Interpretation Plots ----------------
---------------- t-SNE Visualization for K-Means ----------------
---------------- Unsupervised Learning: Hierarchical (Agglomerative) Clustering ---------------- Sampling 3000 rows for Dendrogram and Clustering... Generating Dendrogram...
---------------- Agglomerative Clustering with k=6 (from K-Means) ---------------- Hierarchical Clustering Silhouette Score: 0.1373 ---------------- Hierarchial Cluster Interpretation ---------------- Cluster 0 1 2 3 \ Age 31.910880 32.116667 32.680141 31.816327 InGamePurchases 0.010417 0.016667 0.188049 0.197279 GameDifficulty 0.660880 0.704762 0.706503 0.646259 SessionsPerWeek 9.584491 9.092857 9.342707 9.384354 AvgSessionDurationMinutes 94.428241 97.314286 98.337434 91.972789 PlayerLevel 48.932870 47.390476 49.576450 52.363946 AchievementsUnlocked 24.893519 24.840476 25.472759 23.744898 Cluster 4 5 Age 32.443431 31.655738 InGamePurchases 0.222628 1.000000 GameDifficulty 0.748175 0.718033 SessionsPerWeek 9.250000 9.836066 AvgSessionDurationMinutes 96.702555 92.836066 PlayerLevel 50.434307 49.547541 AchievementsUnlocked 24.211679 25.514754 ---------------- Cluster Interpretation Plots ----------------
---------------- t-SNE Visualization for Hierarchical Clustering ----------------
In [73]:
# ==========================================
# 4. SUPERVISED LEARNING: COMPARISON
# ==========================================
def evaluate_model(model, X_test, y_test, class_names, model_name):
# Evaluates model and returns a dictionary of metrics for comparison.
y_pred = model.predict(X_test)
# Calculate Metrics
acc = accuracy_score(y_test, y_pred)
# Weighted average is best for multi-class balance
precision, recall, f1, _ = precision_recall_fscore_support(y_test, y_pred, average='weighted')
print(f"\n--- Evaluation: {model_name} ---")
print(f"Accuracy: {acc:.4f}")
print("Classification Report:")
print(classification_report(y_test, y_pred, target_names=class_names))
# Confusion Matrix Plot
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(6, 5))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=class_names, yticklabels=class_names)
plt.title(f'Confusion Matrix: {model_name}')
plt.xlabel('Predicted Label')
plt.ylabel('Actual Label')
plt.show()
# ROC-AUC Calculation
auc_score = 0
if hasattr(model, "predict_proba") or hasattr(model, "decision_function"):
try:
y_test_bin = label_binarize(y_test, classes=range(len(class_names)))
if hasattr(model, "predict_proba"):
y_score = model.predict_proba(X_test)
else:
y_score = model.decision_function(X_test)
auc_score = roc_auc_score(y_test_bin, y_score, multi_class='ovr', average='weighted')
print(f"Weighted AUC-ROC Score: {auc_score:.4f}")
except Exception as e:
print(f"Could not calculate ROC-AUC: {e}")
# Return metrics for the comparison chart
return {
'Model': model_name,
'Accuracy': acc,
'Precision': precision,
'Recall': recall,
'F1-Score': f1,
'AUC-ROC': auc_score
}
def compare_models(results):
# Plots a grouped bar chart comparing all models.
print("\n---------------- Model Comparison Summary ----------------")
results_df = pd.DataFrame(results)
# Melt dataframe for Seaborn plotting
df_melted = results_df.melt(id_vars="Model", var_name="Metric", value_name="Score")
plt.figure(figsize=(12, 6))
sns.barplot(x="Metric", y="Score", hue="Model", data=df_melted, palette="viridis")
plt.title("Model Performance Comparison")
plt.ylim(0.5, 1.0)
plt.ylabel("Score (Zoomed in for visualisation purposes | 0.0 - 1.0)")
plt.legend(bbox_to_anchor=(1.05, 1))
plt.grid(axis='y', linestyle='--', alpha=0.8)
plt.tight_layout()
plt.show()
print(results_df)
def run_supervised_learning(X, y, class_names):
print("\n---------------- Supervised Learning: Model Development & Tuning ----------------")
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model_results = [] # Store results here
# ----------------------------------------
# 1. Decision Tree (DT)
# ----------------------------------------
print("\n---------------- Decision Tree Classifier ----------------")
dt_params = {
'max_depth': [None, 5, 10, 20],
'min_samples_split': [2, 5, 10],
'criterion': ['gini', 'entropy']
}
dt = DecisionTreeClassifier(random_state=42)
dt_grid = ll(dt, dt_params, cv=5, scoring='accuracy', n_jobs=-1)
dt_grid.fit(X_train, y_train)
print(f"Best DT Parameters: {dt_grid.best_params_}")
res_dt = evaluate_model(dt_grid.best_estimator_, X_test, y_test, class_names, "Decision Tree")
model_results.append(res_dt)
# ----------------------------------------
# 2. Support Vector Machine (SVM)
# ----------------------------------------
print("\n---------------- Support Vector Machine (SVM) ----------------")
print("Sampling 5,000 rows for SVM training to prevent crash")
sample_size = min(5000, len(X_train))
X_train_svm, _, y_train_svm, _ = train_test_split(
X_train, y_train, train_size=sample_size, stratify=y_train, random_state=42
)
svm_params = {
'C': [0.1, 1, 10],
'kernel': ['rbf', 'linear'],
'gamma': ['scale', 'auto']
}
svm = SVC(probability=True, random_state=42)
svm_grid = GridSearchCV(svm, svm_params, cv=3, scoring='accuracy', n_jobs=-1)
svm_grid.fit(X_train_svm, y_train_svm)
print(f"Best SVM Parameters: {svm_grid.best_params_}")
res_svm = evaluate_model(svm_grid.best_estimator_, X_test, y_test, class_names, "SVM")
model_results.append(res_svm)
# ----------------------------------------
# 3. K-Nearest Neighbors (KNN)
# ----------------------------------------
print("\n---------------- Training K-Nearest Neighbors (KNN) ----------------")
knn_params = {
'n_neighbors': [3, 5, 7, 11, 15],
'weights': ['uniform', 'distance'],
'metric': ['euclidean', 'manhattan']
}
knn = KNeighborsClassifier()
knn_grid = GridSearchCV(knn, knn_params, cv=3, scoring='accuracy', n_jobs=-1)
knn_grid.fit(X_train, y_train)
print(f"Best KNN Parameters: {knn_grid.best_params_}")
res_knn = evaluate_model(knn_grid.best_estimator_, X_test, y_test, class_names, "KNN")
model_results.append(res_knn)
# ----------------------------------------
# 4. Compare All
# ----------------------------------------
compare_models(model_results)
class_names = label_encoder.classes_
run_supervised_learning(X_scaled, y_encoded, class_names)
---------------- Supervised Learning: Model Development & Tuning ----------------
---------------- Decision Tree Classifier ----------------
Best DT Parameters: {'criterion': 'entropy', 'max_depth': 10, 'min_samples_split': 10}
--- Evaluation: Decision Tree ---
Accuracy: 0.8976
Classification Report:
precision recall f1-score support
High 0.90 0.88 0.89 2035
Low 0.89 0.86 0.88 2093
Medium 0.90 0.93 0.91 3879
accuracy 0.90 8007
macro avg 0.90 0.89 0.89 8007
weighted avg 0.90 0.90 0.90 8007
Weighted AUC-ROC Score: 0.9290
---------------- Support Vector Machine (SVM) ----------------
[SAFE MODE] Sampling 5,000 rows for SVM training to prevent crash...
Best SVM Parameters: {'C': 1, 'gamma': 'auto', 'kernel': 'rbf'}
--- Evaluation: SVM ---
Accuracy: 0.8620
Classification Report:
precision recall f1-score support
High 0.89 0.85 0.87 2035
Low 0.87 0.78 0.82 2093
Medium 0.85 0.91 0.88 3879
accuracy 0.86 8007
macro avg 0.87 0.85 0.86 8007
weighted avg 0.86 0.86 0.86 8007
Weighted AUC-ROC Score: 0.9334
---------------- Training K-Nearest Neighbors (KNN) ----------------
Best KNN Parameters: {'metric': 'manhattan', 'n_neighbors': 15, 'weights': 'distance'}
--- Evaluation: KNN ---
Accuracy: 0.7828
Classification Report:
precision recall f1-score support
High 0.87 0.74 0.80 2035
Low 0.84 0.59 0.69 2093
Medium 0.73 0.91 0.81 3879
accuracy 0.78 8007
macro avg 0.81 0.75 0.77 8007
weighted avg 0.80 0.78 0.78 8007
Weighted AUC-ROC Score: 0.8946 ---------------- Model Comparison Summary ----------------
Model Accuracy Precision Recall F1-Score AUC-ROC 0 Decision Tree 0.897590 0.897506 0.897590 0.897358 0.928957 1 SVM 0.861996 0.863079 0.861996 0.861206 0.933361 2 KNN 0.782815 0.796061 0.782815 0.778149 0.894602
In [ ]: