И почему вам стоит начать их использовать.

Вы когда-нибудь обучали модель машинного обучения, и ваши прогнозы выглядели слишком хорошо, чтобы быть правдой? Но потом вы поняли, что между данными обучения и тестирования произошла некоторая утечка данных?

Или у вас было много этапов предварительной обработки для подготовки данных, поэтому было трудно перенести этапы предварительной обработки из обучения модели в производство для получения реальных прогнозов?

Или ваша предварительная обработка становится беспорядочной, и вам трудно поделиться кодом в читаемой и понятной форме?

Тогда вам, возможно, захочется попробовать Pipeline scikit-learn. Pipeline — это элегантное решение для настройки рабочего процесса обучения, тестирования и производства машинного обучения, которое делает вашу жизнь проще, а результаты — более воспроизводимыми.

Но что такое конвейер, каковы его преимущества и как его настроить? Я рассмотрю эти вопросы и приведу несколько примеров кода строительных блоков. Комбинируя эти строительные блоки, вы можете создавать более сложные конвейеры, адаптированные к вашим потребностям.

Что такое трубопровод?

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

Почему мне следует использовать конвейер?

В целом использование конвейера упрощает вашу жизнь и ускоряет разработку моделей машинного обучения. Это потому, что трубопровод

  • приводит к более чистому и понятному коду
  • легко воспроизводить и понимать рабочие процессы с данными
  • легче читать и корректировать
  • ускоряет подготовку данных, поскольку конвейер автоматизирует подготовку данных
  • помогает избежать утечки данных
  • позволяет одновременно выполнять оптимизацию гиперпараметров для всех оценщиков и параметров в конвейере
  • это удобно, поскольку вам нужно всего лишь один раз вызвать fit() и predict(), чтобы запустить весь конвейер данных.

После того как вы обучили и оптимизировали свою модель и остались довольны результатами, вы можете легко сохранить обученный конвейер. Затем, когда вы захотите запустить свою модель, просто загрузите предварительно обученный конвейер, и вы будете готовы сделать некоторые выводы. Благодаря этому вы можете легко поделиться своей моделью в очень чистом виде, который легко воспроизвести и понять.

Как настроить конвейер?

Настроить конвейер с помощью scikit-learn очень просто и понятно.

Pipeline из scikit-learn использует список пар ключ-значение, который содержит преобразователи, которые вы хотите применить к своим данным в качестве значений. Ключи вы можете выбирать произвольно. Ключи можно использовать для доступа к параметрам преобразователей, например, при запуске поиска по сетке во время оптимизации гиперпараметров. Поскольку преобразователи хранятся в списке, вы также можете получить доступ к преобразователям путем индексации.

Чтобы разместить данные в вашем конвейере и сделать прогнозы, вы можете запустить fit() и predict() так же, как и с любым преобразователем или регрессором в scikit-learn.

Очень простой конвейер может выглядеть так:

from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LinearRegression

pipeline = Pipeline(
   steps=[("imputer", SimpleImputer()), 
          ("scaler", MinMaxScaler()), 
          ("regression", LinearRegression())
   ]
)

pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)

Однако scikit-learn сделает вашу жизнь еще проще, если вы не хотите вводить значения ключей для своих преобразователей. Вместо этого вы можете просто использовать функцию make_pipeline(), и scikit-learn устанавливает имена на основе имени класса преобразователя.

from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LinearRegression

pipeline = make_pipeline(steps=[
    SimpleImputer(), 
    MinMaxScaler(), 
    LinearRegression()
    ]
)

Вот и все. Благодаря этому вы быстро создали простой конвейер, который можно начать использовать для обучения модели и выполнения прогнозов. Если вы хотите посмотреть, как выглядит ваш конвейер, вы можете просто распечатать его, и scikit-learn покажет вам его интерактивное представление.

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

Не беспокойтесь, scikit-learn предоставляет дополнительные функции, с помощью которых вы можете создавать больше пользовательских конвейеров и вывести свои конвейеры на новый уровень. Эти функции:

  • ColumnTransformer
  • FeatureUnion
  • TransformedTargetRegressor

Я пройдусь по ним и покажу вам примеры того, как их использовать.

Преобразование выбранных объектов

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

Вы можете выполнить эти шаги предварительной обработки перед передачей функций в конвейер. Но в этом случае вы не сможете позже включить эти шаги и параметры предварительной обработки в поиск гиперпараметров. Кроме того, включение их в конвейер значительно упрощает работу с вашей моделью машинного обучения.

Чтобы применить преобразование или даже последовательность преобразований только к выбранным столбцам, вы можете использовать ColumnTransformer. Использование очень похоже на Pipeline, поскольку вместо передачи пары ключ-значение в steps мы просто передаем те же пары в transformers. Затем мы можем включить созданный преобразователь в качестве одного из этапов нашего конвейера.

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder

categorical_transformer = ColumnTransformer(
    transformers=[("encode", OneHotEncoder())]
)

pipeline = Pipeline(steps=[
    ("categorical", categorical_transformer, ["col_name"])
    ]
)

Поскольку мы хотим запустить преобразование только для определенных столбцов, нам нужно передать эти столбцы в конвейер. Более того, мы можем сообщить ColumnTransformer, что мы хотим делать с оставшимися столбцами. Например, если вы хотите сохранить столбцы, которые не были изменены преобразователем, вам необходимо установить remainder на passthrough. В противном случае столбцы удаляются. Вместо того, чтобы ничего не делать или удалять столбцы, вы также можете преобразовать оставшиеся столбцы, передав преобразователь.

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder

