Simon
Model evealuation (#10)
a9f0e5a
Raw
History Blame Contribute Delete
6.01 kB
"""
Visualization utilities for model evaluation.
This module provides:
- Model comparison plots
- Confusion matrix visualizations
- Feature importance plots
"""
import logging
from typing import Dict, Any
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix
logger = logging.getLogger(__name__)
def plot_model_comparison(results_df: pd.DataFrame, output_path: str = 'model_comparison.png'):
"""
Create visualization comparing model performance.
Args:
results_df: DataFrame with model metrics
output_path: Path to save the plot
"""
logger.info("Creating model comparison visualizations...")
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
# 1. Validation Accuracy comparison
ax = axes[0, 0]
results_df_sorted = results_df.sort_values('Val Accuracy')
ax.barh(results_df_sorted['Model'], results_df_sorted['Val Accuracy'])
ax.set_xlabel('Validation Accuracy')
ax.set_title('Model Comparison: Validation Accuracy')
ax.set_xlim(0, 1)
for i, v in enumerate(results_df_sorted['Val Accuracy']):
ax.text(v + 0.01, i, f'{v:.3f}', va='center')
# 2. Precision, Recall, F1 comparison
ax = axes[0, 1]
metrics_df = results_df[['Model', 'Precision', 'Recall', 'F1 Score']].set_index('Model')
metrics_df.plot(kind='bar', ax=ax)
ax.set_title('Model Comparison: Precision, Recall, F1')
ax.set_ylabel('Score')
ax.set_ylim(0, 1)
ax.legend(loc='lower right')
ax.tick_params(axis='x', rotation=45)
# 3. ROC-AUC comparison
ax = axes[1, 0]
results_df_sorted = results_df.sort_values('ROC-AUC')
ax.barh(results_df_sorted['Model'], results_df_sorted['ROC-AUC'])
ax.set_xlabel('ROC-AUC Score')
ax.set_title('Model Comparison: ROC-AUC')
ax.set_xlim(0, 1)
for i, v in enumerate(results_df_sorted['ROC-AUC']):
ax.text(v + 0.01, i, f'{v:.3f}', va='center')
# 4. Overfitting analysis
ax = axes[1, 1]
results_df_sorted = results_df.sort_values('Overfit (Train-Val)')
colors = ['red' if x > 0.1 else 'orange' if x > 0.05 else 'green'
for x in results_df_sorted['Overfit (Train-Val)']]
ax.barh(results_df_sorted['Model'], results_df_sorted['Overfit (Train-Val)'], color=colors)
ax.set_xlabel('Train - Val Accuracy')
ax.set_title('Overfitting Analysis (Lower is Better)')
ax.axvline(x=0.05, color='orange', linestyle='--', alpha=0.5, label='Warning threshold')
ax.axvline(x=0.1, color='red', linestyle='--', alpha=0.5, label='High overfit threshold')
ax.legend()
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight')
logger.info(f"Saved model comparison plot to {output_path}")
plt.close()
def plot_confusion_matrices(
models: Dict[str, Any],
X: pd.DataFrame,
y: pd.Series,
output_path: str = 'confusion_matrices.png'
):
"""
Create confusion matrices for all models.
Args:
models: Dictionary of trained models
X: Features
y: True labels
output_path: Path to save the plot
"""
logger.info("Creating confusion matrices...")
n_models = len(models)
n_cols = 3
n_rows = (n_models + n_cols - 1) // n_cols
fig, axes = plt.subplots(n_rows, n_cols, figsize=(15, 5 * n_rows))
axes = axes.flatten() if n_models > 1 else [axes]
for idx, (name, model) in enumerate(models.items()):
y_pred = model.predict(X)
cm = confusion_matrix(y, y_pred)
ax = axes[idx]
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', ax=ax)
ax.set_title(f'{name}\nConfusion Matrix')
ax.set_ylabel('Actual')
ax.set_xlabel('Predicted')
ax.set_xticklabels(['Legitimate', 'Phishing'])
ax.set_yticklabels(['Legitimate', 'Phishing'])
# Hide unused subplots
for idx in range(n_models, len(axes)):
axes[idx].axis('off')
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight')
logger.info(f"Saved confusion matrices to {output_path}")
plt.close()
def plot_feature_importance(
importance_df: pd.DataFrame,
mean_importance_df: pd.DataFrame,
output_path: str = 'feature_importance.png'
):
"""
Create visualizations of feature importance.
Args:
importance_df: DataFrame with feature importances per model
mean_importance_df: DataFrame with mean importances
output_path: Path to save the plot
"""
logger.info("Creating feature importance visualizations...")
fig, axes = plt.subplots(1, 2, figsize=(16, 6))
# 1. Mean feature importance across all models
ax = axes[0]
ax.barh(mean_importance_df['Feature'], mean_importance_df['Mean Importance'])
ax.set_xlabel('Mean Importance Score')
ax.set_title('Feature Importance (Averaged Across All Models)')
ax.invert_yaxis()
# Add error bars
ax.errorbar(
mean_importance_df['Mean Importance'],
range(len(mean_importance_df)),
xerr=mean_importance_df['Std Importance'],
fmt='none',
ecolor='gray',
alpha=0.5
)
for i, v in enumerate(mean_importance_df['Mean Importance']):
ax.text(v + 0.01, i, f'{v:.3f}', va='center')
# 2. Feature importance heatmap per model
ax = axes[1]
# Pivot to get features as rows and models as columns
pivot_df = importance_df.pivot_table(
index='Feature',
columns='Model',
values='Importance',
aggfunc='first'
)
# Plot heatmap
sns.heatmap(
pivot_df,
annot=True,
fmt='.3f',
cmap='YlOrRd',
ax=ax,
cbar_kws={'label': 'Importance Score'}
)
ax.set_title('Feature Importance by Model')
ax.set_xlabel('Model')
ax.set_ylabel('Feature')
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight')
logger.info(f"Saved feature importance plot to {output_path}")
plt.close()