Как использовать стратификацию для одного столбца - PullRequest
0 голосов
/ 04 апреля 2020

Я очень новичок в этих данных персонала. Поэтому я не уверен, что мне следует написать в качестве вопроса. Я пытаюсь express решить мою проблему как можно проще. Я показываю часть своих кодов.

print(data)

Вывод:

array([[0, 0, 0, ..., 255, 255, 255],
       [255, 255, 255, ..., 0, 0, 0],
       [255, 255, 255, ..., 255, 255, 255],
       ...,
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255]], dtype=object)

print(result)

Вывод:

['Arrowhead' 'Arrowhead' 'Arrowhead' ... 'Vessel' 'Vessel' 'Vessel']

Метка преобразования на номер:

LE = LabelEncoder()
target = LE.fit_transform(result)

print(target) 

Вывод:

[ 0  0  0 ... 38 38 38]

Расщепление:

X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=42, stratify=target)

Я получил ошибку:

ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of groups for any class cannot be less than 2.

Исправить ошибка, я должен был удалить stratify, что на данный момент может быть хорошо:

X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=42)

Чтобы построить CNN, я должен был сделать это:

lb = preprocessing.LabelBinarizer()

y_train_categorical = lb.fit_transform(y_train)
y_test_categorical = lb.fit_transform(y_test)

print(y_train_categorical.shape)
print(y_test_categorical.shape)

Вывод:

(1945, 38)
(487, 34)

Вот проблема. Мне нужно такое же значение для оси Y (y_train_categorical.shape[1] & y_test_categorical.shape[1]). Потому что я применил:

model = Sequential()

model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(100,100,1)))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(38, activation='softmax'))

, который отлично работает для model.fit ():

model.fit(X_train, y_train_categorical, 
          batch_size=32, epochs=5, verbose=1)

, но во время оценки на тесте

loss, accuracy = model.evaluate(X_test, y_test_categorical, verbose=0)
print('Loss: ', loss,'\nAcc: ', accuracy)

Я получаю эту ошибку:

ValueError: Error when checking target: expected dense_2 to have shape (38,) but got array with shape (34,)

Как я могу сделать y_train_categorical.shape[1] & y_test_categorical.shape[1] одинаковыми или есть какое-то простое решение для решения моей последней ошибки (во время оценки модели на тест)?

Ответы [ 2 ]

1 голос
/ 04 апреля 2020

В общем, независимо от ошибки и с методологической точки зрения, это:

y_train_categorical = lb.fit_transform(y_train)
y_test_categorical = lb.fit_transform(y_test)

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

y_train_categorical = lb.fit_transform(y_train)
y_test_categorical = lb.transform(y_test) # transform only

Это может также исправить вашу ошибку, , если все метки вашего тестового набора присутствуют в вашем наборе поездов - что должно быть для правильно сформированной прогностической проблемы ОД (в противном случае сама проблема является плохо определенной).

Если lb.fit_transform(y_test) выдает ошибку, говорящую о том, что встречаются метки, ранее не присутствовавшие (и не закодированные), это означает, что новые, невидимые метки в вашем тестовом наборе, и это реальная проблема, которую вы должны исправить здесь, а не какая-то ошибка кодирования.

0 голосов
/ 04 апреля 2020

Решение для ошибки:

ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of groups for any class cannot be less than 2.

Ошибка указывает, что в вашей переменной target есть класс, который встречается только один раз. Чтобы объяснить это, давайте рассмотрим следующий пример:

random_list = ['a','a','a','b','b','c','d','d','e','e','e']
LE = LabelEncoder()
target = LE.fit_transform(random_list)
print(target)

дает

array([0, 0, 0, 1, 1, 2, 3, 3, 4, 4, 4])

Теперь, если я попытаюсь сделать train_test_split, это выдаст ошибку.

train_test_split(target, test_size=0.2, stratify=target)
#ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of groups for any class cannot be less than 2.

Это потому, что у меня есть только одно вхождение 'c', которое создает двусмысленность, включать ли это в поезд или тестировать, когда stratify=True. Поэтому, чтобы это работало, нам нужно иметь более 1 вхождения для каждого класса.

Дополнительная ошибка с приведенным выше примером

Даже если я удаляю 'c' из приведенного выше список, вышеуказанное решение не работает. Мы сталкиваемся с другой ошибкой.

random_list = ['a','a','a','b','b','d','d','e','e','e']
E = LabelEncoder()
target = LE.fit_transform(random_list) #produces array([0, 0, 0, 1, 1, 3, 3, 4, 4, 4])
train_test_split(target, test_size=0.2, stratify=target)
#ValueError: The test_size = 2 should be greater or equal to the number of classes = 4

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

...