- Вопрос или проблема
- Ответ или решение
- Разделение данных на обучающую и тестовую выборки с использованием train_test_split для значений типа float
- 1. Использование train_test_split
- 2. Обработка несбалансированных классов
- 3. Устранение ошибки в кросс-валидации
- 4. Стандартизация данных
- 5. Выбор моделей и кросс-валидация
- Вывод
Вопрос или проблема
Как разделить на обучающую и тестовую выборки с помощью train_test_split значений с плавающей запятой?
Я использовал LabelEncoder, но у меня около 300К строк, и когда я использовал cross_val, я увидел ValueError: наименьший класс в y имеет только 1 член, что слишком мало. Минимальное количество групп для любого класса не может быть меньше 2.
Какое лучшее решение?
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=seed )
from imblearn.under_sampling import RandomUnderSampler
from collections import Counter
rus = RandomUnderSampler(random_state=seed, return_indices=True) # (50:50)
from sklearn import preprocessing
lab_enc = preprocessing.LabelEncoder()
training_scores_encoded = lab_enc.fit_transform(y_train)
#print(training_scores_encoded)
X_res, y_res, idx_res = rus.fit_sample(X_train, training_scores_encoded)
from sklearn.preprocessing import StandardScaler
scalerT = StandardScaler().fit(X_train[:,[0]])
#scalerT = StandardScaler().fit(X[:,[0]])
X_train[:,[0]] = scalerT.transform(X_train[:,[0]])
X_test[:,[0]] = scalerT.transform(X_test[:,[0]])
X_res[:,[0]] = scalerT.transform(X_res[:,[0]])
scalerA = StandardScaler().fit(X_train[:,[idx_Amount]])
#scalerA = StandardScaler().fit(X[:,[idx_Amount]])
X_train[:,[idx_Amount]] = scalerA.transform(X_train[:,[idx_Amount]])
X_test[:,[idx_Amount]] = scalerA.transform(X_test[:,[idx_Amount]])
X_res[:,[idx_Amount]] = scalerA.transform(X_res[:,[idx_Amount]])
from sklearn.linear_model import LogisticRegression
models = []
models.append(('LR', LogisticRegression()))
# Параметры по умолчанию для каждой модели
models
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import StratifiedShuffleSplit
XX = X_res
yy = y_res
# StratifiedKFold используется по умолчанию для целого числа cv
#cv=10
cv = StratifiedShuffleSplit(n_splits=10, test_size=0.3, random_state=seed)
results = []
names = []
for name, model in models:
cv_results = cross_val_score(model, XX, yy, cv = cv, scoring = 'accuracy')
results.append(cv_results)
names.append(name)
msg = "%s: %.2f (+/- %.2f)" % (name, cv_results.mean(), cv_results.std())
print(msg)
fig = plt.figure()
fig.suptitle('Точность')
ax = fig.add_subplot(111)
plt.boxplot(results)
ax.set_xticklabels(names)
plt.show()
results = []
names = []
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import StratifiedShuffleSplit
XX = X_res
yy = y_res
# StratifiedKFold используется по умолчанию для целого числа cv
#cv=10
cv = StratifiedShuffleSplit(n_splits=10, test_size=0.3, random_state=seed)
for name, model in models:
cv_results = cross_val_score(model, XX, yy, cv = cv, scoring = 'recall')
results.append(cv_results)
names.append(name)
msg = "%s: %.2f (+/- %.2f)" % (name, cv_results.mean(), cv_results.std())
print(msg)
Проблема в том, что ваши данные нарушают требования StratifiedShuffleSplit, а именно, нельзя сделать разделение 70:30 и сохранить одинаковое количество различных значений y в тестовой и обучающей выборках – скорее всего, потому что у вас есть значение y, которое встречается только 1 раз?
Возможно, просто используйте ShuffleSplit?
Ответ или решение
Разделение данных на обучающую и тестовую выборки с использованием train_test_split
для значений типа float
В ходе работы с большими наборами данных (например, 300 тысяч строк) на этапе предобработки данных может возникнуть сложность разделения выборок на обучающую и тестовую, особенно если данные несбалансированы. В вашем случае, ошибка ValueError
, которую вы наблюдаете, указывает на то, что в одной из классов y содержится только один элемент. Это нарушает правила выполнения стратифицированного разбиения, так как для каждого класса должны быть представлены по крайней мере два образца. В данной статье мы внимательно рассмотрим возможные решения, включая использование ShuffleSplit
вместо StratifiedShuffleSplit
, а также альтернативные методы обработки несбалансированных данных.
1. Использование train_test_split
Функция train_test_split
из библиотеки sklearn.model_selection
позволяет удобно разделять данные на обучающую и тестовую выборки. Чтобы избежать проблем со стратифицированным разбиением, можно использовать обычное перемешивание:
from sklearn.model_selection import train_test_split
# Задание переменной для случайного состояния
seed = 42
# Простое перемешивание данных без стратификации
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=seed)
Это разбиение не будет обеспечивать равное распределение классов в выборках, но будет более гибким в случае, если у вас есть классы с малым числом образцов.
2. Обработка несбалансированных классов
Если вы хотите сохранить сбалансированность классов, рассмотрите возможность использования методов перераспределения классов. В вашем коде вы применяете RandomUnderSampler
, чтобы уменьшить количество примеров в переполненных классах:
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=seed, return_indices=True)
X_res, y_res, idx_res = rus.fit_resample(X_train, y_train)
Это может помочь в создании более сбалансированного набора данных перед применением кросс-валидации.
3. Устранение ошибки в кросс-валидации
Для получения корректных результатов при кросс-валидации, вам стоит использовать метод ShuffleSplit
, особенно если не удается создать сбалансированные выборки с использованием стратифицированного подхода:
from sklearn.model_selection import ShuffleSplit
cv = ShuffleSplit(n_splits=10, test_size=0.3, random_state=seed)
4. Стандартизация данных
Также вы правильно используете StandardScaler
для стандартизации данных, что является хорошей практикой, особенно для моделей, которые зависят от масштаба входных данных. Убедитесь, что вы применяете стандартные скалеры только на обучающей выборке, а затем применяете их к тестовой выборке:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler().fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
5. Выбор моделей и кросс-валидация
Вы логично используете кросс-валидацию для оценки модели, однако помните, что выбор подходящей метрики (например, точность или полнота) должен зависеть от вашей задачи. Для несбалансированных классов может быть более правильно использовать recall
или f1-score
.
Вывод
Создание и обработка моделей при работе с достаточно большими наборами данных требует учета множества факторов, включая баланс классов и правильное применение техник разбиения. Использование ShuffleSplit
может решить возникшие проблемы с StratifiedShuffleSplit
. Не забывайте о важности обработки несбалансированных данных и возможности их стандартизации, чтобы улучшить результаты моделей.
В целом, понимание этих нюансов позволит вам значительно повысить эффективность анализа данных и построения моделей машинного обучения.