ValueError: y_true contains only one label (0). Please provide the true labels explicitly through the labels argument. というエラー
背景
GridSearchCV をすると、
ValueError: y_true contains only one label (0). Please provide the true labels explicitly through the labels argument.
というようなエラーに遭遇することがある。
これは「評価用のデータに1つの正解ラベルしか含まれていないから、複数の正解ラベルを labels
引数に入れてね」というメッセージなのだが、どこに入れるか分からない。
labels
は score 関数のラベルに入れる
結論は表題の通りなのだが、scoring
のパラメータに入れる関数のパラメータとなる。scoring
パラメータは、string, list, dict, None の形式に対応しているが、
string や list は、score関数の文字列で、引数を指定できない。よってdict形式による関数の指定ということなる。
dict 関数の指定は、文字列と関数の二種類があるが、この例のprecision
のようにstringで指定したら引数を指定できないので、
make_scorer(accuracy_score)
のように指定する。この make_scorer
は、
sklearn.metrics.make_scorer — scikit-learn 0.19.1 documentation
のとおりだが、第一引数に、メトリックス関数を指定できるが、その他にそのメトリックス関数の引数(**kwargs
と書かれている)を指定できる。
例
neg_log_loss に labels=[0, 1]
に引数で与える場合。accuracy
は一致をみるので、他のクラスの情報をしらなくても問題ないが、neg_log_loss
は他に何クラスあるのか知っていないと計算できない模様。
from sklearn.model_selection import GridSearchCV from sklearn.linear_model import LogisticRegression from sklearn.model_selection import KFold from sklearn.metrics import accuracy_score, log_loss, make_scorer ... clf = GridSearchCV( LogisticRegression(penalty='l1') {'C': [0.01, 0.1, 1, 10, 100]}, cv=KFold(n_splits=20), scoring={'neg_log_loss': make_scorer(log_loss, labels=[0, 1], greater_is_better=False), 'accuracy': 'accuracy'}, n_jobs=-1, refit='neg_log_loss' ) ...
greater_is_better=False
は、log_loss
から、neg_log_loss
に変換するときに必要。
まとめ
make_scorer
関数を使って、labels
引数を与えたものを scoring
引数のdict型で与える。
ちなみに、cross validation に、KFold
を使わなかったり、cv数(n_splits
)を小さくすれば、このエラーを回避することもできる場合もある(検証事例が単独のクラスになりくくなる)が、それは誤った解決法である。