Невозможно использовать Straified-K-Fold для классификатора с несколькими метками - PullRequest
0 голосов
/ 26 февраля 2019

Следующий код используется для проверки KFold, но я обучаю модель, поскольку она выдает ошибку

ValueError: Error when checking target: expected dense_14 to have shape (7,) but got array with shape (1,)

Моя целевая переменная имеет 7 классов.Я использую LabelEncoder для кодирования классов в числа.

Увидев эту ошибку, я изменяю на MultiLabelBinarizer для кодирования классов.Я получаю следующую ошибку

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

Ниже приведен код для проверки KFold

skf = StratifiedKFold(n_splits=10, shuffle=True)
scores = np.zeros(10)
idx = 0
for index, (train_indices, val_indices) in enumerate(skf.split(X, y)):
    print("Training on fold " + str(index+1) + "/10...")
    # Generate batches from indices
    xtrain, xval = X[train_indices], X[val_indices]
    ytrain, yval = y[train_indices], y[val_indices]
    model = None
    model = load_model() //defined above

    scores[idx] = train_model(model, xtrain, ytrain, xval, yval)
    idx+=1
print(scores)
print(scores.mean())

Я не знаю, что делать.Я хочу использовать Straified K Fold на моей модели.Пожалуйста, помогите мне.

1 Ответ

0 голосов
/ 27 февраля 2019

MultiLabelBinarizer возвращает вектор, который соответствует длине вашего числа классов.

Если вы посмотрите, как StratifiedKFold разбивает ваш набор данных, вы увидите, что он толькопринимает одномерную целевую переменную, тогда как вы пытаетесь передать целевую переменную с измерениями [n_samples, n_classes]

Стратегическое разделение в основном сохраняет распределение вашего класса.И если вы подумаете об этом, это не имеет большого смысла, если у вас есть проблема классификации с несколькими метками.

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

ОБНОВЛЕНИЕ:

Логика примерно такая:

Предполагая, что у вас есть n классов, а ваша целевая переменная является комбинацией этих n классов.У вас будет (2^n) - 1 комбинаций (не включая все 0).Теперь вы можете создать новую целевую переменную, рассматривая каждую комбинацию как новую метку.

Например, если n=3, у вас будет 7 уникальных комбинаций:

 1. [1, 0, 0]
 2. [0, 1, 0]
 3. [0, 0, 1]
 4. [1, 1, 0]
 5. [1, 0, 1]
 6. [0, 1, 1]
 7. [1, 1, 1]

Отобразить всеваши ярлыки для этой новой целевой переменной.Теперь вы можете рассматривать свою проблему как простую классификацию multi-class вместо классификации multi-label .

Теперь вы можете напрямую использовать StartefiedKFold, используя y_new как ваша цель.После того, как разделение выполнено, вы можете отобразить ваши метки обратно.

Пример кода:

import numpy as np

np.random.seed(1)
y = np.random.randint(0, 2, (10, 7))
y = y[np.where(y.sum(axis=1) != 0)[0]]

ВЫХОД:

array([[1, 1, 0, 0, 1, 1, 1],
       [1, 1, 0, 0, 1, 0, 1],
       [1, 0, 0, 1, 0, 0, 0],
       [1, 0, 0, 1, 0, 0, 0],
       [1, 0, 0, 0, 1, 1, 1],
       [1, 1, 0, 0, 0, 1, 1],
       [1, 1, 1, 1, 0, 1, 1],
       [0, 0, 1, 0, 0, 1, 1],
       [1, 0, 1, 0, 0, 1, 1],
       [0, 1, 1, 1, 1, 0, 0]])

Метка кодирует векторы вашего класса:

from sklearn.preprocessing import LabelEncoder

def get_new_labels(y):
    y_new = LabelEncoder().fit_transform([''.join(str(l)) for l in y])
    return y_new

y_new = get_new_labels(y)

ВЫХОД:

array([7, 6, 3, 3, 2, 5, 8, 0, 4, 1])
...