Фон
Tidy Code облегчает все жизнь. Код в проекте ML, вероятно, будет прочитан много раз, поэтому облегчая наш рабочий процесс, чтобы понять, будет оценен позже всем в команде. Во время ML проектов нам нужно получить доступ к данным аналогичным образом (на протяжении всего нашего рабочего процесса) для обучения, проверки и прогнозирования нашей модели и данных. Прозрачный семантический для доступа к данным позволяет облегчить управление кодом между проектами. Кроме того, соглашения о именовании также очень полезны для того, чтобы иметь возможность понять и повторно использовать код оптимальным образом. Есть несколько инструментов, которые могут помочь в этой чистоте, такой как использование трубопроводов и данных о Dataclasses.
Mlengineer составляет 10% мл 90% инженера.
Трубопровод
Трубопровод – это мета Объект, который помогает управлять процессами в модели ML. Трубопроводы могут инкапсулировать отдельные процессы, которые впоследствии могут быть объединены вместе. Принуждение рабочего процесса, который будет реализован в пределах Объекты трубопроводов Может быть неприятности в начале (особенно преобразования между Pandas dataframe и np.ndarray ), но вниз, она гарантирует качество модели (Нет утечки данных, модульность и т. Д.). Вот Кевин Маркхэм 4 мин. видео Объясняя преимущества трубопроводов.
Dataclass.
Еще один полезный Python Object Сохранить наборы данных вдоль трубопровода Dataclasses. . Перед Python 3.7 вы можете использовать NamedTuple. Однако после Python 3.7 Dataclasses были введены, и теперь есть великий кандидат для хранения таких объектов данных. Использование Dataclasses позволяет получить доступ к консистенции различных наборов данных на протяжении всего трубопровода ML.
Трубопровод
Поскольку мы не анализируем ни один набор данных, этот блог пост является примером аванс трубопровод который включает в себя нестандартные части (нет стандартных Sklearn модули). Предполагая, что у нас есть задача классификации, и наши данные имеют числовые типы столбцов и категорических столбцов, трубопровод включает в себя:
- Предыдущая подготовка данных Preprocess на тип столбца
- Обрабатывать
категоричностолбцы, использующие VTREAT упаковка - Запустите Catboost классификатор.
Мы можем построить наш трубопровод следующим образом:
y = df.pop("label")
X = df.copy(True)
num_pipe = Pipeline([("scaler",StanderdScaler()),
("variance",VarianceThreshold()),
])
preprocess_pipe = ColumnTransformer(
remainder="passthrough",
transformers=[("num_pipe", num_pipe, X.select_dtypes("number"))]
)
pipe = Pipeline([("preprocess_pipe", preprocess_pipe),
("vtreat", BinomiaOutcomeTreatmentPlan()),
])
В этом Псевдо код Наш трубопровод имеет некоторую предварительную обработку цифровым столбцам, за которым следует обработка категорических колонн с пакетом VTREAT (он пройдет через все не категорические и числовые столбцы).
Примечание
- С
CatboostНе имеет метода преобразования, мы собираемся представить его позже. - Использование
VTREATявляется примером возможности использования нестандартных модулей в классификации (предполагая, что они следуютSklearnParadigms)
Так что теперь время пришло нарезать наши данные …
Тест против поезда против действительного
Общий рабочий процесс при разработке модели ML является необходимостью разделения даты в Тест/поезд/Допустимые наборы данных Отказ
Источник: Shan-Hung Wu & Datalab, Национальный университет Цин Хуа
В ореховой оболочке разница между данными:
- Тест – отложить в сторону – не смотри до окончательной оценки модели
- Поезд – DataSet для обучения модели
- Valid – DataSet для проверки модели во время этапа тренировки (это может быть через перекрестную итерацию проверки, GridSearch и т. Д.)
Каждый набор данных будет иметь аналогичные атрибуты, которые нам нужно будет сохранить и получить доступ по всему рабочему процессу ML. Для предотвращения путаницы давайте создадим Dataclass Сохранить наборы данных структурированным способом.
# basic dataclass
import numpy as np
from dataclasses import dataclass
@dataclass
class Split:
X: np.ndarray = None
y: np.array = None
idx: np.array = None
pred_class: np.array = None
pred_proba: np.ndarray = None
kwargs: Dict = None
def __init__(self, name:str):
self.name = name
Теперь мы можем создавать наборы наборах обучения и тестирования следующим образом:
train = Split(name='train') test = Split(name='test')
Каждый Dataclass будет иметь следующее поля :
Х– NDARRay NDARRay, хранящую все функцииy– Numpy Array, хранящая классификацию маркировкиIDX– индекс для хранения оригинальных индексов, полезных для ссылки на конец трубопроводной линииpred_class– Numpy Array, хранящая предсказанную классификациюpred_proba– NDARRAY NDARRAY для хранения вероятностей классификаций
Кроме того, мы будем хранить Имя Для Dataclass (в функции init Функция), чтобы легко ссылаться на него вдоль трубопровода.
Расщепление в действии
Существует несколько методов, которые можно использовать для разделения наборов данных. Когда данные дисбалансны, важно разделить данные со стратифицированным методом. В нашем случае мы решили использовать Streatifiedshufflesplit Однако в отличие от простого Train-Test Split Что возвращает сами наборы данных, StreatifiedshuffleSplit возвращает только индексы для каждой группы, поэтому нам понадобится функция помощника, чтобы получить функцию набора данных (наша функция HELPER – это приятно и минимально для использования наших Dataclasses ).
def get_split_from_idx(X, y, split1: Split, split2: Split):
split1.X, split2.X = X.iloc[split1.idx], X.iloc[split2.idx]
split1.y, split2.y = y.iloc[split1.idx], y.iloc[split2.idx]
return split1, split2
for fold_name, (train.idx, test.idx) in enumerate( StratifiedSplitValid(X, y, n_split=5, train_size=0.8) ):
train, test = get_split_from_idx(X, y, train, test) # a helper function
Трубопровод в действии
Теперь мы можем запустить первую часть нашего трубопровода
_train_X = pipe.fit_transform(train.X)
Как только у нас есть fit_transform Наши данные (позволяющие VTREAT MAGY на работу), мы можем представить Catboost классификатор в наш трубопровод.
catboost_clf = CatBoostClassifier()
train_valid = Split(name="train_valid")
valid = Split(name="valid")
for fold_name, (train_valid.idx, valid.idx) in enumerate(StratifiedSplitValid(_train_X, train.y, n_split=10, train_size=0.9) ):
train_valid, valid = get_split_from_idx(_train_X, train.y, train_valid, valid)
pipe.steps.append(("catboost_clf",catboost_clf))
pipe.fit(train_size.X, train_valid.y,
catboost_clf__eval_set=[(valid.X, valid.y)],
)
Обратите внимание на два следующих пункта:
- Использование
Pipe.steps.append.Мы можем представить шаги в трубопровод, который не может быть изначально частью рабочего процесса. - Добавление параметров в шаги в трубопроводе требуется использование двойного разъема для Вложенные параметры Отказ
Наконец мы можем получить некоторые результаты
test.pred_class = pipe.(test.X) test.pred_proba = pipe.pred_proba(test.X)[:,1]
Теперь, когда мы анализируем нашу модель, мы можем генерировать наши метрики (например, confusucy_matrix), путем легко ссылаться на соответствующий набор данных следующим образом:
from sklearn.metrics import confusion_matrix conf_matrix_test = confusion_matrix(y_true=test.y, y_pred=test.pred_class )
Заключение
Этот блог пост описывает преимущества для использования трубопроводов и датчасов. Работа с DataClasses действительно не является мозгом, поскольку он очень прост и может быть легко включен в любую базу кода. Трубопроводы требуют больше усилий при интеграции их в код, но преимущества являются существенными и оно того стоит. Я надеюсь, что пример проиллюстрировал потенциал для такого использования и вдохновляет и поощряет вас попробовать.
Оригинал: “https://dev.to/sephib/tidying-up-pipelines-with-dataclasses-2bde”