Uma Pipeline de Machine Learning

Utilizando como exemplo a competição New York City Taxi Trip Duration, do Kaggle

Matheus Coradini
geleia
7 min readApr 7, 2020

--

Uma pipeline de Machine Learning pode ser definida como o conjunto de passos entre a definição de um problema e a escolha de um modelo preditivo, mas existem outras maneiras de definir. O que importa é que ter uma pipeline em mente torna o seu trabalho mais organizado e veloz no longo prazo. Neste exemplo vou me ater a uma competição do Kaggle que tem como objetivo fazer a regressão de durações de corridas de táxi em NY. Sabemos que os datasets do Kaggle não são muito fiéis aos da vida real, o que nos poupa de grande parte do trabalho de obtenção e limpeza dos dados, o que não é o objetivo desta leitura (em alguma próxima pode vir a ser).

Código completo: https://github.com/matheuscoradini/pipeline-de-machine-learning-taxi-NY

Pipeline:
1. Carregamento dos dados
2. Preparação dos dados e Estatística Descritiva
3. Visualização dos dados
4. Investigação de Outliers
5. Baseline
6. Feature E’ngineering
7. Feature Importance
8. Validar e tunar hiperparâmetros

1. Carregamento dos dados

A primeira etapa é importar as bibliotecas necessárias e realizar o carregamento dos dados, que estão separados em treino e teste:

O dicionário dos dados está descrito na página da competição: https://www.kaggle.com/c/nyc-taxi-trip-duration/data

2. Preparação dos dados e Estatística Descritiva

Na etapa de preparação dos dados ocorre uma primeira análise dos dados, onde realizamos a limpeza e transformações ideais para que seja possível começar a utilização desses dados. A estatística descritiva nos fornece um ponto de vista mais analítico sobre o dataset, e estas duas etapas estão muito interligadas, pois a a estatística descritiva muitas vezes nos fornece insights que auxiliam bastante no pré-processamento.

df.info()
df.isnull().sum()
Valores missing
df.describe()

Pode-se observar que o dataset possui quase 1,5 milhões de entradas e não tem valores missing. Para começar, transformei o pickup_datetime para o formato datetime e dropei as features id e dropoff_datetime do dataset de treino. A dropoff_datetime não está presente no dataset de teste, então não faz sentido a utilizar para o treinamento do modelo (e não teria a menor graça, pois com o horário de início e fim da corrida não precisamos de machine learning para calcular a duração).

No describe do dataset já é possível observar que existem viagens com 0 passageiros e com duração de 1 segundo, além possíveis outliers que serão investigados com maior atenção na visualização dos dados.

Retirei do dataset as corridas com 0 passageiros e as com menos de 20 segundos de duração:

3. Visualização dos dados

A visualização dos dados é um outro ponto de vista, que nos permite enxergar alguns comportamentos do dataset e suas features. Neste caso foram plotados a latitude e longitude de cada corrida, o histograma da duração das viagens e a relação das 3 variáveis categóricas com a target trip_duration. Em todos esses plots fica evidente a presença de outliers, existem coordenadas extremamente distantes das de NY e viagens com durações de milhões de segundos. O ideal agora é fazer o tratamento de outliers e visualizar novamente os dados depois. É importante lembrar que dropar os outliers não é sempre o melhor caminho, em muitos casos eles fazem parte do problema. Mas neste podemos claramente observar que surgiram de falhas na obtenção desses dados, como corridas de 0 passageiros ou de 1 segundo.

Jointplot das latitudes e longitudes do início da corrida e distplot da trip_duration, ambos da biblioteca Seaborn
Boxplots de passenger_count, vendor_id e store_and_fwd_flag

4. Tratamento de Outliers

A técnica utilizada para a remoção foi dropar os dados fora do intervalo de 3 desvios padrões ao redor da média.

Para o plot da imagem foi utilizado o mpimg, do matplotlib

