Como melhorar a qualidade do código de aprendizado de máquina com o Scikit-learn Pipeline e o ColumnTransformer


Quando você está trabalhando em um projeto de aprendizado de máquina, as etapas mais tediosas geralmente são a limpeza e o pré-processamento de dados. Especialmente quando você está trabalhando em um Jupyter Notebook, executar código em muitas células pode ser confuso.

A biblioteca Scikit-learn tem ferramentas chamadas Pipeline e ColumnTransformer que podem realmente tornar sua vida mais fácil. Em vez de transformar o dataframe passo a passo, o pipeline combina todas as etapas de transformação. Você pode obter o mesmo resultado com menos código. Também é mais fácil entender fluxos de trabalho de dados e modificá-los para outros projetos.

Este artigo mostrará passo a passo como criar o pipeline de aprendizado de máquina, começando com um fácil e trabalhando até um mais complicado.

Se você estiver familiarizado com o pipeline Scikit-learn e o ColumnTransformer, você pode ir diretamente para a parte sobre a qual deseja saber mais.

Índice

  • O que é o Scikit-learn Pipeline?
  • O que é o Scikit-learn ColumnTransformer?
  • Qual é a diferença entre o Pipeline e o ColumnTransformer?
  • Como criar um pipeline
  • Como encontrar o melhor método de preparação de dados e hiperparâmetro
  • Como adicionar transformações personalizadas
  • Como escolher o melhor modelo de Machine Learning

O que é o Scikit-learn Pipeline?

Antes de treinar um modelo, você deve dividir seus dados em um conjunto de treinamento e um conjunto de testes. Cada conjunto de dados passará pelas etapas de limpeza e pré-processamento de dados antes de colocá-lo em um modelo de aprendizado de máquina.

Não é eficiente escrever código repetitivo para o conjunto de treinamento e o conjunto de testes. É aí que entra em jogo o pipeline scikit-learn.

O pipeline Scikit-learn é uma maneira elegante de criar um fluxo de trabalho de treinamento de modelo de aprendizado de máquina. Tem a seguinte aparência:

Em primeiro lugar, imagine que você pode criar apenas um pipeline no qual você pode inserir quaisquer dados. Esses dados serão transformados em um formato apropriado antes do treinamento ou previsão do modelo.

O pipeline Scikit-learn é uma ferramenta que une todas as etapas da manipulação de dados para criar um pipeline. Irá encurtar o seu código e torná-lo mais fácil de ler e ajustar. (Você pode até visualizar seu pipeline para ver as etapas dentro.) Também é mais fácil executar o GridSearchCV sem vazamento de dados do conjunto de testes.

O que é o Scikit-learn ColumnTransformer?

Como dito no site scikit-learn, este é o objetivo do ColumnTransformer:

"Este estimador permite que diferentes colunas ou subconjuntos de colunas da entrada sejam transformados separadamente e as características geradas por cada transformador serão concatenadas para formar um único espaço de feição.

Isso é útil para dados heterogêneos ou colunares, para combinar vários mecanismos de extração de recursos ou transformações em um único transformador."

Em resumo, o ColumnTransformer transformará cada grupo de colunas de dataframe separadamente e combiná-las-á mais tarde. Isso é útil no processo de pré-processamento de dados.

Qual é a diferença entre o Pipeline e o ColumnTransformer?

Há uma grande diferença entre Pipeline e ColumnTransformer que você deve entender.

Você usa o pipeline para várias transformações das mesmas colunas.

Por outro lado, você usa o ColumnTransformer para transformar cada conjunto de colunas separadamente antes de combiná-las mais tarde.

Tudo bem, com isso fora do caminho, vamos começar a codificar!!

Como criar um pipeline

Obter o conjunto de dados

Você pode baixar os dados que usei neste artigo a partir deste conjunto de dados kaggle. Aqui está um exemplo do conjunto de dados:

Eu escrevi um artigo explorando os dados deste conjunto de dados que você pode encontrar aqui se estiver interessado.

Em suma, este conjunto de dados contém informações sobre os candidatos a emprego e a sua decisão sobre se querem mudar de emprego ou não. O conjunto de dados tem colunas numéricas e categóricas.

Nosso objetivo é prever se um candidato mudará de emprego com base em suas informações. Esta é uma tarefa de classificação.

Plano de pré-processamento de dados

Observe que eu pulei a codificação de recursos categóricos para a simplicidade deste artigo.

Aqui estão os passos que seguiremos:

  1. Importar dados e codificação
  2. Definir conjuntos de colunas a serem transformadas de maneiras diferentes
  3. Dividir dados para treinar e testar conjuntos
  4. Criar pipelines para recursos numéricos e categóricos
  5. Criar ColumnTransformer para aplicar pipeline para cada conjunto de colunas
  6. Adicionar um modelo a um pipeline final
  7. Exibir o pipeline
  8. Passar dados através do pipeline
  9. (Opcional) Salve o pipeline

Etapa 1: Importar e codificar os dados

Depois de baixar os dados, você pode importá-los usando Pandas assim:

import pandas as pd

df = pd.read_csv("aug_train.csv")

Em seguida, codifice o recurso ordinal usando mapeamento para transformar características categóricas em características numéricas (uma vez que o modelo usa apenas entrada numérica).

# Making Dictionaries of ordinal features

relevent_experience_map = {
    'Has relevent experience':  1,
    'No relevent experience':    0
}

experience_map = {
    '<1'      :    0,
    '1'       :    1, 
    '2'       :    2, 
    '3'       :    3, 
    '4'       :    4, 
    '5'       :    5,
    '6'       :    6,
    '7'       :    7,
    '8'       :    8, 
    '9'       :    9, 
    '10'      :    10, 
    '11'      :    11,
    '12'      :    12,
    '13'      :    13, 
    '14'      :    14, 
    '15'      :    15, 
    '16'      :    16,
    '17'      :    17,
    '18'      :    18,
    '19'      :    19, 
    '20'      :    20, 
    '>20'     :    21
} 
    
last_new_job_map = {
    'never'        :    0,
    '1'            :    1, 
    '2'            :    2, 
    '3'            :    3, 
    '4'            :    4, 
    '>4'           :    5
}

# Transform categorical features into numerical features

def encode(df_pre):
    df_pre.loc[:,'relevent_experience'] = df_pre['relevent_experience'].map(relevent_experience_map)
    df_pre.loc[:,'last_new_job'] = df_pre['last_new_job'].map(last_new_job_map)
    df_pre.loc[:,'experience'] = df_pre['experience'].map(experience_map)
  
    return df_pre

df = encode(df)

Etapa 2: Definir conjuntos de colunas a serem transformadas de maneiras diferentes

Os dados numéricos e categóricos devem ser transformados de diferentes formas. Assim, defino num_col para colunas numéricas (números) e cat_cols para colunas categóricas.

num_cols = ['city_development_index','relevent_experience', 'experience','last_new_job', 'training_hours']

cat_cols = ['gender', 'enrolled_university', 'education_level', 'major_discipline', 'company_size', 'company_type']

Etapa 3: Criar pipelines para recursos numéricos e categóricos

A sintaxe do pipeline é:

Pipeline(steps = [(‘step name’, transform function), …])

Para características numéricas, executo as seguintes ações:

  1. SimpleImputer para preencher os valores em falta com a média dessa coluna.
  2. MinMaxScaler para dimensionar o valor para variar de 0 a 1 (isso afetará o desempenho da regressão).

Para recursos categóricos, executo as seguintes ações:

  1. SimpleImputer para preencher os valores em falta com o valor de maior frequência dessa coluna.
  2. OneHotEncoder para dividir em muitas colunas numéricas para treinamento de modelo. (handle_unknown='ignore' é especificado para evitar erros quando encontra uma categoria invisível no conjunto de testes)
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, MinMaxScaler
from sklearn.pipeline import Pipeline

num_pipeline = Pipeline(steps=[
    ('impute', SimpleImputer(strategy='mean')),
    ('scale',MinMaxScaler())
])
cat_pipeline = Pipeline(steps=[
    ('impute', SimpleImputer(strategy='most_frequent')),
    ('one-hot',OneHotEncoder(handle_unknown='ignore', sparse=False))
])

Etapa 4: Criar ColumnTransformer para aplicar o pipeline para cada conjunto de colunas

A sintaxe do ColumnTransformer é:

ColumnTransformer(transformers=[(‘step name’, transform function,cols), …])

Passe colunas numéricas através do pipeline numérico e passe colunas categóricas através do pipeline categórico criado na etapa 3.

