From 283ca8dfd9458ea071d759cc37224c638e49c5c3 Mon Sep 17 00:00:00 2001 From: Joaquin Torres Bravo Date: Fri, 24 May 2024 11:02:59 +0200 Subject: [PATCH] Ready to test new integration with DT --- model_selection/cv_metric_gen.py | 111 +++++++++++++------------ model_selection/output_cv_metrics.xlsx | Bin 31899 -> 0 bytes 2 files changed, 59 insertions(+), 52 deletions(-) delete mode 100644 model_selection/output_cv_metrics.xlsx diff --git a/model_selection/cv_metric_gen.py b/model_selection/cv_metric_gen.py index 2042928..b5f4a08 100644 --- a/model_selection/cv_metric_gen.py +++ b/model_selection/cv_metric_gen.py @@ -175,8 +175,8 @@ if __name__ == "__main__": # Metric generation through cv for tuned models3 # -------------------------------------------------------------------------------------------------------- scores_sheets = {} # To store score dfs as sheets in the same excel file - for i, group in enumerate(['pre', 'post']): # 'post' - for j, method in enumerate(['', 'over_', 'under_']): + for i, group in enumerate(['pre']): + for j, method in enumerate(['']): # Get train dataset based on group and method X_train = data_dic['X_train_' + method + group] y_train = data_dic['y_train_' + method + group] @@ -184,63 +184,65 @@ if __name__ == "__main__": models = get_tuned_models(group, method_names[j]) # Scores df -> one column per cv split, one row for each model-metric scores_df = pd.DataFrame(columns=range(1,11), index=[f"{model_name}_{metric_name}" for model_name in models.keys() for metric_name in scorings.keys()]) - # Create a figure for all models in this group-method + # Create a figure with 2 subplots (roc and pr curves) for each model in this group-method fig, axes = plt.subplots(len(models), 2, figsize=(10, 8 * len(models))) if len(models) == 1: # Adjustment if there's only one model (axes indexing issue) axes = [axes] # Metric generation for each model for model_idx, (model_name, model) in enumerate(models.items()): print(f"{group}-{method_names[j]}-{model_name}") - # # Retrieve cv scores for our metrics of interest - # scores = cross_validate(model, X_train, y_train, scoring=scorings, cv=cv, return_train_score=True, n_jobs=10) - # # Save results of each fold - # for metric_name in scorings.keys(): - # scores_df.loc[model_name + f'_{metric_name}']=list(np.around(np.array(scores[f"test_{metric_name}"]),4)) - mean_fpr = np.linspace(0, 1, 100) - tprs, aucs = [], [] - mean_recall = np.linspace(0, 1, 100) - precisions, pr_aucs = [], [] - cmap = plt.get_cmap('tab10') # Colormap - # Initialize storage for scores for each fold - fold_scores = {metric_name: [] for metric_name in scorings.keys()} - # Loop through each fold in the cross-validation - for fold_idx, (train_idx, test_idx) in enumerate(cv.split(X_train, y_train)): - X_train_fold, X_test_fold = X_train[train_idx], X_train[test_idx] - y_train_fold, y_test_fold = y_train[train_idx], y_train[test_idx] - # Fit the model on the training data - model.fit(X_train_fold, y_train_fold) - # Predict on the test data - if hasattr(model, "decision_function"): - y_score = model.decision_function(X_test_fold) - else: - y_score = model.predict_proba(X_test_fold)[:, 1] # Use probability of positive class - y_pred = model.predict(X_test_fold) - # Calculate and store the scores for each metric - for metric_name, scorer in scorings.items(): - if metric_name in ['AUROC', 'AUPRC']: - score = scorer._score_func(y_test_fold, y_score) + if model_name == 'DT': + # Curve generation setup + mean_fpr = np.linspace(0, 1, 100) + tprs, aucs = [], [] + mean_recall = np.linspace(0, 1, 100) + precisions, pr_aucs = [], [] + cmap = plt.get_cmap('tab10') # Colormap + # Initialize storage for scores for each fold + fold_scores = {metric_name: [] for metric_name in scorings.keys()} + # Manually loop through each fold in the cross-validation + for fold_idx, (train_idx, test_idx) in enumerate(cv.split(X_train, y_train)): + X_train_fold, X_test_fold = X_train[train_idx], X_train[test_idx] + y_train_fold, y_test_fold = y_train[train_idx], y_train[test_idx] + # Fit the model on the training data + model.fit(X_train_fold, y_train_fold) + # --------------------- SCORINGS --------------------------- + # Predict on the test data + # Check if the model has a decision_function method + if hasattr(model, "decision_function"): + # Use decision_function to get the continuous scores for each test sample + y_score = model.decision_function(X_test_fold) else: - score = scorer._score_func(y_test_fold, y_pred) - fold_scores[metric_name].append(score) + # If decision_function is not available, use predict_proba to get probabilities + # predict_proba returns an array with probabilities for all classes + # [:, 1] extracts the probability for the positive class (class 1) + y_score = model.predict_proba(X_test_fold)[:, 1] + # Get the predicted class labels for the test data + y_pred = model.predict(X_test_fold) + # Calculate and store the scores for each metric + for metric_name, scorer in scorings.items(): + if metric_name in ['AUROC', 'AUPRC']: + score = scorer._score_func(y_test_fold, y_score) + else: + score = scorer._score_func(y_test_fold, y_pred) + fold_scores[metric_name].append(score) + # --------------------- END SCORINGS --------------------------- # --------------------- CURVES --------------------------- - # Generate ROC curve for the fold - roc_display = RocCurveDisplay.from_estimator(model, X_test_fold, y_test_fold, - name=f"ROC fold {fold_idx}", alpha=0.6, lw=2, - ax=axes[model_idx][0], color=cmap(fold_idx % 10)) - interp_tpr = np.interp(mean_fpr, roc_display.fpr, roc_display.tpr) - interp_tpr[0] = 0.0 - tprs.append(interp_tpr) - aucs.append(roc_display.roc_auc) - # Generate Precision-Recall curve for the fold - pr_display = PrecisionRecallDisplay.from_estimator(model, X_test_fold, y_test_fold, - name=f"PR fold {fold_idx}", alpha=0.6, lw=2, - ax=axes[model_idx][1], color=cmap(fold_idx % 10)) - interp_precision = np.interp(mean_recall, pr_display.recall[::-1], pr_display.precision[::-1]) - precisions.append(interp_precision) - pr_aucs.append(pr_display.average_precision) - # Store the fold scores in the dataframe - for metric_name, scores in fold_scores.items(): - scores_df.loc[f"{model_name}_{metric_name}"] = np.around(scores, 4) + # Generate ROC curve for the fold + roc_display = RocCurveDisplay.from_estimator(model, X_test_fold, y_test_fold, + name=f"ROC fold {fold_idx}", alpha=0.6, lw=2, + ax=axes[model_idx][0], color=cmap(fold_idx % 10)) + interp_tpr = np.interp(mean_fpr, roc_display.fpr, roc_display.tpr) + interp_tpr[0] = 0.0 + tprs.append(interp_tpr) + aucs.append(roc_display.roc_auc) + # Generate Precision-Recall curve for the fold + pr_display = PrecisionRecallDisplay.from_estimator(model, X_test_fold, y_test_fold, + name=f"PR fold {fold_idx}", alpha=0.6, lw=2, + ax=axes[model_idx][1], color=cmap(fold_idx % 10)) + interp_precision = np.interp(mean_recall, pr_display.recall[::-1], pr_display.precision[::-1]) + precisions.append(interp_precision) + pr_aucs.append(pr_display.average_precision) # Plot diagonal line for random guessing in ROC curve axes[model_idx][0].plot([0, 1], [0, 1], linestyle='--', lw=2, color='r', alpha=.8, label='Random guessing') # Compute mean ROC curve @@ -261,6 +263,10 @@ if __name__ == "__main__": # Set Precision-Recall plot limits and title axes[model_idx][1].set(xlim=[-0.05, 1.05], ylim=[-0.05, 1.05], title=f"Precision-Recall Curve - {model_name} ({group}-{method_names[j]})") axes[model_idx][1].legend(loc="lower right") + # --------------------- END CURVES --------------------------- + # Store the fold scores in the dataframe + for metric_name, scores in fold_scores.items(): + scores_df.loc[f"{model_name}_{metric_name}"] = np.around(scores, 4) # Store the DataFrame in the dictionary with a unique key for each sheet sheet_name = f"{group}_{method_names[j]}" scores_sheets[sheet_name] = scores_df @@ -272,4 +278,5 @@ if __name__ == "__main__": with pd.ExcelWriter('./output_cv_metrics/metrics.xlsx') as writer: for sheet_name, data in scores_sheets.items(): data.to_excel(writer, sheet_name=sheet_name) - print("Successful cv metric generation for tuned models") \ No newline at end of file + print("Successful cv metric generation for tuned models") + # -------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/model_selection/output_cv_metrics.xlsx b/model_selection/output_cv_metrics.xlsx deleted file mode 100644 index 72112a27b6ff36492eca8c7f8c5851ea62c74d66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31899 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 -- 2.24.1