Je fais un k-fold XV sur une trame de données existante, et j'ai besoin d'obtenir le score AUC. Le problème est - parfois les données de test ne contiennent que des 0 et non des 1!
J'ai essayé d'utiliser l'exemple this , mais avec des nombres différents:
import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 0, 0, 0])
y_scores = np.array([1, 0, 0, 0])
roc_auc_score(y_true, y_scores)
Et je reçois cette exception:
ValueError: une seule classe présente dans y_true. Le score ROC AUC n'est pas défini dans ce cas.
Y a-t-il une solution de contournement qui peut le faire fonctionner dans de tels cas?
Vous pouvez utiliser try-except pour éviter l'erreur:
import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 0, 0, 0])
y_scores = np.array([1, 0, 0, 0])
try:
roc_auc_score(y_true, y_scores)
except ValueError:
pass
Maintenant, vous pouvez également définir le roc_auc_score
à zéro s'il n'y a qu'une seule classe présente. Cependant, je ne ferais pas ça. Je suppose que vos données de test sont très déséquilibrées. Je suggère d'utiliser à la place un pli en K stratifié pour que vous ayez au moins les deux classes présentes.
Oui, c'est clairement un bug! Votre code est parfaitement correct:
import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 0, 0, 0])
y_scores = np.array([1, 0, 0, 0])
roc_auc_score(y_true, y_scores)
Voici ma "solution"
from sklearn.metrics import roc_auc_score, accuracy_score
def roc_auc_score_FIXED(y_true, y_pred):
if len(np.unique(y_true)) == 1: # bug in roc_auc_score
return accuracy_score(y_true, np.rint(y_pred))
return roc_auc_score(y_true, y_pred)
Modifiez simplement le code avec 0 à 1 pour le faire fonctionner
import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 1, 0, 0])
y_scores = np.array([1, 0, 0, 0])
roc_auc_score(y_true, y_scores)
Je crois que le message d'erreur a suggéré qu'une seule classe dans y_true (tout zéro), vous devez donner 2 classes dans y_true.
Comme le note l'erreur, si une classe n'est pas présente dans la vérité terrain d'un lot,
Le score ROC AUC n'est pas défini dans ce cas.
Je suis contre le fait de lever une exception (à propos de quoi? C'est le comportement attendu) ou de renvoyer une autre mesure (par exemple, la précision). La métrique n'est pas cassée en soi.
Je n'ai pas envie de résoudre un "problème" de déséquilibre des données avec un "correctif" métrique. Il serait probablement préférable d'utiliser un autre échantillonnage, si possible, ou simplement de joindre plusieurs lots qui satisfont aux exigences de population de la classe.
Je suis confronté au même problème maintenant et j'utilise try-catch
ne résout pas mon problème. J'ai développé le code ci-dessous pour y faire face.
import pandas as pd
import numpy as np
class KFold(object):
def __init__(self, folds, random_state=None):
self.folds = folds
self.random_state = random_state
def split(self, x, y):
assert len(x) == len(y), 'x and y should have the same length'
x_, y_ = pd.DataFrame(x), pd.DataFrame(y)
y_ = y_.sample(frac=1, random_state=self.random_state)
x_ = x_.loc[y_.index]
event_index, non_event_index = list(y_[y == 1].index), list(y_[y == 0].index)
assert len(event_index) >= self.folds, 'number of folds should be less than the number of rows in x'
assert len(non_event_index) >= self.folds, 'number of folds should be less than number of rows in y'
indexes = []
#
#
#
step = int(np.ceil(len(non_event_index) / self.folds))
start, end = 0, step
while start < len(non_event_index):
train_fold = set(non_event_index[start:end])
valid_fold = set([k for k in non_event_index if k not in train_fold])
indexes.append([train_fold, valid_fold])
start, end = end, min(step + end, len(non_event_index))
#
#
#
step = int(np.ceil(len(event_index) / self.folds))
start, end, i = 0, step, 0
while start < len(event_index):
train_fold = set(event_index[start:end])
valid_fold = set([k for k in event_index if k not in train_fold])
indexes[i][0] = list(indexes[i][0].union(train_fold))
indexes[i][1] = list(indexes[i][1].union(valid_fold))
indexes[i] = Tuple(indexes[i])
start, end, i = end, min(step + end, len(event_index)), i + 1
return indexes
Je viens d'écrire ce code et je ne l'ai pas testé de manière exhaustive. Il a été testé uniquement pour les catégories binaires. J'espère que ce sera encore utile.