remainder='drop' é especificado para ignorar outras colunas em um dataframe.

n_job=-1 significa que usaremos todos os processadores para executar em paralelo.

from sklearn.compose import ColumnTransformer

col_trans = ColumnTransformer(transformers=[
    ('num_pipeline',num_pipeline,num_cols),
    ('cat_pipeline',cat_pipeline,cat_cols)
    ],
    remainder='drop',
    n_jobs=-1)

Etapa 5: Adicionar um modelo ao pipeline final

Estou usando o modelo de regressão logística neste exemplo.

Crie um novo pipeline para combinar o ColumnTransformer na etapa 4 com o modelo de regressão logística. Eu uso um pipeline neste caso porque todo o dataframe deve passar pela etapa ColumnTransformer e pela etapa de modelagem, respectivamente.

from sklearn.linear_model import LogisticRegression

clf = LogisticRegression(random_state=0)
clf_pipeline = Pipeline(steps=[
    ('col_trans', col_trans),
    ('model', clf)
])

Etapa 6: Exibir o pipeline

A sintaxe para isso é display(nome do pipeline):

from sklearn import set_config

set_config(display='diagram')
display(clf_pipeline)

Você pode clicar na imagem exibida para ver os detalhes de cada etapa.
Quão conveniente!

Etapa 7: Dividir os dados em conjuntos de trem e teste

Divida 20% dos dados em um conjunto de testes como este:

from sklearn.model_selection import train_test_split

X = df[num_cols+cat_cols]
y = df['target']
# train test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y)

Vou ajustar a tubulação para o conjunto de trem e usar essa tubulação ajustada para o conjunto de teste para evitar vazamento de dados do conjunto de teste para o modelo.

Etapa 8: Passar dados pelo pipeline

Aqui está a sintaxe para isso:

pipeline_name.fit, pipeline_name.predict, pipeline_name.score

pipeline.fit passa dados através de um pipeline. Ele também se encaixa no modelo.

pipeline.predict usa o modelo treinado quando pipeline.fits para prever novos dados.

pipeline.score obtém uma pontuação do modelo no pipeline (precisão da regressão logística neste exemplo).

clf_pipeline.fit(X_train, y_train)
# preds = clf_pipeline.predict(X_test)
score = clf_pipeline.score(X_test, y_test)
print(f"Model score: {score}") # model accuracy

(Opcional) Etapa 9: salvar o pipeline

A sintaxe para isso é joblib.dumb.

Use a biblioteca joblib para salvar o pipeline para uso posterior, para que você não precise criar e ajustar o pipeline novamente. Quando você quiser usar um pipeline salvo, basta carregar o arquivo usando joblib.load assim:

import joblib

# Save pipeline to file "pipe.joblib"
joblib.dump(clf_pipeline,"pipe.joblib")

# Load pipeline when you want to use
same_pipe = joblib.load("pipe.joblib")

Como encontrar o melhor método de preparação de dados e hiperparâmetro

Um pipeline não só torna seu código mais organizado, mas também pode ajudá-lo a otimizar hiperparâmetros e métodos de preparação de dados.

Veja o que abordaremos nesta seção:

  • Como encontrar os parâmetros mutáveis do pipeline
  • Como encontrar os melhores conjuntos de hiperparâmetros: Adicionar um pipeline à Pesquisa em Grade
  • Como encontrar o melhor método de preparação de dados: pular uma etapa em um pipeline
  • Como encontrar os melhores conjuntos de hiperparâmetros e o melhor método de preparação de dados

Como encontrar os parâmetros de pipeline mutáveis

Primeiro, vamos ver a lista de parâmetros que podem ser ajustados.

clf_pipeline.get_params()

O resultado pode ser muito longo. Respire fundo e continue a leitura.

A primeira parte é apenas sobre as etapas do gasoduto.

Abaixo da primeira parte você encontrará o que nos interessa: uma lista de parâmetros que podemos ajustar.

O formato é step1_step2_..._parameter.

Por exemplo, col_trans_cat_pipeline_one-hot_sparse significa parâmetro esparso da etapa one-hot.

Você pode alterar parâmetros diretamente usando set_param.

clf_pipeline.set_params(model_C = 10)

Como encontrar os melhores conjuntos de hiperparâmetros: adicionar um pipeline à pesquisa de grade

