Sklearn StratifiedKFold: ValueError: Поддерживаемые целевые типы: ('binary', 'multiclass'). Вместо этого отобразился "многозначный индикатор"

Работа с Sklearn стратифицированным разделением kfold, и когда я пытаюсь разделить с помощью мультикласса, я получил ошибку (см. Ниже). Когда я попытался и разделил с помощью двоичного кода, это не проблема.

num_classes = len(np.unique(y_train))
y_train_categorical = keras.utils.to_categorical(y_train, num_classes)
kf=StratifiedKFold(n_splits=5, shuffle=True, random_state=999)

# splitting data into different folds
for i, (train_index, val_index) in enumerate(kf.split(x_train, y_train_categorical)):
    x_train_kf, x_val_kf = x_train[train_index], x_train[val_index]
    y_train_kf, y_val_kf = y_train[train_index], y_train[val_index]

ValueError: Supported target types are: ('binary', 'multiclass'). Got 'multilabel-indicator' instead.

Ответ 1

keras.utils.to_categorical создает один горячий кодированный вектор класса, то есть multilabel-indicator упомянутый в сообщении об ошибке. StratifiedKFold не предназначен для работы с такими входами; из split метода docs:

split (X, y, groups = None)

[...]

y: array-like, shape (n_samples,)

Целевая переменная для контролируемых проблем обучения. Стратификация выполняется на основе ярлыков y.

т.е. ваш y должен быть 1-D массивом ваших ярлыков класса.

По сути, вам нужно просто инвертировать порядок операций: сначала y_train (используя ваш y_train), а затем конвертировать в to_categorical.

Ответ 2

Я столкнулся с той же проблемой и выяснил, что вы можете проверить тип цели с помощью этой функции util:

from sklearn.utils.multiclass import type_of_target
type_of_target(y)

'multilabel-indicator'

Из его документа:

  • 'binary': y содержит <= 2 дискретных значения и 1d или вектор столбца.
  • "multiclass": y содержит более двух дискретных значений, не является последовательностью последовательностей и является 1d или вектором столбца.
  • "multiclass-multioutput": y - это 2d-массив, который содержит более двух дискретных значений, не является последовательностью последовательностей, и оба измерения имеют размер> 1.
  • "multilabel-indicator": y - индикаторная матрица ярлыков, массив из двух измерений с по меньшей мере двумя столбцами и не более 2 уникальных значений.

С LabelEncoder вы можете преобразовать свои классы в 1d массив чисел (если ваши целевые метки находятся в 1d массиве категориальных/объектов):

from sklearn.preprocessing import LabelEncoder

label_encoder = LabelEncoder()
y = label_encoder.fit_transform(target_labels)

Ответ 3

В моем случае x была двумерной матрицей, а y также была 2d-матрицей, то есть действительно многопроцессорным многовыходным случаем. Я просто передал фиктивный np.zeros(shape=(n,1)) для y и x как обычно. Полный пример кода:

import numpy as np
from sklearn.model_selection import RepeatedStratifiedKFold
X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [3, 7], [9, 4]])
# y = np.array([0, 0, 1, 1, 0, 1]) # <<< works
y = X # does not work if passed into '.split'
rskf = RepeatedStratifiedKFold(n_splits=3, n_repeats=3, random_state=36851234)
for train_index, test_index in rskf.split(X, np.zeros(shape=(X.shape[0], 1))):
    print("TRAIN:", train_index, "TEST:", test_index)
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]

Ответ 4

Позвоните в split() следующим образом:

for i, (train_index, val_index) in enumerate(kf.split(x_train, y_train_categorical.argmax(1))):
    x_train_kf, x_val_kf = x_train[train_index], x_train[val_index]
    y_train_kf, y_val_kf = y_train[train_index], y_train[val_index]