#python #scikit-learn #train-test-split
#python #scikit-learn #поезд-тест-сплит
Вопрос:
Я работаю с крупномасштабными, несбалансированными наборами данных, где мне нужно выбрать стратифицированный обучающий набор. Однако, даже если набор данных сильно несбалансирован, мне все равно нужно убедиться, что по крайней мере каждый класс label включен хотя бы один раз в обучающий набор. sklearns train_test_split или StratifiedShuffleSplit не будут «гарантировать» это включение.
Вот пример:
import numpy as np
from sklearn.model_selection import train_test_split
X = np.arange(100).reshape((50, 2))
y = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,4,4]
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=4, random_state=42, stratify=y)
print(X_train, y_train)
Результат
[[80 81]
[48 49]
[18 19]
[30 31]] [2, 2, 1, 1]
Таким образом, классы меток 3 и 4 не включены в это разделение обучения. Учитывая абсолютный train_size= 4, эти два класса недостаточно велики для включения. Для строго стратифицированного разделения это правильно.
Однако для небольших классов мне нужно хотя бы убедиться, что алгоритм «видел класс label». Поэтому мне нужно какое-то смягчение принципа стратификации и какое-то пропорциональное включение меньших классов.
Для достижения этой цели я написал довольно много кода, который сначала удаляет меньшие классы, а затем обрабатывает их отдельно с пропорциональным разделением. Однако при удалении это также повлияет на train_test_split из-за изменений в количестве классов / общем размере.
Существует ли какая-либо простая функция / алгоритм для достижения такого поведения?
Ответ №1:
Вы проверили sklearn.model_selection.StratifiedKFold
? Попробуйте установить n_folds
значение меньше или равно числу членов в наименее заполненном классе. Если у вас есть, то я могу только рекомендовать использовать методы неполной / избыточной выборки из imbalanced-learn
.
Комментарии:
1. Большое вам спасибо за предложения. К сожалению, StratifiedKFold в этом случае с n_fold=2 будет разделением 50: 50, но не решает проблему. Я посмотрел на unbalanced-learn и обнаружил, что RandomUnderSampler с собственной реализацией sampling_strategy с использованием экспоненциального уменьшения решит эту проблему. Однако эта собственная реализация — это именно то, что я имею сегодня, используя экспоненциальное уменьшение по классам (для этого я использовал sklearns resample). Так что здесь нет реального упрощения…