Как мигрировать Kaggle: пошаговая инструкция с примерами кода для переноса ноутбуков в продакшн

Подробное руководство по переносу кода из ноутбука Kaggle в продакшн-окружение: от декомпозиции и выноса конфигурации до создания модульного пайплайна предобработки, обучения и инференса с примерами на Python.
Участие в соревнованиях Kaggle — отличный способ отточить навыки Data Science, но победительское решение в ноутбуке и промышленный конвейер — это две большие разницы. Миграция кода с Kaggle в продакшн-среду — критический этап, который часто упускают из виду. Эта инструкция проведет вас через весь процесс: от извлечения логики из сырого ноутбука до создания модульного, тестируемого и развертываемого пайплайна.

Шаг 1: Анализ и декомпозиция ноутбука. Не пытайтесь перенести ноутбук целиком. Откройте его и выделите логические блоки: загрузка данных, предобработка (EDA, очистка, feature engineering), разделение на train/val/test, определение и обучение модели, инференс, создание сабмита. Каждый из этих блоков станет отдельным модулем или скриптом. Создайте новую структуру проекта:

my_kaggle_pipeline/
├── config/
│  └── params.yaml  # Конфигурация путей, гиперпараметров
├── data/
│  ├── make_dataset.py  # Скачивание/загрузка сырых данных
│  └── preprocess.py  # Вся предобработка и feature engineering
├── features/
│  └── build_features.py  # Создание фичей (может быть частью preprocess)
├── models/
│  ├── train.py  # Обучение модели
│  ├── predict.py  # Прогнозирование
│  └── model.py  # Архитектура модели (наследник torch.nn.Module или tf.keras.Model)
├── notebooks/
│  └── original_kaggle.ipynb # Исходный ноутбук для справки
├── tests/  # Unit-тесты
├── requirements.txt  # Зависимости
├── setup.py  # Для упаковки в пакет (опционально)
└── main.py  # Точка входа для обучения или инференса

Шаг 2: Вынос конфигурации. Жестко закодированные пути и параметры — главный враг продакшена. Вынесите их в YAML или JSON файл. Используйте библиотеку like Hydra, OmegaConf или просто `yaml`.

# config/params.yaml
data:
 raw_path: "data/raw/train.csv"
 processed_path: "data/processed/train.parquet"
model:
 name: "lightgbm"
 params:
 n_estimators: 1000
 learning_rate: 0.01
 num_leaves: 31
training:
 test_size: 0.2
 random_state: 42
 target_column: "target"

# В коде загружаем конфиг:
import yaml
with open('config/params.yaml', 'r') as f:
 config = yaml.safe_load(f)
raw_data_path = config['data']['raw_path']

Шаг 3: Рефакторинг предобработки данных. Это самая важная часть. Код из ноутбука, где все происходит в глобальном пространстве имен, нужно превратить в воспроизводимые функции, которые сохраняют fitted состояния (например, `sklearn` трансформеры) для применения на новых данных (тесте и в продакшене).

# data/preprocess.py
import joblib
import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler

def build_preprocessor(train_df, config):
 """Обучает препроцессор на тренировочных данных и возвращает его."""
 # 1. Импьютер для числовых колонок
 num_cols = train_df.select_dtypes(include=['number']).columns.tolist()
 num_imputer = SimpleImputer(strategy='median')
 num_imputer.fit(train_df[num_cols])

 # 2. Скалер
 scaler = StandardScaler()
 scaler.fit(num_imputer.transform(train_df[num_cols]))  # fit на импутированных данных

 preprocessor = {
 'num_imputer': num_imputer,
 'scaler': scaler,
 'num_cols': num_cols
 }
 # Сохраняем fitted препроцессор!
 joblib.dump(preprocessor, 'models/preprocessor.joblib')
 return preprocessor

def apply_preprocessing(df, preprocessor):
 """Применяет обученный препроцессор к новым данным."""
 num_imputer = preprocessor['num_imputer']
 scaler = preprocessor['scaler']
 num_cols = preprocessor['num_cols']

 df_processed = df.copy()
 df_processed[num_cols] = scaler.transform(num_imputer.transform(df[num_cols]))
 return df_processed

Шаг 4: Создание воспроизводимого конвейера обучения. Обучение модели не должно зависеть от порядка ячеек в ноутбуке.

# models/train.py
import pandas as pd
import lightgbm as lgb
from sklearn.model_selection import train_test_split
from .model import save_model
from data.preprocess import build_preprocessor, apply_preprocessing

