Usando Machine Learning para Descobrir Anúncios Ilegais Em Russo, Sem Saber Falar Russo

O site Avito.Ru, fundado em 2007, é um dos 5 maiores sites russos de classificados. Ele é utilizado tanto por pessoas físicas quanto empresas para negociar produtos novos e usados. Um dos maiores desafios é manter a qualidade do conteúdo diante do crescimento e do volume de novos anúncios. Para resolver isso, o site decidiu buscar uma solução baseada nos dados disponíveis.

Esta foi uma competição disponibilizada na plataforma Kaggle.

Para os leitores com conhecimento técnico, o código da solução final está disponível neste link (github).

Dados disponíveis

No banco de dados disponibilizado havia o conteúdo dos anúncios, atributos sobre os produtos anunciados, categoria e subcategoria, título e descrição. A variável que precisava ser prevista era binária, se o anúncio seria bloqueado ou não pela moderação. Cerca de 4 milhões de anúncios com as previsões dadas pela moderação humana foram disponibilizados para treino, e 1,5 milhão para teste.

Além disso havia uma variável indicando se aquele anúncio havia sido bloqueado por um moderador experiente, que poderia fazer a diferença no fator de erro humano.

Métrica de Avaliação

A métrica utilizada para avaliar a melhor solução era AvgPrecision@K (Top at K). Após atribuir uma pontuação que indicava a probabilidade de um determinado anúncio estar em desacordo com as regras, eles deveriam ser ordenados, de maneira que os mais prováveis estivessem mais acima no ranking. Feito isso, o sistema considerava os K primeiros anúncios e comparava com os valores reais para decidir qual a porcentagem de acerto do modelo.

Transformação dos dados

Minha solução envolveu apenas o título e a descrição dos anúncios. Primeiro o básico, colocar todas as palavras em caixa baixa, remover as stopwords, e fazer o stemming. Um detalhe é que os anúncios estavam em russo, então eu não sei exatamente se existem diferenças de caixa alta e baixa no idioma, ou quais stopwords são relevantes para outras palavras (no caso do inglês, “can” é uma stopword, mas pode ser relevante por também ser usada como “lata”).

De qualquer maneira, esses procedimentos melhoravam a performance do modelo.

Além disso, transformei os documentos numa matriz em que cada linha era um anúncio, e cada coluna, uma palavra. Nos valores testei três variações:

– Binária: na qual a presença da palavra no anúncio era indicada com o número 1;
– Contagem: cada valor era o número de vezes que a palavra aparecia no anúncio;
– Tf-Idf: cada valor era baseado em uma fórmula que leva em conta a frequência da palavra no anúncio, e também em relação aos outros anúncios. Ela atribui um valor maior a palavras raras no contexto geral, mas que tenham uma alta frequência dentro do anúncio específico.

Dentre estas alternativas, a que demonstrou melhor performance foi a Tf-Idf. Esta é uma técnica bastante usada em classificação de texto, e normalmente apresenta uma melhora na precisão da classificação.

Apesar de fazer algumas tentativas de limpeza dos dados, tirando as palavras mais raras, a performance era afetada negativamente. O que ajudou um pouco foi remover números.

Solução

Meu foco era criar uma solução simples, então meu primeiro teste foi com a Logistic Regression em todos os dados. Um dos fatores a se levar em conta era a distribuição de exemplos positivos e negativos, que não era 50%. Com esta solução a precisão era de 91,8%.

Após testar algumas opções disponíveis no scikit-learn (biblioteca de Machine Learning em Python que utilizei), descobri que usando a função loss “modified_huber” apresentava uma maior precisão. Esta é uma função mais robusta do que a log loss, pois aplica uma penalidade quadrática para pequenos erros, e linear para grandes.

Outra ideia que ajudou muito foi separar os anúncios por categoria. Cada categoria possuía uma proporção diferente de exemplos positivos e negativos (Algumas com menos de 1% e outras com mais de 30%). Aplicando o algoritmo acima nos dados transformados desta maneira obtive 97,3% de precisão. Uma melhora de 10,6%.

Para a solução final, treinei também uma modelo Naive Bayes que, apesar de assumir que as variáveis são independentes, possui uma boa performance para classificação de texto. Ao fazer a média da solução dos dois algoritmos, consegui a precisão final de 97,9%.

Diferenças para a solução vencedora

Comparando a minha solução com a solução da dupla vencedora, há uma pequena diferença de 0,8% de precisão. Mas quando olhamos a complexidade, a história é outra. A solução vencedora utilizou mais de 30 modelos, entre transformações e classificação, para cada exemplo do training set. Na prática, assim como acontece normalmente nestas competições, não valeria a pena implementar a solução vencedora. Mas isso não tira o crédito dos vencedores, e também a oportunidade de aprendizado.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *