Одной из ключевых задач при создании модели машинного обучения является разделение данных на обучающую и тестовую выборки. Это необходимый этап для того, чтобы модель могла обучаться на одной части данных и проверяться на другой, не использованной при обучении. В Python для этой цели существует несколько методов, среди которых наиболее популярным является использование библиотеки scikit-learn, которая предоставляет удобные функции для разделения данных.
Один из самых распространённых способов разделить данные – это функция train_test_split из модуля sklearn.model_selection. Эта функция автоматически разделяет массив данных на две части: обучающую и тестовую. Важно помнить, что разделение данных должно быть случайным, чтобы избежать смещения результатов, однако в некоторых случаях можно использовать параметр stratify, который позволяет учитывать распределение классов в данных, что особенно важно при работе с несбалансированными выборками.
Типичная пропорция разделения – 70-80% данных для обучения и 20-30% для тестирования. Однако в зависимости от объема данных и конкретной задачи этот баланс может варьироваться. При малом объеме данных рекомендуется использовать кросс-валидацию, чтобы максимально эффективно использовать все доступные данные для тренировки модели и её оценки.
Необходимо также учитывать важность случайности при разделении. Даже при одинаковых данных, каждый запуск функции train_test_split может давать разные результаты. Для обеспечения воспроизводимости экспериментов, можно задать параметр random_state, который фиксирует начальное состояние генератора случайных чисел, гарантируя одинаковое разделение при повторных запусках.
Как использовать train_test_split из библиотеки scikit-learn для деления данных
Основной синтаксис функции:
train_test_split(*arrays, test_size=None, train_size=None, random_state=None, shuffle=True, stratify=None)
*arrays
– массивы или DataFrame, которые нужно разделить (например, признаки и целевая переменная).test_size
– доля данных, которая пойдет в тестовую выборку. Обычно указывается значение от 0 до 1. Например, 0.2 – это 20% данных для теста.train_size
– доля данных для обучающей выборки. Если указана иtest_size
не задана, это параметр определяет размер обучающей выборки.random_state
– параметр для фиксирования случайных чисел, что делает разбиение повторяемым при одинаковых параметрах.shuffle
– флаг, который контролирует, нужно ли перемешивать данные перед разбиением. По умолчаниюTrue
.stratify
– позволяет разделить данные с учётом распределения классов целевой переменной, что особенно важно для классификации, чтобы сохранить пропорции классов в обучающей и тестовой выборках.
Пример использования:
from sklearn.model_selection import train_test_split
X = ... # Признаки
y = ... # Целевая переменная
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)
В этом примере данные разделяются на 70% для обучения и 30% для тестирования. Параметр stratify=y
обеспечивает, что распределение классов в обучающей и тестовой выборках будет одинаковым. Указание random_state=42
позволяет повторить разбиение с теми же самыми результатами в будущем.
Дополнительные рекомендации:
- Если в данных имеются выбросы или сильные дисбалансы, рассмотрите возможность применения стратифицированного разбиения для сохранения пропорций классов в обеих выборках.
- При работе с большими данными можно использовать
shuffle=False
, чтобы ускорить процесс разделения, если данные уже случайным образом перемешаны. - Перед делением важно убедиться, что данные подготовлены (например, нормализованы или стандартизированы), чтобы разделение не влияло на результаты.
Функция train_test_split
– это простой и быстрый способ организовать корректное разбиение данных, что значительно упрощает подготовку данных для дальнейшего обучения моделей машинного обучения.
Какие параметры train_test_split влияют на размер выборок
test_size
– это параметр, который определяет долю данных, выделяемых для тестирования. Значение может быть числовым, например, 0.2, что означает 20% от общего объема данных, или целым числом, которое указывает количество объектов в тестовой выборке. Важно помнить, что если задан только test_size
, то train_size
рассчитывается автоматически как разница между размером всей выборки и размером тестовой.
train_size
аналогичен test_size
, но отвечает за размер обучающей выборки. Установив это значение, можно точно контролировать долю данных, которая пойдет на обучение. Если задан и train_size
, и test_size
, то они должны совместно покрывать все данные, в противном случае возникнет ошибка.
Если оба параметра не указаны, то по умолчанию используется стандартная настройка, при которой тестовая выборка составляет 25% данных, а обучающая – 75%. Система сама определяет пропорции, если оба значения отсутствуют.
random_state
не влияет напрямую на размер выборок, но оказывает влияние на воспроизводимость разбиения данных. Установка фиксированного значения для random_state
гарантирует, что разбиение будет одинаковым при каждом запуске функции, что особенно важно при проведении экспериментов и сравнении моделей.
Влияние параметров test_size
и train_size
напрямую связано с размером исходной выборки. Например, при большом объеме данных небольшие изменения в значениях этих параметров не оказывают сильного влияния на конечный результат, но для малых выборок изменение одного из параметров может существенно повлиять на обучение модели.
Как сохранить разделённые данные в новые файлы
Для сохранения разделённых данных в новые файлы в Python можно использовать библиотеки pandas и scikit-learn. После того как данные будут разделены на обучающую и тестовую выборки, необходимо сохранить их в отдельные файлы, чтобы впоследствии использовать их для обучения модели и оценки её качества. Рассмотрим, как это сделать.
Для начала загрузим необходимые библиотеки и разделим данные. В примере ниже используется pandas для работы с данными и scikit-learn для их разделения:
import pandas as pd
from sklearn.model_selection import train_test_split
# Загрузка данных
data = pd.read_csv('data.csv')
# Разделение на обучающую и тестовую выборки
train_data, test_data = train_test_split(data, test_size=0.2, random_state=42)
После того как данные разделены, можно сохранить их в новые файлы. Для этого используем функцию to_csv()
из библиотеки pandas. Этот метод позволяет сохранять данные в формате CSV.
Пример сохранения обучающей и тестовой выборок в файлы:
train_data.to_csv('train_data.csv', index=False)
test_data.to_csv('test_data.csv', index=False)
Здесь index=False
означает, что индексы строк не будут сохраняться в файл, что часто бывает ненужно при обработке данных. Если требуется, можно настроить разделители или кодировку с помощью дополнительных параметров метода to_csv()
.
Если ваши данные представлены в другом формате, например, в виде Excel-файла, можно использовать метод to_excel()
для сохранения выборок в Excel:
train_data.to_excel('train_data.xlsx', index=False)
test_data.to_excel('test_data.xlsx', index=False)
Для работы с большими объёмами данных или сохранения их в других форматах (например, JSON) также доступны аналогичные методы, такие как to_json()
или to_pickle()
.
Таким образом, после разделения данных на обучающую и тестовую выборки, можно легко сохранить их в нужном формате для дальнейшего использования в проектах машинного обучения или аналитике.
Как разделить данные на обучающую и тестовую выборки с учётом классов (stratify)
При разделении данных на обучающую и тестовую выборки важно сохранить пропорциональное распределение классов, особенно в случае с несбалансированными данными. Использование параметра stratify
позволяет гарантировать, что распределение классов в обеих выборках будет таким же, как и в исходных данных.
Для этого в библиотеке scikit-learn
есть удобный метод train_test_split
, который принимает параметр stratify
. При указании этого параметра данные разделяются так, что соотношение классов в обучающей и тестовой выборке сохраняется. Например, если в исходных данных 70% положительных и 30% отрицательных примеров, то аналогичное соотношение будет соблюдаться в каждой выборке.
Пример использования:
from sklearn.model_selection import train_test_split
X = # ваши данные
y = # метки классов
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
В этом примере train_test_split
разделяет данные так, чтобы 20% данных оказалось в тестовой выборке, при этом пропорции классов в y_train
и y_test
будут одинаковыми, как в исходной выборке.
Стратифицированное разделение особенно полезно при работе с классами, которые встречаются редко (например, в задачах классификации с малым количеством примеров одного из классов), так как без него может возникнуть ситуация, когда в одной из выборок не будет представленных определённых классов, что сделает модель менее устойчивой и точной.
В случае с многоклассовыми данными параметр stratify
также сохраняет пропорции классов, что позволяет избежать искажения распределения даже в сложных задачах.
Как разделить данные с временными метками на обучающую и тестовую выборки
При работе с временными рядами нельзя перемешивать данные перед разделением, так как это нарушит хронологический порядок. Модель должна обучаться на прошлых значениях и проверяться на будущих.
Рекомендуется использовать деление по дате. Например, если данные охватывают период с 2015 по 2024 год, можно взять всё до конца 2022 года как обучающую выборку, а данные с 2023 года – как тестовую. Такой подход гарантирует, что модель будет проверяться на ещё не встречавшихся значениях.
В pandas это делается через фильтрацию по дате:
df['timestamp'] = pd.to_datetime(df['timestamp'])
train = df[df['timestamp'] < '2023-01-01']
test = df[df['timestamp'] >= '2023-01-01']
Если данных немного, можно использовать скользящее окно: например, обучаться на 3 предыдущих года, тестироваться на следующем. Затем окно сдвигается вперёд. Это позволяет проверить устойчивость модели во времени.
Нельзя использовать функцию train_test_split, так как она не учитывает порядок. В задачах с временными метками важно сохранить последовательность событий.
Как правильно разделить данные, если их слишком мало
При ограниченном объёме данных стандартное разбиение на обучающую и тестовую выборки (например, 80/20) может привести к потере информации. В таких случаях предпочтительнее использовать перекрёстную проверку.
Наиболее надёжный метод – K-fold cross-validation. Данные делятся на K равных частей. Каждая из них поочерёдно используется как тестовая, а оставшиеся – как обучающие. Это позволяет использовать все доступные данные для обучения и оценки.
Если данных крайне мало (менее 50 наблюдений), лучше использовать Leave-One-Out Cross-Validation (LOOCV). Каждый объект поочерёдно становится тестовым, а оставшиеся – обучающими. Это даёт максимально возможное использование данных, но требует больше времени на вычисления.
Пример разбиения с использованием K-fold:
from sklearn.model_selection import KFold
import numpy as np
X = np.array([[1], [2], [3], [4], [5]])
y = np.array([1, 2, 3, 4, 5])
kf = KFold(n_splits=5)
for train_index, test_index in kf.split(X):
print("Обучающая:", train_index, "Тестовая:", test_index)
Если модель выбирается из нескольких, необходимо включать перекрёстную проверку и на этапе подбора параметров, чтобы избежать переобучения. В таких случаях используйте Nested Cross-Validation.
При использовании нейронных сетей, где перекрёстная проверка затратна, можно уменьшить долю валидации (например, 90/10) и применять регуляризацию или раннюю остановку для контроля переобучения.
В малых выборках важно зафиксировать генератор случайных чисел для воспроизводимости результатов:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
Избегайте случайного разбиения без стратификации при несбалансированных классах. Для этого используйте параметр stratify
:
train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
Как использовать кросс-валидацию для проверки моделей на разных выборках
Кросс-валидация делит выборку на несколько непересекающихся подмножеств и поочерёдно использует каждое из них в роли тестовой. Наиболее распространённый вариант – KFold. Например, KFold(n_splits=5)
делит данные на 5 частей: модель обучается на четырёх и проверяется на оставшейся, процедура повторяется 5 раз.
Для применения кросс-валидации используйте cross_val_score
из sklearn.model_selection
. Пример:
from sklearn.model_selection import cross_val_score, KFold
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=kf)
Параметр shuffle=True
обязателен, если порядок объектов в выборке не случаен. Без перемешивания возможна утечка информации или смещение оценок. random_state
фиксирует результат.
Для несбалансированных классов используйте StratifiedKFold, который сохраняет пропорции классов в каждом подмножестве:
from sklearn.model_selection import StratifiedKFold
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
Значения cross_val_score
– это метрики качества модели на каждой итерации. Для средней оценки используйте scores.mean()
, для оценки разброса – scores.std()
. Это даст представление о стабильности модели.
Если требуется использовать собственные метрики, передайте параметр scoring
, например scoring='f1'
или scoring='neg_log_loss'
. Список поддерживаемых метрик доступен в sklearn.metrics.get_scorer_names()
.
Кросс-валидация особенно полезна при малом объёме данных, когда выделение отдельной тестовой выборки приводит к потере значительной части обучающих данных.