Зачем разделять данные?
Основная проблема: переобучение (overfitting)
Представьте, что вы готовитесь к экзамену и заучиваете наизусть все задачи из учебника. На экзамене попадаются те же самые задачи — вы получаете 100%. Но если попадутся новые задачи — вы не справитесь, потому что не понимаете принципы, а просто запомнили ответы.
То же самое происходит с моделями машинного обучения!
Проблема без разделения:
# ❌ НЕПРАВИЛЬНО: обучаем и тестируем на одних данных
model.fit(X, y)
predictions = model.predict(X) # Те же самые данные!
score = model.score(X, y) # R² = 1.0 (идеально!)
# Но на новых данных модель работает плохо!
Почему плохо?
- Модель "запомнила" обучающие данные, включая шум и случайные выбросы
- Метрики качества завышены и не отражают реальную производительность
- На новых данных модель работает гораздо хуже
Решение: разделение данных
# ✅ ПРАВИЛЬНО: разделяем данные
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)
# Обучаем только на train
model.fit(X_train, y_train)
# Тестируем на данных, которые модель НЕ ВИДЕЛА
predictions = model.predict(X_test)
score = model.score(X_test, y_test) # Честная оценка!
Концепция разделения
Визуальное представление:
Полный датасет (100%)
├── Train (80%) ────────────────────► Обучение модели
└── Test (20%) ────────────────────► Проверка качества
Назначение каждой выборки:
Выборка |
Назначение |
Использование |
Train |
Обучение модели |
model.fit(X_train, y_train) |
Test |
Оценка качества |
model.predict(X_test) |
Золотое правило: Модель никогда не должна видеть тестовые данные во время обучения!
Функция train_test_split в sklearn
Базовый синтаксис:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y)
Что возвращает функция?
Функция возвращает 4 объекта в следующем порядке:
- X_train — признаки для обучения
- X_test — признаки для тестирования
- y_train — целевая переменная для обучения
- y_test — целевая переменная для тестирования
# Визуализация разделения
print(f"X_train shape: {X_train.shape}") # (400, 5) — 400 объектов, 5 признаков
print(f"X_test shape: {X_test.shape}") # (100, 5) — 100 объектов, 5 признаков
print(f"y_train shape: {y_train.shape}") # (400,) — 400 значений
print(f"y_test shape: {y_test.shape}") # (100,) — 100 значений
Параметры train_test_split
1. test_size — размер тестовой выборки
Типы значений:
# Вариант 1: Доля от 0.0 до 1.0 (наиболее популярно)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# 20% данных в test, 80% в train
# Вариант 2: Абсолютное количество объектов
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=100)
# Ровно 100 объектов в test
# Вариант 3: По умолчанию (если не указан)
X_train, X_test, y_train, y_test = train_test_split(X, y)
# test_size=0.25 (25% по умолчанию)
Типичные значения:
test_size |
Описание |
Когда использовать |
0.2 (20%) |
Стандартный вариант |
Для большинства задач |
0.3 (30%) |
Больше данных для теста |
Когда данных много (>10000) |
0.1 (10%) |
Меньше данных для теста |
Когда данных мало (<500) |
2. train_size — размер обучающей выборки
# Можно указать train_size вместо test_size
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8)
# 80% в train, 20% в test (то же, что test_size=0.2)
# Или оба параметра (должны в сумме давать 1.0 или общее число)
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, test_size=0.3)
3. random_state — контроль случайности
Самый важный параметр для воспроизводимости!
# Без random_state — каждый раз разное разделение
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# Запуск 1: объекты [0,1,2,3,4] попали в test
# Запуск 2: объекты [5,7,9,11,15] попали в test
# С random_state — всегда одинаковое разделение
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Запуск 1: объекты [0,1,2,3,4] попали в test
# Запуск 2: объекты [0,1,2,3,4] попали в test (те же!)
Зачем это нужно?
- ✅ Воспроизводимость результатов
- ✅ Возможность сравнить разные модели на одних и тех же данных
- ✅ Отладка кода
- ✅ Научные исследования (другие смогут повторить ваши результаты)
Какое значение выбрать?
- Любое целое число: 0, 1, 42, 123, 999, ...
- 42 — самое популярное (отсылка к "Автостопом по галактике")
- Главное — использовать одно и то же значение во всем проекте
4. shuffle — перемешивание данных
# shuffle=True (по умолчанию) — данные перемешиваются перед разделением
X_train, X_test, y_train, y_test = train_test_split(X, y, shuffle=True)
# shuffle=False — данные НЕ перемешиваются
X_train, X_test, y_train, y_test = train_test_split(X, y, shuffle=False)
# Train: первые 80% строк
# Test: последние 20% строк
Когда использовать shuffle=False?
- Временные ряды (данные упорядочены по времени)
- Когда порядок данных важен
В большинстве случаев используйте shuffle=True (по умолчанию)!