def train_pipeline(config):
 # Загрузка данных
 df = pd.read_csv(config['data']['raw_path'])

 # Разделение ДО любой предобработки, чтобы избежать data leakage
 train_df, val_df = train_test_split(
 df, test_size=config['training']['test_size'],
 random_state=config['training']['random_state']
 )

 # Построение и применение препроцессора
 preprocessor = build_preprocessor(train_df, config)
 X_train = apply_preprocessing(train_df.drop(columns=[config['training']['target_column']]), preprocessor)
 y_train = train_df[config['training']['target_column']]
 X_val = apply_preprocessing(val_df.drop(columns=[config['training']['target_column']]), preprocessor)
 y_val = val_df[config['training']['target_column']]

 # Обучение модели
 model = lgb.LGBMRegressor(**config['model']['params'])
 model.fit(
 X_train, y_train,
 eval_set=[(X_val, y_val)],
 callbacks=[lgb.early_stopping(50), lgb.log_evaluation(100)]
 )

 # Сохранение модели
 save_model(model, 'models/trained_model.pkl')
 print("Модель обучена и сохранена.")
 return model, preprocessor

Шаг 5: Подготовка инференс-скрипта. Скрипт для предсказаний должен загружать сохраненные артефакты (модель, препроцессор) и применять их к новым данным.

# models/predict.py
import joblib
import pandas as pd
import lightgbm as lgb
from data.preprocess import apply_preprocessing

def load_artifacts(model_path='models/trained_model.pkl',
 preprocessor_path='models/preprocessor.joblib'):
 model = joblib.load(model_path)
 preprocessor = joblib.load(preprocessor_path)
 return model, preprocessor

def predict(input_data_path, config, model=None, preprocessor=None):
 """Делает предсказания для данных по указанному пути."""
 if model is None or preprocessor is None:
 model, preprocessor = load_artifacts()

 df_new = pd.read_csv(input_data_path)
 # Важно: применять ту же предобработку, что и к train
 X_new = apply_preprocessing(df_new, preprocessor)
 predictions = model.predict(X_new)

 # Сохранение предсказаний в формате, готовом для сабмита на Kaggle
 output_df = pd.DataFrame({
 'id': df_new['id'],  # предполагая, что есть колонка id
 'prediction': predictions
 })
 output_df.to_csv('data/predictions/submission.csv', index=False)
 print("Предсказания сохранены в data/predictions/submission.csv")
 return predictions

Шаг 6: Добавление тестов и логирования. Напишите простые unit-тесты для критических функций (например, `apply_preprocessing`). Добавьте логирование с помощью библиотеки `logging`, чтобы отслеживать прогресс обучения и ошибки в продакшене. Оберните основной пайплайн в `main.py`, который может принимать аргументы командной строки (с помощью `argparse`) для выбора режима: обучение или предсказание.

Такой структурированный подход превращает одноразовый исследовательский ноутбук в надежный, воспроизводимый и готовый к развертыванию конвейер машинного обучения, который можно запускать по расписанию, дообучать на новых данных и легко интегрировать в более крупные системы.
295 4

Комментарии (11)

avatar
hu2pzbyokmp 01.04.2026
Отличная инструкция! Как раз ищу способы привести свои Kaggle-эксперименты в божеский вид для работы.
avatar
f3dd3huka 01.04.2026
Наконец-то кто-то структурировал этот процесс! Беру в закладки для своей команды.
avatar
aja3fi 02.04.2026
Хороший обзор, но переход от research к production — это больше про культуру, чем про инструменты.
avatar
2vesljs9 02.04.2026
Актуально. Многие забывают про логирование и обработку ошибок при переносе, а это критично.
avatar
7wjidxt 02.04.2026
По шагу 3: вы рекомендуете DVC для управления данными, но не упомянули альтернативы вроде MLflow.
avatar
y6jndv 02.04.2026
Для маленьких проектов это избыточно. Часто достаточно просто вынести код в скрипты.
avatar
oqec3c 03.04.2026
Ждал подобного гайда. Особенно ценно про выделение конфигурации в отдельные файлы (YAML/JSON).
avatar
kb9ukeg4efh 03.04.2026
Спасибо! Самый болезненный этап — это именно декомпозиция монолитного ноутбука на модули.
avatar
l17v9v81 03.04.2026
Считаю, что важно добавить раздел про тестирование (pytest) для каждого модуля пайплайна.
avatar
83xqm6rg7 03.04.2026
Статья полезная, но примеры кода слишком схематичны. Хотелось бы больше реальных кейсов.
Вы просмотрели все комментарии