Pipeline и первый ML-проект: от данных до сохранённой модели

Итоговый ML-проект — это воспроизводимый путь от исходной таблицы до проверенного прогноза, а не один вызов fit. Он фиксирует постановку, разделение данных, преобразования, baseline, выбор метрики, финальную оценку и контракт использования модели.

Каркас проекта

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

Затем разделите данные способом, похожим на production. Исследуйте только train, а test отложите. Все решения по признакам, алгоритму, порогу и гиперпараметрам принимайте через validation или кросс-валидацию.

Полный Pipeline для смешанной таблицы

from pathlib import Path
import pickle

import pandas as pd

from sklearn.compose import ColumnTransformer
from sklearn.dummy import DummyClassifier
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler

X = pd.DataFrame({
    'age': [22, 28, 35, 41, 46, 53, 31, 39, 44, 26, 58, 33],
    'amount': [1_200, 800, 3_400, 2_100, 5_600, 4_800, 1_700, 2_900, 6_200, 950, 7_100, 2_400],
    'city': ['Казань', 'Омск', 'Москва', 'Казань', 'Москва', 'Омск', 'Казань', 'Москва', 'Омск', 'Казань', 'Москва', 'Омск'],
    'channel': ['web', 'app', 'app', 'web', 'app', 'web', 'app', 'web', 'app', 'web', 'app', 'web'],
})
y = [0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0]
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42, stratify=y
)

numeric = make_pipeline(SimpleImputer(strategy='median'), StandardScaler())
categorical = make_pipeline(
    SimpleImputer(strategy='most_frequent'),
    OneHotEncoder(handle_unknown='ignore'),
)
features = ColumnTransformer([
    ('numeric', numeric, ['age', 'amount']),
    ('categorical', categorical, ['city', 'channel']),
])

pipeline = make_pipeline(
    features,
    LogisticRegression(max_iter=2_000),
)
pipeline.fit(X_train, y_train)

baseline = DummyClassifier(strategy='most_frequent').fit(X_train, y_train)
predictions = pipeline.predict(X_test)
print('Baseline accuracy:', baseline.score(X_test, y_test))
print(classification_report(y_test, predictions, zero_division=0))

with Path('model.pkl').open('wb') as file:
    pickle.dump(pipeline, file)

with Path('model.pkl').open('rb') as file:
    restored_pipeline = pickle.load(file)

print('Smoke prediction:', restored_pipeline.predict(X_test.head(2)))

Pickle показан как компактный учебный пример, но загружать недоверенный файл нельзя: десериализация способна выполнить произвольный код. Артефакт также не гарантирует совместимость между версиями scikit-learn; сохраняйте окружение и происхождение модели.

Что хранить рядом с артефактом

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

Проверка перед сохранением

Один раз посчитайте test-метрики после завершения выбора. Сравните с baseline, проверьте матрицу ошибок и сегменты, убедитесь, что Pipeline принимает сырые строки в том же формате, что и будущий сервис. Добавьте тест на неизвестную категорию, пропуск и неверный набор колонок.

Также измерьте время predict, размер артефакта и потребление памяти. Модель, которая выигрывает 0,1% метрики, но не укладывается в задержку, не является лучшей для приложения.

После запуска работа продолжается

Логируйте версию модели, схему входа, задержку и агрегированные характеристики данных без лишних персональных значений. Когда появляются подтверждённые ответы, считайте качество и его доверительный интервал. Следите за долями классов, пропусками, неизвестными категориями и сдвигом признаков.

Переобучение запускается не просто по календарю. Нужен триггер, процедура сравнения кандидата с текущей моделью и возможность отката. Кандидат сначала проходит заранее зафиксированную validation-схему или rolling backtest. Свежий независимый holdout используют для редкой финальной проверки: после многократных решений по нему он становится внутренним benchmark и перестаёт быть независимым.

Практика: защита мини-проекта

Возьмите открытый табличный датасет и подготовьте репозиторий с README, фиксированным split, Pipeline, baseline и одной основной метрикой. Добавьте команду обучения, команду оценки и тест, который загружает три новые строки. В отчёте назовите два ограничения и сигнал для пересмотра модели.

Что важно запомнить

Источники