Aqui podemos ver que agora o nosso dataset possui somente corridas dentro de NY. As de maior duração são as que tiveram início longe de Manhattan, centro comercial da cidade. Algumas corridas aparentemente começaram dentro do mar, mas dropar estes dados fica de dever de casa para quem for praticar com os dados dessa competição.

Na distribuição vemos que as corridas mais longas estão na faixa de 12000 segundos, aproximadamente 3 horas e meia. O que é bem plausível de ter acontecido em uma cidade como NY. E abaixo os violinplots já nos adiantam que não existe grande correlação entre as 3 features categóricas e a duração da viagem. Poderemos conferir isso nos próximos passos.

5. Baseline

A Baseline é o resultado de uma modelagem muito simples que serve de referência para os próximos modelos que forem testados. A ideia da Baseline é ser o limite inferior do que você busca para o projeto, ou seja: para um resultado ser considerado deve ser no mínimo melhor que a Baseline. Neste exemplo a Baseline é uma Random Forest com somente as features numéricas: vendor_id, passenger_count e as latitudes e longitudes.

Por fins de praticidade eu utilizei uma sample aleatória de 5% do dataset total, pois a partir deste momento são feitos alguns testes com os algoritmos de machine learning, e, como estamos lidando com um dataset de mais de 1 milhão de entradas os tempos de processamento seriam muito longos. Mas é claro que, se o objetivo fosse obter a melhor pontuação no Kaggle, o ideal seria trabalhar integralmente com todo o dataset. Não é o nosso caso.

A métrica utilizada foi o RMSE (root-mean-square deviation), mas isso fica a critério. Acredito que quanto mais métricas utilizadas na análise, melhor.

6. Feature Engineering

Aqui é onde grande parte da arte costuma acontecer, e a partir daqui é importante aplicar as transformações tanto no dataset de treino quanto no de teste. Transformei a feature pickup_datetime em uma série de outras features: horário, dia do mês, semana do ano, dia da semana, mês e dia do ano. As possibilidades são muitas, poderíamos considerar dias chuvosos, feriados, eventos importantes, etc. E a maioria desse tipo de dado pode ser encontrado em datasets upados por usuários no próprio Kaggle.

Outra observação importante é que, caso forem usados modelos que dependem de distância entre os pontos, seria recomendável normalizar os dados. Neste caso não é necessário pois os modelos validados são robustos nesse sentido por serem tree-based

O pacote geopy possui funções que calculam distância terrestre entre duas coordenadas, e um dos métodos é o geodesic. Com isso a feature distance foi criada:

Os algoritmos não se dão bem com dados no formato string, então por último foi utilizado o get_dummies na store_and_fwd_flag.

7. Correlação e Feature Importance

Esta etapa tem uma dupla importância. Além de nos permitir escolher as melhores features para usar no nosso modelo, nos faz compreender melhor nossos dados, suas correlações e como elas de fato afetam o algoritmo, o que é muito importante para apresentaçõe. Principalmente quando lidamos com pessoas que não são da área. Neste caso é interessante reparar a baixa correlação da pickup_time com a variável target, mas alta importância no algoritmo.

Heatmap das correlações

Foi utilizada a RandomForest, novamente, para calcular as feature importances.

O modelo melhorou ligeiramente utilizando as 10 features de maior importância(RMSE = 292.48) Mesmo não sendo uma diferença significativa, nos poupa tempo de processamento.

8. Hiperparametrização e escolha do modelo

Finalizando a Pipeline, nesta etapa podem ser testados quantos modelos forem de interesse com o objetivo de obter as melhores métricas, mas com atenção ao overfit.

Utilizei o Random Search para buscar os melhores parâmetros da Random Forest e do XGboost. Considerando somente uma métrica o XGBoosting performou melhor, e provavelmente seria escolhida para ser colocada em produção.

Random Forest:

XGBoost:

Dependendo da situação, o 9º passo pode ser o deploy, um submit no Kaggle ou uma publicação no Medium do Geleia.

Agradeço a atenção e espero ter contribuído! Até a próxima.

--

--