Aumente significativamente seus resultados de pesquisa de grade com esses parâmetros
Pesquisa de grade em qualquer etapa do pipeline de aprendizado de máquina usando um EstimatorSwitch
Uma etapa muito comum na construção de um modelo de aprendizado de máquina é pesquisar em grade os parâmetros de um classificador no conjunto de trens, usando validação cruzada, para encontrar os parâmetros mais ideais. O que é menos conhecido é que você também pode pesquisar em grade praticamente qualquer etapa do pipeline, como etapas de engenharia de recursos. Por exemplo, qual estratégia de imputação funciona melhor para valores numéricos? Média, mediana ou arbitrária? Qual método de codificação categórica usar? Codificação one-hot, ou talvez ordinal?
Neste artigo, guiarei você pelas etapas para poder responder a essas perguntas em seus próprios projetos de aprendizado de máquina usando pesquisas em grade.
Para instalar todos os pacotes Python necessários para este artigo:
pip install extra-datascience-tools feature-engine
O conjunto de dados
Vamos considerar o seguinte conjunto de dados de domínio público muito simples que criei e que possui duas colunas: last_grade
e passed_course
. A coluna da última nota contém a nota que o aluno obteve em seu último exame e a coluna do curso aprovado é uma coluna booleana com True
se o aluno foi aprovado no curso e False
se o aluno foi reprovado no curso. Podemos construir um modelo que preveja se um aluno passou no curso com base em sua última nota?
Vamos primeiro explorar o conjunto de dados :
import pandas as pd
df = pd.read_csv('last_grades.csv')
df.isna().sum()
OUTPUT
last_grade 125
course_passed 0
dtype: int64
Obviamente, para evitar qualquer vazamento de dados, devemos dividir nosso conjunto de dados em um conjunto de treinamento e teste antes de continuar.
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)
Em vez de analisar por que alguns alunos perderam a última nota, simplesmente tentaremos fazer uma pesquisa em grade em diferentes técnicas de imputação para ilustrar como fazer uma pesquisa em grade em qualquer etapa do pipeline, como esta etapa de engenharia de recursos.
Vamos explorar a distribuição da variável independente last_grade
:
import seaborn as sns
sns.histplot(data=X_train, x='last_grade')
Distribution of last_grade (Image by Author)
Vejamos também a distribuição da variável de destino para determinar qual métrica de pontuação usar:
y_train.value_counts()
OUTPUT
True 431
False 412
Name: course_passed, dtype: int64
Pesquisa em grade
Em seguida, vamos configurar o modelo e a pesquisa em grade e executá-lo apenas otimizando os parâmetros do classificador, que é como vejo a maioria dos cientistas de dados usar uma pesquisa em grade. Por enquanto, usaremos o feature-engine para imputar a média e o scikit-learn para prever a variável de destino.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)
No entanto, não sabemos se imputar a falta last_grades
com a média é realmente a melhor estratégia de imputação. O que podemos fazer é, na verdade, pesquisar em grade em três estratégias de imputação diferentes usando ferramentas extra-datascience ' EstimatorSwitch
:
- Imputação média
- imputação mediana
- Imputação de número arbitrário (por padrão , 999 para .
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
porque não queremos usar ambos os imputadores ao mesmo tempo. Isso ocorre porque após o primeiro imputador ter transformado X, não haverá nan
valores deixados para o segundo imputador transformar.max_tree_depth
de None , 2 e 5 para o ArbitraryNumberImputer
e o MeanMedianImputer
.MeanMedianImputer
e o ArbitraryNumberImputer
sejam aplicados ao mesmo tempo. Usando o apply
parâmetro de EstimatorSwitch
podemos simplesmente ligar ou desligar um dos dois imputadores. Claro, você também pode executar o código duas vezes, uma vez com o primeiro imputador comentado e a segunda execução com o segundo imputador comentado. No entanto, isso levará a erros em nossa grade de parâmetros, então precisaríamos ajustá-la também, e os resultados das diferentes estratégias de imputação não estão disponíveis na mesma grade de resultados de cv de pesquisa, o que torna muito mais difícil comparar.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)
Obviamente, a pesquisa em grade já pode levar algum tempo e, não apenas pesquisando em grade no classificador, mas também em outras etapas do pipeline, a pesquisa em grade também pode demorar mais. Existem alguns métodos para reduzir ao mínimo o tempo extra necessário:
- Primeiro pesquisa de grade sobre os parâmetros do classificador e, em seguida, sobre outras etapas, como etapas de engenharia de recursos ou vice-versa, dependendo da situação.
- Use extra-datascience-tools '
filter_tried_params
para evitar configurações de parâmetros duplicados de uma pesquisa em grade. - Use scikit-learn ’s
HalvingGridSearch
ouHalvingRandomSearch
ao invés de aGridSearchCV
(ainda em fase experimental).
Além de usar a pesquisa de grade para otimizar um classificador, como uma árvore de decisão, vimos que você pode realmente otimizar praticamente qualquer etapa em um pipeline de aprendizado de máquina usando ferramentas extras de ciência de dados , EstimatorSwitch
por exemplo, pesquisa de grade sobre a estratégia de imputação. Mais alguns exemplos de etapas do pipeline que valem a pena pesquisar na grade ao lado da estratégia de imputação e do próprio classificador são:
- Média vs codificação ordinal vs one-hot de uma variável categórica.
- A tolerância de um raro codificador de etiquetas .
- Um capper outlier arbitrário vs um aparador outlier .
- Se deve usar um transformador de regressor de destino ou não.