Spaces:
Sleeping
Sleeping
| """ | |
| Train and evaluate multimodal machine learning models for Parkinson's disease classification. | |
| This script combines traditional ML, transformer models, and ensemble methods. | |
| """ | |
| import os | |
| import sys | |
| import numpy as np | |
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| from sklearn.metrics import classification_report, confusion_matrix | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| # Add src directory to path | |
| sys.path.append(os.path.join(os.path.dirname(__file__))) | |
| sys.path.append(os.path.join(os.path.dirname(__file__), 'models')) | |
| from data_preprocessing import DataPreprocessor | |
| from models.multimodal_ml import MultimodalEnsemble, AdvancedFeatureEngineering, create_multimodal_pipeline | |
| def main(): | |
| """Main function to run multimodal ML pipeline.""" | |
| print("Multimodal Machine Learning for Parkinson's Disease Classification") | |
| print("=" * 70) | |
| # --- Load and prepare data --- | |
| preprocessor = DataPreprocessor() | |
| base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| file_paths = [ | |
| os.path.join(base_dir, "PPMI_Curated_Data_Cut_Public_20241211.csv"), | |
| os.path.join(base_dir, "PPMI_Curated_Data_Cut_Public_20250321.csv"), | |
| os.path.join(base_dir, "PPMI_Curated_Data_Cut_Public_20250714.csv"), | |
| ] | |
| print("\nLoading and preparing data with patient-level split...") | |
| X_train, X_test, y_train, y_test = preprocessor.prepare_data( | |
| file_paths, | |
| test_size=0.2, | |
| use_patient_split=True, | |
| ) | |
| print(f" Train: {X_train.shape}, Test: {X_test.shape}") | |
| # Convert to numpy arrays if they are DataFrames | |
| if isinstance(X_train, pd.DataFrame): | |
| X_train_np = X_train.values | |
| X_test_np = X_test.values | |
| else: | |
| X_train_np = X_train | |
| X_test_np = X_test | |
| if isinstance(y_train, pd.Series): | |
| y_train_np = y_train.values | |
| y_test_np = y_test.values | |
| else: | |
| y_train_np = y_train | |
| y_test_np = y_test | |
| # Create multimodal pipeline | |
| print("\nCreating multimodal ML pipeline...") | |
| ensemble, results = create_multimodal_pipeline(X_train, X_test, y_train_np, y_test_np) | |
| # Detailed evaluation of ensemble | |
| if ensemble.ensemble_model is not None: | |
| print("\nDetailed Ensemble Evaluation:") | |
| print("-" * 40) | |
| ensemble_results = ensemble.evaluate_ensemble(X_test, y_test_np) | |
| print(f"Ensemble Accuracy: {ensemble_results['accuracy']:.4f}") | |
| print("\nClassification Report:") | |
| print(ensemble_results['classification_report']) | |
| # Plot confusion matrix | |
| os.makedirs('notebooks', exist_ok=True) | |
| plt.figure(figsize=(10, 8)) | |
| sns.heatmap(ensemble_results['confusion_matrix'], | |
| annot=True, fmt='d', cmap='Blues', | |
| xticklabels=['HC', 'PD', 'SWEDD', 'PRODROMAL'], | |
| yticklabels=['HC', 'PD', 'SWEDD', 'PRODROMAL']) | |
| plt.title('Multimodal Ensemble - Confusion Matrix') | |
| plt.ylabel('True Label') | |
| plt.xlabel('Predicted Label') | |
| plt.tight_layout() | |
| plt.savefig('notebooks/multimodal_confusion_matrix.png', dpi=300, bbox_inches='tight') | |
| plt.close() | |
| print("Confusion matrix saved to notebooks/multimodal_confusion_matrix.png") | |
| # Advanced analysis | |
| print("\nAdvanced Multimodal Analysis:") | |
| print("-" * 40) | |
| # Feature importance analysis (if available) | |
| if hasattr(ensemble.ensemble_model, 'coef_'): | |
| feature_importance = np.abs(ensemble.ensemble_model.coef_).mean(axis=0) | |
| print("Top 10 most important ensemble features:") | |
| top_indices = np.argsort(feature_importance)[-10:][::-1] | |
| for i, idx in enumerate(top_indices): | |
| print(f"{i+1:2d}. Feature {idx}: {feature_importance[idx]:.4f}") | |
| # Model diversity analysis | |
| print("\nModel Diversity Analysis:") | |
| if len(ensemble.traditional_models) > 0 and len(ensemble.transformer_models) > 0: | |
| trad_preds, _ = ensemble.get_traditional_predictions(X_test) | |
| trans_preds, _ = ensemble.get_transformer_predictions(X_test_np) | |
| if trad_preds and trans_preds: | |
| trad_pred = list(trad_preds.values())[0] | |
| trans_pred = list(trans_preds.values())[0] | |
| agreement = np.mean(trad_pred == trans_pred) | |
| print(f"Agreement between traditional and transformer models: {agreement:.4f}") | |
| # Performance summary | |
| print("\nFinal Performance Summary:") | |
| print("-" * 40) | |
| best_model = max(results.items(), key=lambda x: x[1]) | |
| print(f"Best performing model: {best_model[0]} (Accuracy: {best_model[1]:.4f})") | |
| if 'Ensemble' in results: | |
| ensemble_acc = results['Ensemble'] | |
| individual_accs = [acc for name, acc in results.items() if name != 'Ensemble'] | |
| if individual_accs: | |
| avg_individual = np.mean(individual_accs) | |
| improvement = ensemble_acc - avg_individual | |
| print(f"Ensemble improvement over average individual model: {improvement:.4f}") | |
| print("\nMultimodal ML pipeline completed successfully!") | |
| print("Results and visualizations saved to notebooks/ directory") | |
| if __name__ == "__main__": | |
| main() |