машинное обучение
May 14, 2022

Создание пайплайнов предобработки данных

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

from sklearn.datasets import load_diabetes
from sklearn.metrics import mean_absolute_error, mean_absolute_percentage_error
import pandas as pd
import numpy as np
np.random.seed(0)

df, y = load_diabetes(return_X_y=True, as_frame=True)
df['target'] = y
display(df.head())
display(df.shape) 

Разобьем данные на тренировочный и тестовый наборы:

from sklearn.model_selection import train_test_split

X_tr, X_ts, y_tr, y_ts = train_test_split(df.drop(columns='target').copy(), 
                                          df['target'], test_size=0.2)
y_tr.shape[0], y_ts.shape[0]

Теперь предскажем значения target с использованием линейной регрессии (Ridge) и посчитаем ошибки (абсолютную и процентную):

from sklearn.linear_model import Ridge
model = Ridge()

model.fit(X_tr, y_tr)
y_p = model.predict(X_ts)

print(f'{mean_absolute_error(y_ts, y_p):.2f}',
      f'{mean_absolute_percentage_error(y_ts, y_p):.3f}')

Так как для модели линейной регрессии желательно нормализовать признаки, применим StandardScaler, но включим его в качестве промежуточного шага в экземпляр класса Pipeline:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

model = Pipeline(steps=[('prep', StandardScaler()), ('reg', Ridge())])

model.fit(X_tr, y_tr)
y_p = model.predict(X_ts)

print(f'{mean_absolute_error(y_ts, y_p):.3f}',
      f'{mean_absolute_percentage_error(y_ts, y_p):.3f}')

В Pipeline задается цепочка трансформаторов, после которых идет оценщик (фактически наша модель). Метод fit приводит к последовательному вызову fit, transform каждого трансформатора и только fit для оценщика. А predict - вызывает последовательность вызовов transform трансформаторов и predict оценщика.

Можно в качестве первого шага также задать композитную трансформацию колонок, например, категориальный столбец 'sex' не требует нормализации, зато его следует закодировать:

from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import make_column_transformer

cat_cols = ['sex']
num_cols = df.drop(columns=['target', 'sex']).columns

ct = make_column_transformer((OneHotEncoder(),cat_cols),(StandardScaler(), num_cols))

model = Pipeline(steps=[('prep', ct), ('reg', Ridge())])
model.fit(X_tr, y_tr)
y_p = model.predict(X_ts)

print(f'{mean_absolute_error(y_ts, y_p):.3f}',
      f'{mean_absolute_percentage_error(y_ts, y_p):.3f}')

Теперь перепишем последнюю ячейку вручную, чтобы лучше понимать, что происходит внутри:

предобработка:

sc = StandardScaler()
X_tr[num_cols] = sc.fit_transform(X_tr[num_cols])
X_ts[num_cols]= sc.transform(X_ts[num_cols])

ohe = OneHotEncoder(sparse=False)
ohe.fit(X_tr[cat_cols])
X_tr_cat = pd.DataFrame(ohe.transform(X_tr[cat_cols]), 
                              columns=ohe.get_feature_names(cat_cols), index=X_tr.index)
X_ts_cat = pd.DataFrame(ohe.transform(X_ts[cat_cols]), 
                              columns=ohe.get_feature_names(cat_cols), index=X_ts.index)
X_tr = X_tr[num_cols].merge(X_tr_cat, left_index=True, right_index=True)
X_ts = X_ts[num_cols].merge(X_ts_cat, left_index=True, right_index=True)

и предсказание:

model = Ridge()
model.fit(X_tr, y_tr)
y_p = model.predict(X_ts)

print(f'{mean_absolute_error(y_ts, y_p):.3f}',f'{mean_absolute_percentage_error(y_ts, y_p):.3f}')

Полезные ссылки:

Композитная трансформация колонок

Не пропустите ничего интересного и подписывайтесь на страницы канала в других социальных сетях:

Яндекс Дзен

Telegram