A Pesquisa de Grade é um método que você pode usar para executar o ajuste de hiperparâmetros. Ele ajuda você a encontrar os conjuntos de parâmetros ideais que produzem a mais alta precisão do modelo.

Defina os parâmetros de ajuste e seu intervalo.

Criar um dicionário de parâmetros de ajuste (hiperparâmetros)

{ ‘tuning parameter’ : ‘possible value’, … }

Neste exemplo, quero encontrar o melhor tipo de penalidade e C de um modelo de regressão logística.

grid_params = {'model__penalty' : ['none', 'l2'],
               'model__C' : np.logspace(-4, 4, 20)}

Adicionar o pipeline à Pesquisa em Grade

GridSearchCV(model, tuning parameter, …)

Nosso pipeline tem uma etapa de modelo como etapa final, para que possamos inserir o pipeline diretamente na função GridSearchCV.

from sklearn.model_selection import GridSearchCV

gs = GridSearchCV(clf_pipeline, grid_params, cv=5, scoring='accuracy')
gs.fit(X_train, y_train)

print("Best Score of train set: "+str(gs.best_score_))
print("Best parameter set: "+str(gs.best_params_))
print("Test Score: "+str(gs.score(X_test,y_test)))

Depois de definir a Pesquisa em Grade, você pode ajustar a Pesquisa em Grade com os dados e ver os resultados. Vamos ver o que o código está fazendo:

  • .fit: ajusta-se ao modelo e tenta todos os conjuntos de parâmetros no dicionário de parâmetros de ajuste
  • .best_score_: a mais alta precisão em todos os conjuntos de parâmetros
  • .best_params_: O conjunto de parâmetros que produzem a melhor pontuação
  • .score(X_test,y_test): A pontuação ao tentar o melhor modelo com o conjunto de testes.

Você pode ler mais sobre GridSearchCV na documentação aqui.

Como encontrar o melhor método de preparação de dados: pular uma etapa em um pipeline

Encontrar o melhor método de preparação de dados pode ser difícil sem um pipeline, já que você precisa criar muitas variáveis para muitos casos de transformação de dados.

Com o pipeline, podemos criar etapas de transformação de dados no pipeline e realizar uma pesquisa de grade para encontrar a melhor etapa. Uma pesquisa em grelha selecionará o passo a ignorar e comparará o resultado de cada caso.

Como ajustar um pouco o pipeline atual

Quero saber qual método de dimensionamento funcionará melhor para meus dados entre MinMaxScaler e StandardScaler.

Eu adiciono uma etapa StandardScaler no num_pipeline. O resto não muda.

from sklearn.preprocessing import StandardScaler

num_pipeline2 = Pipeline(steps=[
    ('impute', SimpleImputer(strategy='mean')),
    ('minmax_scale', MinMaxScaler()),
    ('std_scale', StandardScaler()),
])

col_trans2 = ColumnTransformer(transformers=[
    ('num_pipeline',num_pipeline2,num_cols),
    ('cat_pipeline',cat_pipeline,cat_cols)
    ],
    remainder='drop',
    n_jobs=-1)
    
clf_pipeline2 = Pipeline(steps=[
    ('col_trans', col_trans2),
    ('model', clf)
])

Como executar a pesquisa de grade

Em parâmetros de pesquisa em grade, especifique as etapas que deseja ignorar e defina seu valor como passagem.

Como MinMaxScaler e StandardScaler não devem funcionar ao mesmo tempo, usarei uma lista de dicionários para os parâmetros de pesquisa em grade.

[{case 1},{case 2}]

Se utilizar uma lista de dicionários, a pesquisa em grelha realizará uma combinação de todos os parâmetros no caso 1 até à conclusão. Em seguida, ele executará uma combinação de todos os parâmetros no caso 2. Portanto, não há nenhum caso em que MinMaxScaler e StandardScaler sejam usados juntos.

grid_step_params = [{'col_trans__num_pipeline__minmax_scale': ['passthrough']},
                    {'col_trans__num_pipeline__std_scale': ['passthrough']}]

Execute a Pesquisa de grade e imprima os resultados (como uma pesquisa de grade normal).

gs2 = GridSearchCV(clf_pipeline2, grid_step_params, scoring='accuracy')
gs2.fit(X_train, y_train)

