#mlgems #sklearn #pipelines
Столкнулся с ситуацией, когда есть конвейер sklearn/imblearn с препроцессингом (удаление, нормализация некоторых столбцов), в конце бустинг, поддерживающий задание отдельного eval_set ( catboost, xgboost). К eval_set конвейер, конечно же, не применяется, т.к. pipeline про eval_set знает только то, что это ещё один из параметров для модели в конце списка. Как быть? Тестирую пока решение с промежуточным конвейером, только пытаюсь сделать его более эффективным.
Столкнулся с ситуацией, когда есть конвейер sklearn/imblearn с препроцессингом (удаление, нормализация некоторых столбцов), в конце бустинг, поддерживающий задание отдельного eval_set ( catboost, xgboost). К eval_set конвейер, конечно же, не применяется, т.к. pipeline про eval_set знает только то, что это ещё один из параметров для модели в конце списка. Как быть? Тестирую пока решение с промежуточным конвейером, только пытаюсь сделать его более эффективным.
Stack Overflow
Sklearn pass fit() parameters to xgboost in pipeline
Similar to How to pass a parameter to only one part of a pipeline object in scikit learn? I want to pass parameters to only one part of a pipeline. Usually, it should work fine like:
estimator =
estimator =
#earlystopping #pipelines #boostings
При тестировании отборщиков признаков в конвейере (а это, по идее, лучшая практика) вдруг осознал, что из 3-х основных бустингов только катбуст может обучать финальную модель с ранней остановкой, и то, если нет категориальных признаков в датасете. Все остальные требуют явного указания валидационного множества в fit_params, т.е. создаёшь такой его до запуска конвейера из начальных признаков (а как ещё-то?), первым этапом конвейера запускается отборщик признаков, убирает у тебя, скажем, половину фич, передаёт самые важные на обучение финальной модели, а она валится с ошибкой, что в валидационном множестве найдены несовпадающие признаки. Вопрос: каким местом думают разработчики популярных бустингов, почему не сделали передачу индексов или вообще сплиттеров вместо полноценных данных?
Пока выход виден только один, отказаться от лучшей практики и фиттить отборщик признаков отдельно. Или есть ещё варианты?
Почему это вообще считалось лучшей практикой? Наверное, потому, что весь конвейер было легко сохранить в один файл и обучать на любых новых данных почти одной строкой. Почти потому, что надо ж ещё просплитить данные было на train и eval.
Пока что, если хочется следовать остальным лучшим практикам (Early Stopping etc), выходит что конвейер надо сохранять 2 частями: препроцессинг (с потенциальным созданием новых фичей)+FS, и финальная моделька (потенциально + обёртка в виде HPT).
Что-то не могу придумать красивого варианта (
При тестировании отборщиков признаков в конвейере (а это, по идее, лучшая практика) вдруг осознал, что из 3-х основных бустингов только катбуст может обучать финальную модель с ранней остановкой, и то, если нет категориальных признаков в датасете. Все остальные требуют явного указания валидационного множества в fit_params, т.е. создаёшь такой его до запуска конвейера из начальных признаков (а как ещё-то?), первым этапом конвейера запускается отборщик признаков, убирает у тебя, скажем, половину фич, передаёт самые важные на обучение финальной модели, а она валится с ошибкой, что в валидационном множестве найдены несовпадающие признаки. Вопрос: каким местом думают разработчики популярных бустингов, почему не сделали передачу индексов или вообще сплиттеров вместо полноценных данных?
Пока выход виден только один, отказаться от лучшей практики и фиттить отборщик признаков отдельно. Или есть ещё варианты?
Почему это вообще считалось лучшей практикой? Наверное, потому, что весь конвейер было легко сохранить в один файл и обучать на любых новых данных почти одной строкой. Почти потому, что надо ж ещё просплитить данные было на train и eval.
Пока что, если хочется следовать остальным лучшим практикам (Early Stopping etc), выходит что конвейер надо сохранять 2 частями: препроцессинг (с потенциальным созданием новых фичей)+FS, и финальная моделька (потенциально + обёртка в виде HPT).
Что-то не могу придумать красивого варианта (
#mlgems #pipelines #functiontransformer #preprocessing
Интересная находка. Если у Вас есть долго выполняющийся препроцессинг, который Вы тем не менее хотите использовать с несколькими ML модельками, есть рецепт, как оптимизировать время расчётов и избежать повторного бессмысленного фиттинга, но при этом сохранить преимущества конвейера (Pipeline).
Для этого нужно
1) вынести препроцессинг в отдельный субконвейер с заданным параметром memory
2) добавить к субконвейеру identity-транcформер, просто передающий входы дальше по цепочке. для этого можно использовать FunctionTransformer без указания func. зачем это надо: согласно доке, последний элемент конвейера НЕ КЭШИРУЕТСЯ, поэтому добавляем последним такой dummy-трансформер.
P.S. для ленивых - можете заменить Pipeline на make_pipeline, тогда не надо будет указывать явно имена шагов.
Интересная находка. Если у Вас есть долго выполняющийся препроцессинг, который Вы тем не менее хотите использовать с несколькими ML модельками, есть рецепт, как оптимизировать время расчётов и избежать повторного бессмысленного фиттинга, но при этом сохранить преимущества конвейера (Pipeline).
Для этого нужно
1) вынести препроцессинг в отдельный субконвейер с заданным параметром memory
2) добавить к субконвейеру identity-транcформер, просто передающий входы дальше по цепочке. для этого можно использовать FunctionTransformer без указания func. зачем это надо: согласно доке, последний элемент конвейера НЕ КЭШИРУЕТСЯ, поэтому добавляем последним такой dummy-трансформер.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import FunctionTransformer
preprocessor=Pipeline([('prep',MyExpensivePreprocessor()),('identity', FunctionTransformer())],memory=r"R:\Temp")
for model in (model1,model2,model3):
pipe=Pipeline([('prep',preprocessor),('est',model)])
pipe.fit(X,y)
...
P.S. для ленивых - можете заменить Pipeline на make_pipeline, тогда не надо будет указывать явно имена шагов.
✍2