Spaces:
Sleeping
Sleeping
| """ | |
| 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() | |