print("Best Score of train set: "+str(gs2.best_score_))
print("Best parameter set: "+str(gs2.best_params_))
print("Test Score: "+str(gs2.score(X_test,y_test)))

O melhor caso é minmax_scale : 'passthrough', então o StandardScaler é o melhor método de dimensionamento para esses dados.

Como encontrar os melhores conjuntos de hiperparâmetros e o melhor método de preparação de dados

Você pode encontrar os melhores conjuntos de hiperparâmetros e o melhor método de preparação de dados adicionando parâmetros de ajuste ao dicionário de cada caso do método de preparação de dados.

grid_params = {'model__penalty' : ['none', 'l2'],
               'model__C' : np.logspace(-4, 4, 20)}
               
grid_step_params = [{**{'col_trans__num_pipeline__minmax_scale': ['passthrough']}, **grid_params},
                    {**{'col_trans__num_pipeline__std_scale': ['passthrough']}, **grid_params}]

grid_params serão adicionados ao caso 1 (pular MinMaxScaler) e ao caso 2 (pular StandardScalerand).

# You can merge dictionary using the syntax below.

merge_dict = {**dict_1,**dict_2}

Execute a Pesquisa de grade e imprima os resultados (como uma pesquisa de grade normal).

gs3 = GridSearchCV(clf_pipeline2, grid_step_params2, scoring='accuracy')
gs3.fit(X_train, y_train)

print("Best Score of train set: "+str(gs3.best_score_))
print("Best parameter set: "+str(gs3.best_params_))
print("Test Score: "+str(gs3.score(X_test,y_test)))

Você pode encontrar o melhor conjunto de parâmetros usando .best_params_. Como minmax_scale : 'passthrough', então o StandardScaler é o melhor método de dimensionamento para esses dados.

Você pode mostrar todos os casos de pesquisa em grade usando .cv_results_:

pd.DataFrame(gs3.cv_results_)

Há 80 casos para este exemplo. Há tempo de execução e precisão de cada caso para você considerar, já que às vezes podemos selecionar o modelo mais rápido com precisão aceitável em vez do mais alto precisão.

Como adicionar transformações personalizadas e encontrar o melhor modelo de aprendizado de máquina

Procurar o melhor modelo de aprendizado de máquina pode ser uma tarefa demorada. O pipeline pode tornar essa tarefa muito mais conveniente para que você possa encurtar o ciclo de treinamento e avaliação do modelo.

Aqui está o que abordaremos nesta parte:

  • Adicionar uma transformação personalizada
  • Encontre o melhor modelo de aprendizagem automática

Como adicionar uma transformação personalizada

Além das funções padrão de transformação de dados, como MinMaxScaler do sklearn, você também pode criar sua própria transformação para seus dados.

Neste exemplo, vou criar um método de classe para codificar recursos ordinais usando mapeamento para transformar recursos categóricos em numéricos. Em palavras simples, mudaremos os dados de texto para números.

Primeiro, faremos o processamento de dados necessário antes do treinamento do modelo de regressão.

from sklearn.base import TransformerMixin

class Encode(TransformerMixin):
    
    def __init__(self):
        # Making Dictionaries of ordinal features
        self.rel_exp_map = {
            'Has relevent experience': 1,
            'No relevent experience': 0}
            
    def fit(self, df, y = None):
    	return self
        
    def transform(self, df, y = None):
        df_pre = df.copy()
        df_pre.loc[:,'rel_exp'] = df_pre['rel_exp']\
                               .map(self.rel_exp_map)
        return df_pre

Aqui está uma explicação do que está acontecendo neste código:

  • Crie uma classe chamada Encode que herda a classe base chamada TransformerMixin do sklearn.
  • Dentro da aula, existem 3 métodos necessários: __init__, ajustar e transformar
  • __init__ serão chamados quando um pipeline for criado. É onde definimos variáveis dentro da classe. Criei uma variável 'rel_exp_map' que é um dicionário que mapeia categorias para números.
  • O ajuste será chamado ao encaixar a tubulação. Deixei em branco para este caso.
  • transform será chamada quando uma transformação de pipeline for usada. Este método requer um dataframe (df) como uma entrada, enquanto y está definido como None por padrão (Ele é forçado a ter o argumento y, mas eu não vou usá-lo de qualquer maneira).
  • Na transformação, a coluna de dataframe 'rel_exp' será mapeada com o rel_exp_map.

Observe que o \ é apenas para continuar o código para uma nova linha.

Em seguida, adicione essa classe Encode como uma etapa de pipeline.

pipeline = Pipeline(steps=[
    ('Encode', Encode()),
    ('col_trans', col_trans),
    ('model', LogisticRegression())
])

Em seguida, você pode ajustar, transformar ou pesquisar em grade o pipeline como um pipeline normal.

Como encontrar o melhor modelo de Machine Learning

A primeira solução que me veio à mente foi adicionar muitas etapas do modelo em um pipeline e pular uma etapa alterando o valor da etapa para 'passthrough' na pesquisa de grade. Isso é como o que fizemos ao encontrar o melhor método de preparação de dados.

temp_pipeline = Pipeline(steps=[
    ('model1', LogisticRegression()),
    ('model2',SVC(gamma='auto'))
])

Mas vi um erro como este:

Ah ha – você não pode ter dois modelos de classificação em um pipeline!

A solução para esse problema é criar uma transformação personalizada que recebe um modelo como entrada e executa a pesquisa em grade para encontrar o melhor modelo.

Aqui estão os passos que seguiremos:

  1. Criar uma classe que recebe um modelo como entrada
  2. Adicionar a classe na etapa 1 a um pipeline
  3. Realizar pesquisa em grelha
  4. Imprimir resultados de pesquisa em grelha como uma tabela

Etapa 1: Criar uma classe que recebe um modelo como entrada

from sklearn.base import BaseEstimator
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC

class ClfSwitcher(BaseEstimator):

def __init__(self, estimator = LogisticRegression()):
        self.estimator = estimator
        
def fit(self, X, y=None, **kwargs):
        self.estimator.fit(X, y)
        return self
        
def predict(self, X, y=None):
        return self.estimator.predict(X)
        
def predict_proba(self, X):
        return self.estimator.predict_proba(X)
        
def score(self, X, y):
        return self.estimator.score(X, y)

Explicação do código:

  • Crie uma classe chamada ClfSwitcher que herda a classe base chamada BaseEstimator do sklearn.
  • Dentro da classe, existem cinco métodos necessários, como o modelo de classificação: __init__, ajuste, previsão, predict_proba e pontuação
  • __init__ recebe um estimador (modelo) como entrada. Eu afirmei LogisticRegression() como um modelo padrão.
  • ajuste é para ajuste de modelo. Não há valor de retorno.
  • Os outros métodos são simular o modelo. Ele retornará o resultado como se fosse o próprio modelo.

Etapa 2: Adicionar a classe na etapa 1 a um pipeline

clf_pipeline = Pipeline(steps=[
    ('Encode', Encode()),
    ('col_trans', col_trans),
    ('model', ClfSwitcher())
])

Etapa 3: Executar a pesquisa de grade

Existem 2 casos usando diferentes modelos de classificação em parâmetros de busca de grade, incluindo regressão logística e máquina vetorial de suporte.

from sklearn.model_selection import GridSearchCV

grid_params = [
    {'model__estimator': [LogisticRegression()]},
    {'model__estimator': [SVC(gamma='auto')]}
]

gs = GridSearchCV(clf_pipeline, grid_params, scoring='accuracy')
gs.fit(X_train, y_train)

print("Best Score of train set: "+str(gs.best_score_))
print("Best parameter set: "+str(gs.best_params_))
print("Test Score: "+str(gs.score(X_test,y_test)))

O resultado mostra que a regressão logística produz o melhor resultado.

Etapa 4: Imprimir os resultados da pesquisa em grade como uma tabela

pd.DataFrame(gs.cv_results_)

A regressão logística tem uma precisão um pouco maior do que a SVC, mas é muito mais rápida (menos tempo de ajuste).

Lembre-se de que você também pode aplicar diferentes métodos de preparação de dados para cada modelo.

Conclusão

Você pode implementar o pipeline Scikit-learn e o ColumnTransformer desde a limpeza de dados até as etapas de modelagem de dados para tornar seu código mais limpo.

Você também pode encontrar o melhor hiperparâmetro, método de preparação de dados e modelo de aprendizado de máquina com pesquisa em grade e a palavra-chave passthrough.

Você pode encontrar meu código neste GitHub