Como Consegui o 6º lugar Entre 985 Participantes na Competição de Machine Learning do Facebook

Nesta competição de recrutamento, o Facebook disponibilizou dados anônimos sobre usuários de um site de leilões. A tarefa era criar um modelo que determinasse qual usuário é humano e qual é robô. Os usuários humanos de um site de leilões não querem ter que competir com máquinas. Um site com muitos robôs pode sofrer um êxodo de usuários humanos, então é importante ter um sistema robusto de detecção de usuários suspeitos.

Segundo os administradores, estes dados não vinham do Facebook, mas acredito que o interesse era criar um ambiente parecido com o sistema de leilões de publicidade deles.

Esta competição tornou-se bastante especial para mim, já que foi meu primeiro Top 10 no Kaggle, e acabei me tornando Kaggle Master. Este era meu primeiro objetivo, mas também tem o bônus de ser considerado para uma entrevista para a vaga de Data Scientist no Facebook.

Dados

Uma das partes mais interessantes desta competição, e que a tornava bastante próxima de um caso real de ciência de dados, era o fato de não termos um arquivo bruto com variáveis relacionadas ao objetivo, que pudesse ser utilizado diretamente com algum modelo de machine learning.

Foram disponibilizados dois arquivos: o primeiro continha cerca de 2000 linhas com informações anônimas dos usuários, como ID e endereço. O segundo continha mais de 7 milhões de lances dados no site.

As variáveis do segundo arquivo incluíam: ID do lance, ID do usuário, ID do leilão, categoria do leilão, dispositivo do usuário, tempo, país, IP e URL. O tempo estava codificado, de maneira que não era possível descobrir a data exata dos lances.

Validação

Ter um ambiente de validação robusto é essencial para qualquer tarefa de machine learning. Neste caso havia o desafio de termos apenas 2000 exemplos para treinar e validar. Após testar várias combinações, decidi utilizar uma validação cruzada estratificada, com 5 divisões, e repetir essa validação por 5 vezes.

A repetição acaba fazendo com que os exemplos sejam colocados, aleatoriamente, em divisões diferentes, o que ajuda a estabilizar a estimativa de erro, já que um ou outro exemplo particular terá menor influência na média.

Criação de variáveis

A parte mais importante de qualquer trabalho de ciência de dados é garantir que você tenha os dados corretos para fazer a previsão. Um erro muito comum é achar que é só colocar os dados no algoritmo, e ele vai aprender o que você quiser. Esta foi, de longe, a parte mais importante da minha solução.

Contagens

O primeiro passo foi criar variáveis com a contagem de quantos lances cada usuário tinha feito. Estendendo esta ideia, criei variáveis para a contagem de quantos dispositivos, IPs, categorias, países e URLs diferentes um mesmo usuário tinha utilizado. Com estas variáveis simples, uma Random Forest, sem tuning, atingia 0,86 AUC na validação cruzada com 5 divisões.

No caso dos países, além de integrar a variável própria para contar o número de países diferentes, fiz variáveis individuais para cada um deles, contando quantos lances o usuário tinha dado vindos de cada país. Isto ajuda o modelo a identificar “países de risco”, onde pode ser mais fácil hospedar robôs para dar os lances.

Estatísticas simples

Depois de ver que as contagens possuíam um grande valor informativo, decidi testar estatísticas simples, como médias e desvios. Exemplos de variáveis importantes:

– Média e desvio padrão de lances por leilão;
– Número máximo de lances dados num mesmo leilão, com a mesma timestamp;
– Média de tempo entre lances.

Temporais

A variável que indicava o tempo nos dados originais estava codificada de maneira que não dava para saber a data exata em que os lances ocorreram. Mas, após analisar os dados, percebi que mesmo não sabendo a data exata, era possível identificar o que seriam dias, horas e minutos.

Isto me permitiu criar variáveis relativas a médias, desvios, proporções e contagens baseadas em unidades de tempo. Algumas variáveis importantes:

– Desvio padrão de lances por dia;
– Média de lances por dia;
– Média de lances na mesma timestamp;
– Contagem de lances por hora do dia;
– Média de leilões que o usuário participou no mesmo dia.

Parece que todos os participantes que se posicionaram no topo da tabela conseguiram identificar estes padrões temporais.

Proporções

Algumas proporções baseadas nas contagens e no tempo também foram importantes. Alguns exemplos são:

