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 и одной основной метрикой. Добавьте команду обучения, команду оценки и тест, который загружает три новые строки. В отчёте назовите два ограничения и сигнал для пересмотра модели.
Что важно запомнить
- Pipeline является версионируемой частью модели вместе с преобразованиями.
- Финальный test используют после завершения всех решений.
- Артефакт требует схемы входа, окружения, метрик и происхождения.
- После запуска нужны мониторинг, новые ответы и безопасная процедура замены.