web-dev-qa-db-fra.com

Sklearn StratifiedKFold: ValueError: Les types de cibles pris en charge sont: ('binary', 'multiclass'). A obtenu 'multilabel-indicateur' à la place

Utilisation de la division kfold stratifiée de Sklearn et lorsque je tente de scinder en utilisant plusieurs classes, je l’ai reçu par erreur (voir ci-dessous). Lorsque j'ai essayé et scindé en binaire, cela ne pose aucun problème.

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.
11
jKraut

keras.utils.to_categorical produit un vecteur de classe codé à chaud, c’est-à-dire le multilabel-indicator mentionné dans le message d’erreur. StratifiedKFold n'est pas conçu pour fonctionner avec une telle entrée; à partir de la méthode splitdocs :

split (X, y, groupes = Aucun)

[...]

y: semblable à un tableau, forme (n_samples,)

La variable cible pour les problèmes d'apprentissage supervisé. La stratification est faite sur la base des étiquettes y.

c'est-à-dire que votre y doit être un tableau 1-D de vos étiquettes de classe.

Pour l’essentiel, vous devez simplement inverser l’ordre des opérations: divisez d’abord (avec votre y_train initial), puis convertissez to_categorical ensuite.

12
desertnaut

Je suis tombé sur le même problème et ai découvert que vous pouvez vérifier le type de la cible avec cette fonction util:

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

'multilabel-indicator'

De sa docstring:

  • 'binary': y contient <= 2 valeurs discrètes et vaut 1d ou une colonne vecteur.
  • 'multiclass': y contient plus de deux valeurs discrètes, n'est pas un séquence de séquences, et est 1d ou un vecteur colonne.
  • 'multiclass-multioutput': y est un tableau 2D qui contient plus de que deux valeurs discrètes, n'est pas une séquence de séquences, et les deux les dimensions sont de taille> 1.
  • 'multilabel-indicator': y est une matrice d'indicateurs d'étiquettes, un tableau de deux dimensions avec au moins deux colonnes et au plus 2 uniques valeurs.

Avec LabelEncoder, vous pouvez transformer vos classes en un tableau de nombres 1d (étant donné que vos étiquettes cible se trouvent dans un tableau de catégories/objet 1d):

from sklearn.preprocessing import LabelEncoder

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

Appelez split() comme ceci:

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]
1
wilmeragsgh

Dans mon cas, x était une matrice 2D et y était également une matrice 2d, c’est-à-dire un cas multi-classes à sorties multiples. Je viens de passer une np.zeros(shape=(n,1)) fictive__ pour les y et les x comme d'habitude. Exemple de code complet:

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]
1
shadi