– Proporção máxima do total de lances em um dia atribuídos ao usuário;
– Densidade de lances por hora do dia

Modelos

Quando você tem variáveis que contêm bastante informação sobre o evento, a parte de seleção e ajuste de parâmetros do modelo se torna mais simples. Neste caso, apesar de testar brevemente modelos lineares, acabei optando por explorar melhor modelos baseados em ensembles de decision trees.

Random Forest

O primeiro modelo que testei, e o que se provou mais útil neste caso.

Acredito que sua performance superior se deu por ser um modelo mais voltado para a diminuição da variância. Por ter poucos dados para treinar, era importante que o modelo conseguisse lidar bem com valores extremos, e estabilizasse as previsões.

Uma Random Forest com 500 árvores e parâmetros ajustados através da validação cruzada apresentava 0,9112 AUC na medição local, e 0,9203 na LB.

Gradient Boosted Trees

Este é um dos modelos mais utilizados em competições de ciência de dados porque reconhecidamente oferece uma boa performance em diversos tipos de tarefas. Neste caso não foi assim. Os meus melhores modelos ficaram por volta dos 0,90-0,91 AUC na LB apesar de alcançarem a 0,94 na validação.

Isso levanta a seguinte questão: temos um modelo baseado em decision trees que nos dá uma boa performance (Random Forest) e, em tese, boosting melhoraria a pontuação, por que este não é o caso aqui?

A minha resposta é: Random Forest aumenta o bias, ou seja, torna o modelo mais rígido, com menor variância, enquanto o GBT aumenta a variância, sendo mais sensível ao ruído presente nos dados. Neste caso temos menos de 2000 exemplos, e um forte desequilíbrio entre as classes. Estas duas razões combinadas geram dados com uma boa quantidade de variância, aumentá-la ainda mais vai causar overfitting.

A solução seria fazer o tuning e regularizar mais o GBT, mas com poucos dados para validar fica difícil confiar nos resultados. Por isso, decidi confiar nas razões teóricas e continuar trabalhando com a Random Forest para ter um modelo mais estável.

Ensembles

O toque final de boa parte das melhores soluções de competições é fazer um ensemble com os melhores modelos.

Ensemble Aleatório

Devido ao pequeno número de exemplos, era difícil confiar nos parâmetros encontrados através da validação. Por isso, decidi criar um ensemble com Random Forests “aleatórias” nos parâmetros. Cada uma delas tinha uma seed e alguns parâmetros diferentes. Este ensemble atingiu uma AUC de 0,92 na estimativa out-of-bag e na LB.

AdaBoost Random Forest

Apesar da instabilidade do GBT, decidi aplicar boosting à Random Forest. Talvez aplicando este método em modelos mais estáveis que as decision trees pudesse ajudar, mesmo com a pequena quantidade de exemplos. E foi isso mesmo que aconteceu.

Na validação obtive 0,925 de AUC, e 0,928 na LB.

Ainda assim havia uma diferença entre a pontuação da validação e da LB quando eu adicionava novas variáveis.

Estabilizando as seeds

Para estabilizar as previsões decidi rodar o modelo de Boosted Random Forest usando várias seeds diferentes, e fazer a média. Isso não deu um bom resultado na LB, mas apresentava estabilidade na validação cruzada, o que me fez confiar no modelo.

Conclusão

No fim, utilizei um modelo de Boosted Random Forest com um conjunto de atributos que apresentava AUC 0,94 na validação cruzada, e foi basicamente minha pontuação no test set final da competição, que me garantiu o 6º lugar.

  1. Parabéns pelo resultado.

    Uma dúvida, vc falou de todo o tratamento que fez nos dados, mas não ficou claro para mim qual era a variável objetivo desse problema. Qual seria?

    Abs

    • Mario Filho

      Jorbisom,

      O objetivo era calcular a probabilidade de um usuário do site ser um robô ou um humano dependendo do comportamento dele nos leilões. Nos dados de treino havia uma variável com o número 1 para robôs, e 0 para humanos.

  2. Olá, primeiramente parabéns pela conquista.
    Conheci sua página a poucos dias e gostei demais do conteúdo. Show de bola.

    Obrigado por compartilhar sua experiência, com toda certeza é de grande valor pra nos jovens que sonham em conseguir chega perto do seu feito.

    Grande Abraço!

    Régis

Leave a Reply

Your email address will not be published. Required fields are marked *