categorical_transformer = ColumnTransformer(
 transformers=[("encode", OneHotEncoder(), ["col_name"])], remainder="passthrough"
)

categorical_transformer = ColumnTransformer(
 transformers=[("encode", OneHotEncoder(), ["col_name"])], remainder=MinMaxScaler()
)
```

Поскольку scikit-learn допускает стекирование конвейеров, мы могли бы даже передать конвейер в ColumnTransformer вместо того, чтобы указывать каждое преобразование, которое мы хотим сделать, в самом ColumnTransformer.

from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder

categorical_transformer = Pipeline(steps=[("encode", OneHotEncoder())])
numerical_transformer = Pipeline(
   steps=[("imputation", SimpleImputer()), ("scaling", MinMaxScaler())]
)

preprocessor = ColumnTransformer(
   transfomers=[
     ("numeric", numerical_transformer),
     ("categoric", categorical_transformer, ["col_name"]),
   ]
)

pipeline = Pipeline(steps=["preprocesssing", preprocessor])

Объединение функций

Теперь вы можете выполнять разные этапы предварительной обработки для разных столбцов, но что, если вы хотите получить новые функции из данных и добавить их в свой набор функций?

Для этого вы можете использовать FeatureUnion, который объединяет объекты-трансформеры в новый трансформер с объединенными объектами. Запуск конвейера с FeatureUnion подбирает каждый трансформатор независимо, а затем объединяет их выходы.

Например, предположим, что мы хотим добавить скользящую среднюю в качестве функции, мы могли бы сделать это:

from sklearn.compose import FeatureUnion
from sklearn.pipeline import Pipeline

preprocessor = (
   FeatureUnion(
     [
       ("moving_Average", MovingAverage(window=30)),
       ("numerical", numerical_pipeline),
     ]
   ),
)

pipeline = Pipeline(steps=["preprocesssing", preprocessor])

Преобразование целевого значения

Если у вас есть проблема с регрессией, иногда это может помочь преобразовать цель перед подгонкой регрессии.

Вы можете включить такое преобразование, используя класс TransformedTargetRegressor. С помощью этого класса вы можете либо использовать преобразователи, предоставляемые scikit-learn, например масштабатор MinMax, либо писать свои собственные функции преобразования.

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

from sklearn.compose import TransformedTargetRegressor
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import MinMaxScaler

regressor = TransformedTargetRegressor(
    regressor=model, 
    func=np.log1p, 
    inverse_func=np.expm1
)

pipeline = Pipeline(
   steps=[
      ("imputer", SimpleImputer()), 
      ("scaler", MinMaxScaler()), 
      ("regressor", regressor)
    ]
)

pipeline.fit(X_train, y_train)

y_pred = pipeline.predict(X_test)

Создание собственных пользовательских функций

Иногда недостаточно использовать методы предварительной обработки, предусмотренные scikit-learn. Однако это не должно сдерживать вас при использовании Pipelines. Вы можете легко создавать свои собственные функции, которые затем включать в конвейер.

Для этого вам необходимо создать класс, содержащий методы fit() и transform(), поскольку они вызываются при запуске конвейера. Однако эти методы не обязательно должны что-либо делать. Более того, мы можем позволить классу наследовать классы scikit-learn BaseEstimator и TransformerMixin, чтобы предоставить нам некоторые базовые функции, необходимые нашему конвейеру.

Например, предположим, что мы хотим сделать прогноз для временного ряда и сгладить все функции с помощью скользящего среднего. Для этого мы просто создали класс с методом transform, который содержит часть сглаживания.

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import MinMaxScaler

class MovingAverage(BaseEstimator, TransformerMixin):

    def __init__(self, window=30):  
        self.window = window
    
    def fit(self, X, y=None):  
        return self
    
    def transform(self, X, y=None):
        return X.rolling(window=self.window, min_periods=1, center=False).mean()


pipeline = Pipeline(
   steps=[
       ("ma", MovingAverage(window=30)),
       ("imputer", SimpleImputer()),
       ("scaler", MinMaxScaler()),
       ("regressor", model),
   ]
)

pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)

Что еще нужно знать?

По умолчанию трансформаторы в scikit-learn возвращают пустой массив. Это может привести к проблемам в вашем конвейере, если вы хотите применить преобразование только к определенным функциям на втором этапе конвейера, например, только к категориальным функциям.

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

from sklearn import set_config
set_config(transform_output = "pandas")

При оптимизации гиперпараметров или при проверке отдельных параметров конвейера может оказаться полезным прямой доступ к параметрам. Для доступа к параметрам вы можете использовать синтаксис <estimator>__<parameter>syntax. Например, в приведенном выше примере скользящего среднего мы могли бы получить доступ к ширине окна преобразователя MovingAverage, вызвав pipeline.set_params(pipeline__ma_window=7).

Заключение

Использование Pipeline scikit-learn может значительно облегчить вашу жизнь при разработке новых моделей машинного обучения и настройке этапов предварительной обработки. Помимо множества преимуществ, настройка Pipeline также проста и понятна. Тем не менее, вы можете создавать сложные и настраиваемые конвейеры предварительной обработки, границы которых устанавливает только ваше творчество.

Если вам понравилась эта статья или у вас есть вопросы, оставьте комментарий или свяжитесь со мной. Мне также интересен ваш опыт работы с Pipeline scikit-learn.

Хотите узнать больше о Pipelines, перейдите по следующей ссылке: