Daniel Tonetti
28/6/2022

Por que você deveria utilizar pipelines em todos os seus projetos de Data Science?



Data Science é a profissão mais sexy do século 21”, o famoso artigo da Harvard Business Review é de outubro de 2012. Passados quase 10 anos e a frase se mantém atual; talvez já não seja a “mais sexy”, mas o mercado de ciência de dados continua aquecido.

Nesse momento de crise de emprego, este oásis de oportunidades tem atraído muitos profissionais, sejam recém-formados ou realizando uma transição de carreira.

Aqui na Datarisk estamos constantemente entrevistando e contratando novos cientistas de dados e em uma das etapas do processo há um case técnico. Foi avaliando estes cases que decidi escrever este artigo, sobre a importância de utilizar a função de pipeline no momento de realizar transformações nos dados de treinamento e evitar o vazamento dos mesmos.

Alguns dos conceitos mais comuns em cursos e materiais para iniciantes em Data Science são:

  • A importância de reservar uma parte do seu conjunto de dados para validação;
  • Transformações nos dados;
  • Otimização de hiperparâmetros;
  • Cross-validation.

Neste artigo não irei aprofundar esses assuntos, porém julgo importante relembrar de forma geral estes conceitos antes de falarmos sobre o uso de pipelines e sua importância.

Por que reservar um conjunto de dados para validação do modelo?

Todo iniciante em Data Science já se deparou com a função train_test_split, cuja função é dividir a base em 2 conjuntos aleatórios, um que será utilizado para o treino do modelo e outro para validação.

Não é a única técnica de validação para modelos, mas certamente a mais comum. Independentemente da técnica o que quero ressaltar aqui é o conceito de validação:

Garantir que o modelo treinado apresente a performance esperada, mantendo valores similares nas métricas calculadas na amostra de treino em um cenário mais próximo o possível da aplicação do modelo em produção.

E isso implica que esses dados:

  • Sejam inéditos — tomar cuidados com o vazamento destes;
  • Respeitem a ordem predeterminada de tratamentos. Caso sejam aplicadas transformações nos dados, que elas sejam aplicadas na mesma ordem e de forma igual ao treinamento;
  • Tenham uma distribuição muito próxima dos dados de produção. Exemplo: em casos de modelos de classificação com target muito desbalanceadas (quando uma das classes é muito mais comum do que a outra) é comum o uso de técnicas de balanceamento nos dados de treinamento, para ajudar o modelo a aprender a reconhecer a classe minoritária. Porém, no momento de validar o modelo é crucial utilizar a distribuição original, desbalanceada, pois é este o cenário que seu modelo irá encontrar em produção.


Transformações nos dados

Dos tópicos listados é de longe o mais abrangente, mas de maneira geral é qualquer processo que altera o formato, a estrutura e/ou valores dos dados.

As transformações mais comuns são:

  • Preenchimento de missings;
  • Normalização: altera a escala das variáveis para o intervalo entre 0 e 1, ou -1 e 1, caso existam valores negativos;
  • Padronização: altera a escala das variáveis garantindo que a média seja 0 e o desvio padrão 1;
  • Tratar assimetria: altera a distribuição dos dados para aproximar a uma curva Gaussiana normal — raiz quadrada, log, log1p(), etc.

Otimização de hiperparâmetros

Hiperparâmetros são as variáveis do algoritmo definidas antes do treinamento. Para redes neurais podem ser o número de camadas, o valor da learning rate. Para modelos baseados em árvore podem ser a quantidade de árvores e a profundidade das mesmas. Cada modelo que se quer implementar deve-se procurar na documentação quais são os hiperparâmetros disponíveis.

Otimizar hiperparâmetros nada mais é do que utilizar algum método, mais ou menos extensivo, para testar diversos valores e encontrar aqueles que maximizam o desempenho do seu modelo de acordo com alguma métrica escolhida.

Cross-validation

É o segundo método de validação mais ensinado em cursos de Data Science. A ideia aqui é dividir os seus dados em um número K de grupos, normalmente um número no intervalo 5–10, e realizar K vezes os processos de treinamento e validação do modelo, onde em cada uma dessas vezes um conjunto é o de validação e os outros se juntam para ser o conjunto de treino.

A grande vantagem em relação ao método mais comum é que você terá mais medidas das métricas escolhidas para validar ao invés de apenas uma. Isso traz mais confiança nos seus resultados.

Hora da verdade — aplicando o que aprendemos

Ao iniciar um novo projeto, por exemplo um case de processo seletivo, é a hora de colocar em prática e juntar todos esses conceitos.

“Aí que mora o perigo
Aí que eu caio lindo…”

As armadilhas mais comuns estão relacionadas à aplicação de transformações nos dados e o processo de validação do modelo, principalmente quando se utilizam técnicas interativas no processo de treinamento, seja na etapa de otimização de hiperparâmetros como um grid search ou apenas na validação com cross-validation.

Nesse artigo vou utilizar como exemplo o processo de balanceamento da target, processo de transformação dos dados, em combinação com a técnica de grid search para mostrar os erros mais comuns e como solucionar.

Case — Detecção de fraude em transações de cartão de crédito

Para esse post selecionei uma base de dados bastante conhecida, que está disponível aqui. Esta base contém 284.807 registros de transações de crédito, onde apenas 492 são fraudulentas.

Nosso objetivo é construir um modelo que nos ajude a identificar possíveis fraudes e o grande desafio é que a base é extremamente desbalanceada. Para contornar este problema iremos aplicar uma técnica de balanceamento e buscar otimizar os hiperparâmetros do nosso modelo.

Definições:

  • Modelo de classificação binária;
  • Target desbalanceada;
  • Validação aleatória;
  • Algoritmo: Random Forest;
  • Otimização de hiperparâmetros: grid search;
  • Desbalanceamento: SMOTE — lib imblearn;

Exemplo 1 — Erro ao balancear target sem reservar uma amostra de validação:

O conceito mais importante dos quatro relembrados no começo deste texto é justamente a importância e o motivo de fazer uma boa validação. Então o erro mais grave no momento de tratar o desbalanceamento é alterar a proporção da target sem reservar uma amostra na proporção original para validação.

No código abaixo temos um exemplo desse erro, compare a proporção da target original com a da amostra de validação.

Exemplo 1— Erro.

Quando isso acontece, você até conseguirá medir o desempenho do seu modelo na sua amostra de validação, porém esses resultados não refletirão o cenário de uso e portanto não tem nenhuma utilidade.

No código abaixo temos um exemplo de como realizar a separação de uma amostra de validação corretamente, antes do balanceamento da target. Compare agora a proporção da target original com a de validação:

Exemplo 1— Correto.


Exemplo 2 —Erro ao realizar transformações na base antes de reservar uma amostra de validação:

Esse é um erro que não está relacionado ao desbalanceamento, porém acontece com frequência, e acarreta no vazamento de dados. Isto é, ao aplicar uma transformação, à StandardScaler, por exemplo, com todos os dados da base antes de dividi-la em treino e validação, adiciona-se uma camada de “relacionamento” entre esses dados. Assim, mesmo que de maneira indireta, a premissa de utilizar dados inéditos para validar o modelo fica comprometida.

No código abaixo temos um exemplo de quando isso acontece.

<script src="https://gist.github.com/dtonetti/224d464c2cbece8d473fed38b99f947f.js"></script>

Exemplo 2 — Erro.

No código abaixo temos um exemplo de como realizar a transformação corretamente: ajustar (.fit) o transformador apenas nos dados de treinamento e depois aplicar (.transform) a transformação nos dados de validação.

post_pipeline_exemplo2_correto.py
Exemplo 2 — Correto.

Um dos resultados esperados de se aplicar normalização (StandardScaler) é que a média da série (variável) se transforme em 0, para a distribuição que foi treinada, e no caso de novos dados fique próxima de 0.

Podemos observar que a média da variável Amount no treino do Exemplo 2 Erro é 0.0018, próxima mas não igual a 0. Isso ocorreu pois a aplicação da transformação foi incorreta. Já no Exemplo 2 está correto, temos o comportamento esperado.

Exemplo 3— Separar uma amostra de validação da maneira correta, porém tomar decisões em cima de uma base já balanceada:

Foram casos, repetidos como este, que motivaram a escrita deste post, pois há uma certa capciosidade envolvida. Geralmente o autor do código já está com o conceito de validação mais maduro e não comete os dois erros acima, porém acaba não enxergando este deslize.

No seguinte código, apenas repetimos os processos aplicados anteriormente, balanceamento da target e StandardScaler, já da forma correta.

post_pipeline_exemplo3_parte1.py

Até o ponto acima está, aparentemente, tudo correndo bem. O próximo passo é o treinamento do modelo, onde será utilizado um grid search para otimizar os hiperparâmetros.

post_pipeline_exemplo3_erro.py

No código acima, seu conjunto de dados X_train3_balanced será dividido em 5 folds, da mesma maneira que no exemplo apresentado sobre cross-validation — então 4 serão utilizados para treinamento do modelo e 1 para validação. Os parâmetros contidos no dicionário params serão testados em todas as combinações possíveis e a métrica escolhida para medir qual a melhor combinação será o AUC.

Acontece que ao dividir o conjunto de dados X_train3_balanced nos 5 folds, seus 4 folds de treinamento estão com a target balanceada, o que é correto, porém o fold restante que será utilizado para validar quais são os melhores parâmetros também está com a target balanceada. Então basicamente voltamos ao problema do Exemplo 1.

Não o bastante, também ocorre o vazamento de dados do Exemplo 2, pois a transformação foi aplicada no conjunto todo antes da divisão em 5 folds.

Utilizando a função pipeline para realizar todas as etapas de preparação da base de forma correta:

O pipeline é utilizado para encadear as várias etapas pelas quais os dados devem passar até o resultado final — predição do modelo. Isso é útil, pois geralmente há uma sequência fixa de etapas no processamento dos dados, no nosso exemplo, normalização (StandardScaler), balanceamento da target e por fim o treinamento do modelo.

As principais vantagens são:

  • Comodidade e encapsulamento:
    Você só precisa chamar .fit e .predict uma vez em seus dados;
  • Seleção de parâmetros conjuntos:
    Você pode otimizar hiperparâmetros de todos os passos do pipeline de uma só vez;
  • Segurança:
    Evitar o vazamento de dados na validação cruzada, garantindo que as mesmas amostras sejam usadas para treinar os transformadores e o modelo.

Todos os passos em um pipeline, exceto o último, devem ser transformadores (ou seja, devem ter um método de transformação). O último passo pode ser de qualquer tipo (transformador, classificador, etc.).

A biblioteca scikit-learn tem a função pipeline mais famosa do mundo de data science, porém para o nosso caso específico iremos utilizar a versão da biblioteca imblearn pois um dos passos do nosso fluxo é o balanceamento da target e ainda não há uma integração por parte da scikit-learn.

post_pipeline_exemplo4_correto.py

No código acima, seu conjunto de dados será dividido em 5 folds, 4 serão utilizados para treinamento (.fit) de todos os passos do pipeline e 1 para validação, diferente do exemplo anterior, onde as transformações ocorreram antes da divisão em 5 folds.

Além disso os parâmetros contidos no dicionário params serão testados em todas combinações possíveis e a métrica escolhida para medir qual a melhor combinação será o AUC. Sempre respeitando todas as boas práticas de validação nesse caso.

Espero que essas dicas sejam úteis e tenham gostado do artigo. Em caso de dúvida estou a disposição no LinkedIn.

Quer saber mais sobre Ciência de Dados ou como a Datarisk pode gerar valor para a sua empresa? Acesse nosso site e confira também nossos outros posts aqui no Medium.

Até a próxima!

Thanks to Everton Juliano da Silva, Felipe Sassi, and Alexandre Marcondes

Mais artigos da Datarisk

Ver todos os artigos
© Copyright 2017 - 2022 | Datarisk.io | Todos os direitos reservados