web-dev-qa-db-ja.com

roc_auc_score-y_trueに存在するクラスは1つだけ

既存のデータフレームでk倍のXVを実行しています。AUCスコアを取得する必要があります。問題は、テストデータに0のみが含まれ、1が含まれない場合があることです。

this の例を使用してみましたが、数値は異なります。

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に存在するクラスは1つだけです。その場合、ROC AUCスコアは定義されません。

このような場合に機能させるための回避策はありますか?

10
bloop

エラーを防ぐためにtry-exceptを使用できます。

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は、クラスが1つしかない場合はゼロになります。しかし、私はこれをしません。あなたのテストデータは非常にアンバランスだと思います。少なくとも両方のクラスが存在するように、代わりに層別K分割を使用することをお勧めします。

13
Dat Tran

はい、明らかにバグです。あなたのコードは完全に正しいです:

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)
4

コードを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のクラスが1つだけ(すべてゼロ)であることを示唆していると思います。y_trueに2つのクラスを指定する必要があります。

0
Shark Deng

エラーが示すように、クラスがバッチのグラウンドトゥルースに存在しない場合、

その場合、ROC AUCスコアは定義されません。

例外をスローするか(これは何ですか?これは予想される動作です)、または別のメトリック(精度など)を返すことに反対しています。メトリック自体は壊れていません。

指標「修正」でデータの不均衡「問題」を解決したくありません。可能であれば、別のサンプリングを使用するか、クラスの母集団の要件を満たす複数のバッチを結合することをお勧めします。

0
Diego Ferri

私は今、同じ問題に直面しており、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 

私はそのコードを書いたばかりで、徹底的にテストしていません。バイナリカテゴリに対してのみテストされました。まだお役に立てば幸いです。