roc_auc_score - в y_true присутствует только один класс

Я делаю XV-кратный XV на существующем фрейме данных, и мне нужно получить оценку AUC. Проблема в том, что иногда тестовые данные содержат только 0, а не 1!

Я попытался использовать этот пример, но с разными номерами:

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)

И я получаю это исключение:

ValueError: В y_true присутствует только один класс. Оценка ROC AUC в этом случае не определяется.

Есть ли обходной путь, который может заставить его работать в таких случаях?

2 ответа

Решение

Вы можете использовать try-кроме, чтобы предотвратить ошибку:

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

Теперь вы также можете установить roc_auc_score быть нулевым, если присутствует только один класс. Однако я бы не стал этого делать. Я полагаю, ваши тестовые данные сильно разбалансированы. Я бы предложил вместо этого использовать стратифицированную K-складку, чтобы, по крайней мере, присутствовали оба класса.

Как отмечается в сообщении об ошибке, если класс не присутствует в основной части пакета,

В этом случае показатель ROC AUC не определяется.

Я против либо создания исключения (о чем? Это ожидаемое поведение), либо возврата другой метрики (например, точности). Сама по себе метрика не нарушается.

Мне не хочется решать "проблему" дисбаланса данных с помощью "исправления" метрики. Вероятно, было бы лучше использовать другую выборку, если это возможно, или просто объединить несколько партий, которые удовлетворяют требованию популяции класса.

Вы можете увеличить размер пакета, например, с 32 до 64, вы можете использовать StratifiedKFold или StratifiedShuffleSplit. Если ошибка не исчезла, попробуйте перетасовать данные, например, в DataLoader.

Да, это явно ошибка! Ваш код совершенно корректен:

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)

Вот мое "исправление"

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)

Я сталкиваюсь с той же проблемой сейчас и использую try-catch не решает мою проблему. Я разработал код ниже, чтобы справиться с этим.

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 

Я просто написал этот код, и я не проверял его полностью. Это было проверено только для двоичных категорий. Надеюсь, это будет полезно еще.

Просто измените код с 0 на 1, чтобы он работал

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)

Я считаю, что сообщение об ошибке предполагает, что только один класс в y_true (все нулевые), вам нужно указать 2 класса в y_true.

Другие вопросы по тегам