1.3 Первая модель и train/test split; утечка данных и переобучение

Урок 1.3. Первая модель

После урока вы сможете:

  • разделять данные на обучающую и тестовую выборки;
  • строить baseline и объяснять, зачем он нужен;
  • обучать линейную регрессию в pipeline и оценивать её по MAE;
  • распознавать утечку данных и переобучение.

Train и test: экзамен для модели

Представьте студента, который выучил ответы на экзаменационные билеты, не понимая предмета. На знакомых билетах он получит «отлично», на новых — провалится. С моделями то же самое. Поэтому мы прячем часть данных — тестовую выборку — и проверяем модель только на ней.

from sklearn.model_selection import train_test_split

X = df[num_features + cat_features]   # признаки
y = df['price_usd']                   # целевая переменная

# 80% данных на обучение, 20% на проверку
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42)

random_state=42 фиксирует случайное разбиение, чтобы у вас получились те же цифры, что и в уроке.

Метрика MAE

MAE (mean absolute error) — средняя абсолютная ошибка. Если модель прогнозирует $60 000, а квартира стоит $65 000, ошибка равна $5 000. MAE — среднее таких ошибок по всем квартирам теста. Её легко объяснить руководителю: «в среднем модель ошибается на столько-то долларов».

Baseline: с чем сравниваем

Модель с MAE $6 000 — это хорошо или плохо? Без точки отсчёта ответить нельзя. Baseline — самое простое разумное решение. Для цены квартиры это правило «всегда называй медианную цену».

from sklearn.dummy import DummyRegressor
from sklearn.metrics import mean_absolute_error

baseline = DummyRegressor(strategy='median').fit(X_train, y_train)
mae_base = mean_absolute_error(y_test, baseline.predict(X_test))
print(f'Baseline MAE: ${mae_base:,.0f}')   # ≈ $19 900

Линейная регрессия

Линейная регрессия ищет, на сколько долларов меняется цена при изменении каждого признака: +1 м² площади, переход из 104 серии в элитку, +1 км от центра. Подключаем её к pipeline из урока 1.2:

from sklearn.linear_model import LinearRegression

model = Pipeline([('prep', preprocess),
                  ('lr', LinearRegression())])
model.fit(X_train, y_train)

mae_lr = mean_absolute_error(y_test, model.predict(X_test))
print(f'Linear regression MAE: ${mae_lr:,.0f}')         # ≈ $5 800
print(f'Улучшение к baseline: {1 - mae_lr / mae_base:.0%}')  # ≈ 71%

Результат для BishkekDom: модель ошибается в среднем примерно на $5 800 вместо $19 900 у baseline. Это на 71% точнее. Для квартиры стоимостью $65 000 ошибка около 9% — вполне рабочий ориентир для агента на первой встрече с клиентом.

Теперь модель можно применить к новой квартире:

new_flat = pd.DataFrame([{
    'rooms': 2, 'area_m2': 68, 'floor': 7, 'floors_total': 12,
    'year_built': 2019, 'has_parking': 1, 'distance_center_km': 3.5,
    'district': 'Первомайский', 'building_series': 'Элитка',
    'condition': 'Евроремонт', 'heating': 'Автономное'}])

print(f'Прогноз цены: ${model.predict(new_flat)[0]:,.0f}')

Ловушка 1: утечка данных

В выгрузке есть столбец price_per_m2 — цена за квадратный метр. Добавим его в признаки:

# MAE с price_per_m2 ≈ $2 900 — в два раза лучше!

Слишком хороший результат — повод насторожиться. price_per_m2 вычислен из цены: это цена, делённая на площадь. Модель фактически подглядывает в ответ. Агент в момент приёма объявления этого числа не знает, поэтому в реальной работе такая модель бесполезна. Это и есть утечка данных (data leakage) — одна из самых частых и дорогих ошибок в ML.

Как проверить признак на утечку: спросите себя, будет ли это значение известно в момент прогноза. Если нет или «вычислено из ответа» — признак убираем.

Ловушка 2: переобучение

Сравним ошибку на train и на test для дерева решений разной глубины (подробно деревья изучим в модуле 4):

Глубина дерева MAE на train MAE на test
2 $12 200 $13 100
5 $7 500 $9 000
10 $1 700 $8 700
Без ограничения $0 $9 100

Дерево без ограничения глубины ошибается на train ровно на ноль долларов: оно запомнило каждую квартиру. Но на новых квартирах оно хуже, чем дерево глубиной 10. Это переобучение: модель выучила шум вместо закономерностей. Признак переобучения — большой разрыв между ошибкой на train и на test.

Обратите внимание: простая линейная регрессия ($5 800) обошла все деревья. Сложная модель не всегда лучше. Именно поэтому профессионалы начинают с baseline и простых моделей, а сложность добавляют только тогда, когда она даёт измеримый выигрыш.

Итоги урока и модуля

  • Модель оценивается только на данных, которые она не видела (test).
  • Baseline — обязательная точка отсчёта. Без него нельзя сказать, хороша ли модель.
  • MAE показывает среднюю ошибку в понятных бизнесу единицах.
  • Слишком хороший результат часто означает утечку данных.
  • Большой разрыв между train и test означает переобучение.

Вы прошли полный цикл ML: задача → данные → очистка → pipeline → baseline → модель → проверка. Переходите к квизу и практическому заданию модуля.