File size: 4,743 Bytes
bf5fb5f
89f0e63
3633596
89f0e63
 
3633596
89f0e63
3633596
 
43d4438
 
 
89f0e63
43d4438
 
 
 
 
89f0e63
43d4438
 
 
3633596
89f0e63
 
 
43d4438
 
bf5fb5f
 
 
 
89f0e63
 
 
 
 
bf5fb5f
 
 
 
 
 
89f0e63
bf5fb5f
 
 
89f0e63
 
 
bf5fb5f
89f0e63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bf5fb5f
89f0e63
 
 
 
 
 
 
 
 
bf5fb5f
89f0e63
65e5e42
89f0e63
 
 
65e5e42
89f0e63
 
65e5e42
 
 
 
 
 
 
89f0e63
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import cupy as cp
from typing import Dict, Protocol, Tuple
import warnings
# Utiliser cuml.metrics pour les calculs accélérés par GPU
from cuml.metrics import accuracy_score, precision_recall_curve, roc_auc_score

# Filtrer les avertissements
warnings.filterwarnings("ignore", category=Warning)


class MetricsCalculator(Protocol):
    """
    Interface pour les calculateurs de métriques pour la classification binaire.
    """
    def calculate_and_log(
        self,
        y_true: cp.ndarray,
        y_pred: cp.ndarray,
        y_proba: cp.ndarray, # Probabilités classe positive (1D) - Supposées toujours fournies
        prefix: str
    ) -> Dict[str, float]:
        """
        Calcule les métriques pour un problème binaire.
        Assume que y_proba est toujours fourni et est un tableau 1D
        contenant les probabilités de la classe positive.
        Retourne Accuracy, AUC ROC, Precision, Recall et F1 Score.
        """
        pass


class DefaultMetricsCalculator(MetricsCalculator):
    """
    Implémentation concrète de MetricsCalculator utilisant cuML pour la classification binaire.
    Calcule l'accuracy, l'AUC-ROC, la précision, le rappel et le F1 score en utilisant les fonctions cuML.
    Utilise precision_recall_curve pour calculer les métriques de précision, rappel et F1 score optimales.
    Assume que les données d'entrée sont valides et que y_proba est toujours fourni
    en tant que tableau 1D des probabilités de la classe positive.
    """

    def calculate_and_log(
        self,
        y_true: cp.ndarray,
        y_pred: cp.ndarray,
        y_proba: cp.ndarray, # Probabilités classe positive (1D) - Supposées toujours fournies
        prefix: str
    ) -> Dict[str, float]:
        """
        Calcule l'accuracy, l'AUC ROC, la précision, le rappel et le F1 score pour un problème binaire en utilisant cuML.
        Utilise precision_recall_curve pour calculer les métriques optimales.
        Assume des entrées valides et que y_proba est un tableau 1D fourni.
        """
        # 1. Calculer l'accuracy (comme dans l'exemple accuracy_score)
        acc = accuracy_score(y_true, y_pred)

        # 2. Calculer l'AUC binaire (comme dans l'exemple roc_auc_score)
        auc = roc_auc_score(y_true.astype(cp.int32), y_proba.astype(cp.float32))

        # 3. Utiliser precision_recall_curve pour obtenir les courbes
        precision, recall, thresholds = precision_recall_curve(
            y_true.astype(cp.int32), y_proba.astype(cp.float32)
        )
        
        # 4. Calculer la précision, le rappel et le F1 score optimaux
        optimal_precision, optimal_recall, optimal_f1, optimal_threshold = self._calculate_optimal_f1(
            precision, recall, thresholds
        )

        # Construire le dictionnaire des métriques scalaires disponibles
        metrics = {
            f"{prefix}_accuracy"           : acc,
            f"{prefix}_precision"          : optimal_precision,
            f"{prefix}_recall"             : optimal_recall,
            f"{prefix}_f1"                 : optimal_f1,
            f"{prefix}_optimal_threshold"  : optimal_threshold,
            f"{prefix}_auc_roc"            : auc
        }
        # Retourner les métriques scalaires calculées
        return metrics
        
    def _calculate_optimal_f1(
        self, 
        precision: cp.ndarray, 
        recall: cp.ndarray, 
        thresholds: cp.ndarray
    ) -> Tuple[float, float, float, float]:
        """
        Calcule le F1 score optimal à partir des courbes de précision et de rappel.
        
        Args:
            precision: Tableau de précisions pour différents seuils
            recall: Tableau de rappels pour différents seuils
            thresholds: Tableau de seuils correspondants
            
        Returns:
            Tuple contenant (précision optimale, rappel optimal, F1 score optimal, seuil optimal)
        """
        # Ajouter le seuil 1.0 à thresholds (qui n'est pas inclus par défaut dans precision_recall_curve)
        thresholds_with_one = cp.append(thresholds, cp.array([1.0]))
            
        # Calculer le F1 score pour chaque point de la courbe
        # F1 = 2 * (precision * recall) / (precision + recall)
        f1_scores = 2 * (precision * recall) / (precision + recall)
        
        # Trouver l'indice du F1 score maximal
        best_idx = cp.argmax(f1_scores)
        best_precision = float(precision[best_idx])
        best_recall = float(recall[best_idx])
        best_f1 = float(f1_scores[best_idx])
        
        # Obtenir le seuil optimal
        best_threshold = float(thresholds_with_one[best_idx])
            
        return best_precision, best_recall, best_f1, best_threshold