разделение на обучающую и тестовую выборки с помощью train_test_split для вещественных значений?

Вопрос или проблема

Как разделить на обучающую и тестовую выборки с помощью 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. Не забывайте о важности обработки несбалансированных данных и возможности их стандартизации, чтобы улучшить результаты моделей.

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

Оцените материал
Добавить комментарий

Капча загружается...