Значительно увеличьте результаты поиска в сетке с помощью этих параметров
Поиск по сетке на любом этапе конвейера машинного обучения с использованием EstimatorSwitch
Очень распространенным шагом в построении модели машинного обучения является поиск по сетке параметров классификатора в наборе поездов с использованием перекрестной проверки для поиска наиболее оптимальных параметров. Что менее известно, так это то, что вы также можете выполнять поиск по сетке практически на любом этапе конвейера, например, на этапах разработки функций. Например, какая стратегия вменения лучше всего подходит для числовых значений? Среднее, срединное или произвольное? Какой категориальный метод кодирования использовать? Горячее кодирование, а может порядковое?
В этой статье я проведу вас через шаги, чтобы иметь возможность отвечать на такие вопросы в ваших собственных проектах машинного обучения, используя поиск по сетке.
Чтобы установить все необходимые пакеты Python для этой статьи:
pip install extra-datascience-tools feature-engine
Набор данных
Давайте рассмотрим следующий очень простой набор общедоступных данных, который я создал, который имеет два столбца: last_grade
и passed_course
. Столбец «Последняя оценка» содержит оценку, полученную учащимся на последнем экзамене, а столбец «Пройденный курс» представляет собой логический столбец, в котором указано, True
прошел ли учащийся курс и False
не прошел ли учащийся курс. Можем ли мы построить модель, которая предсказывает, сдал ли студент курс на основе его последней оценки?
Давайте сначала исследуем набор данных :
import pandas as pd
df = pd.read_csv('last_grades.csv')
df.isna().sum()
OUTPUT
last_grade 125
course_passed 0
dtype: int64
Конечно, чтобы предотвратить утечку данных, мы должны сначала разделить наш набор данных на поезд и тестовый набор, прежде чем продолжить.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
df[['last_grade']],
df['course_passed'],
random_state=42)
Вместо того, чтобы анализировать, почему у некоторых учащихся отсутствует их последняя оценка, мы просто попытаемся использовать поиск по сетке для различных методов вменения, чтобы проиллюстрировать, как выполнять поиск по сетке на любом этапе конвейера, таком как этот этап разработки признаков.
Давайте исследуем распределение независимой переменной last_grade
:
import seaborn as sns
sns.histplot(data=X_train, x='last_grade')
Distribution of last_grade (Image by Author)
Давайте также посмотрим на распределение целевой переменной, чтобы определить, какую метрику оценки использовать:
y_train.value_counts()
OUTPUT
True 431
False 412
Name: course_passed, dtype: int64
Поиск по сетке
Далее мы настроим модель и поиск по сетке и запустим ее, просто оптимизировав параметры классификатора, как я вижу, большинство специалистов по данным используют поиск по сетке. Сейчас мы будем использовать feature-engine для определения среднего значения и scikit-learn для прогнозирования целевой переменной.MeanMedianImputer
DecisionTreeClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
from feature-engine.imputation import MeanMedianImputer
model = Pipeline(
[
("meanmedianimputer", MeanMedianImputer(imputation_method="mean")),
("tree", DecisionTreeClassifier())
]
)
param_grid = [
{"tree__max_depth": [None, 2, 5]}
]
gridsearch = GridSearchCV(model, param_grid=param_grid)
gridsearch.fit(X_train, y_train)
gridsearch.train(X_train, y_train)
pd.DataFrame(gridsearch.cv_results_).loc[:,
['rank_test_score',
'mean_test_score',
'param_tree__max_depth']
].sort_values('rank_test_score')
Results from code above (Image by Author)
Однако мы не знаем, является ли вменение отсутствующих значений last_grades
средним значением на самом деле лучшей стратегией вменения. Что мы можем сделать , так это поиск по сетке по трем различным стратегиям вменения с использованием дополнительных инструментов обработки данных :EstimatorSwitch
- Среднее вменение
- Медианное вменение
- Вменение произвольного числа (по умолчанию 999 для файлов
ArbitraryNumberImputer
.
from feature_engine.imputation import (
ArbitraryNumberImputer,
MeanMedianImputer,
)
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier
from extra_ds_tools.ml.sklearn.meta_estimators import EstimatorSwitch
# create a pipeline with two imputation techniques
model = Pipeline(
[
("meanmedianimputer", EstimatorSwitch(
MeanMedianImputer()
)),
("arbitraryimputer", EstimatorSwitch(
ArbitraryNumberImputer()
)),
("tree", DecisionTreeClassifier())
]
)
# specify the parameter grid for the classifier
classifier_param_grid = [{"tree__max_depth": [None, 2, 5]}]
# specify the parameter grid for feature engineering
feature_param_grid = [
{"meanmedianimputer__apply": [True],
"meanmedianimputer__estimator__imputation_method": ["mean", "median"],
"arbitraryimputer__apply": [False],
},
{"meanmedianimputer__apply": [False],
"arbitraryimputer__apply": [True],
},
]
# join the parameter grids together
model_param_grid = [
{
**classifier_params,
**feature_params
}
for feature_params in feature_param_grid
for classifier_params in classifier_param_grid
]
EstimatorSwitch
потому что мы не хотим использовать оба импьютера одновременно. Это связано с тем, что после того, как первый импутер преобразовал X , не останется nan
значений для преобразования вторым импутером.max_tree_depth
None , 2 и 5 как для , так ArbitraryNumberImputer
и для MeanMedianImputer
.MeanMedianImputer
и for. ArbitraryNumberImputer
С помощью apply
параметра EstimatorSwitch
мы можем просто включить или выключить один из двух импьютеров. Конечно, вы также можете запустить код дважды, один раз с закомментированным первым импутером, а второй — с закомментированным вторым импутером. Однако это приведет к ошибкам в нашей сетке параметров, поэтому нам также потребуется скорректировать ее, а результаты различных стратегий вменения недоступны в одних и тех же результатах поиска по сетке cv, что значительно усложняет поиск. сравнивать.gridsearch = GridSearchCV(model, param_grid=model_param_grid)
gridsearch.fit(X_train, y_train)
gridsearch.train(X_train, y_train)
pd.DataFrame(gridsearch.cv_results_).loc[:,
['rank_test_score',
'mean_test_score',
'param_tree__max_depth',
'param_meanmedianimputer__estimator__imputation_method']
].sort_values('rank_test_score')
Grid-search results on feature engineering (image by Author)
Конечно, поиск по сетке уже может занимать довольно много времени, и поиск по сетке не только по классификатору, но и по другим шагам конвейера также может занять больше времени. Есть несколько способов свести дополнительное время к минимуму:
- Сначала поиск по сетке по параметрам классификатора, а затем по другим шагам, таким как этапы разработки признаков, или наоборот, в зависимости от ситуации.
- Используйте дополнительные инструменты обработки данных ,
filter_tried_params
чтобы предотвратить дублирование настроек параметров поиска по сетке. - Используйте scikit-learn или
HalvingGridSearch
вместоHalvingRandomSearch
aGridSearchCV
(все еще в экспериментальной фазе).
Помимо использования поиска по сетке для оптимизации классификатора, такого как дерево решений, мы увидели, что вы действительно можете оптимизировать практически любой шаг в конвейере машинного обучения, используя дополнительные инструменты обработки данных , EstimatorSwitch
например, поиск по сетке по стратегии вменения. Еще несколько примеров шагов пайплайна, которые стоит поискать по сетке помимо стратегии вменения и самого классификатора:
- Среднее , порядковое и однократное кодирование категориальной переменной.
- Допуск кодировщика редких меток .
- Произвольный улавливатель выбросов против триммера выбросов .
- Использовать ли целевой преобразователь регрессора или нет.