Melhorando o Sistema de Busca de E-commerce da Home Depot com Machine Learning

Uma das tarefas mais importantes para um site de e-commerce é apresentar produtos relevantes para o usuário. Existem várias maneiras de se criar um sistema de busca de produtos, inclusive usando machine learning em alguma parte do processo. Uma delas é usar um modelo para determinar a relevância de um produto para um termo de busca.

A Home Depot é uma rede de lojas que comercializa itens para casa, como móveis, eletrodomésticos e equipamentos de manutenção. Além das lojas físicas, existe uma loja virtual onde os consumidores podem navegar pelos produtos e fazer compras.

Nesta competição a tarefa a ser solucionada era determinar qual a relevância dos resultados do mecanismo de busca do site desta empresa. Foram disponibilizados dados sobre a frase de busca e informações dos produtos retornados, além de uma pontuação, indicando a relevância daquele resultado.

A solução apresentada aqui é parte da que usei para garantir o 13º lugar, entre mais de 2000 times, na competição.

Quais Eram as Informações Disponíveis?

Foram disponibilizados pares de termos de busca e produtos retornados. Para a maioria dos produtos havia o título e a descrição, além de alguns atributos específicos como medidas, cor, material e textura.

Por fim, uma coluna determinava a relevância, que ia de 1 a 3, sendo 1 para produtos irrelevantes para a busca, e 3 para produtos bastante relevantes. Estas notas foram dadas por vários avaliadores humanos

Durante a criação dos dados, os avaliadores tinham fotografias dos produtos para ajudar a determinar a relevância, mas estas não foram disponibilizadas durante a competição.

As Diferenças Entre Dados de Treino e Teste

O treino e o teste continham termos de busca diferentes. Apenas 30% dos termos de busca do teste apareciam no treino. No fim da competição foi revelado que alguns exemplos dos dados de teste não eram utilizados para avaliar o resultado do modelo, mas apenas para evitar que competidores determinassem a relevância manualmente.

Alguns produtos também só apareciam em um dos dois conjuntos dos dados.

Num caso real esta divisão faz sentido, já que não queremos que o modelo seja bom apenas nas buscas que já conhecemos, mas também em novas buscas e produtos.

Como Isso Influenciou a Validação

Por causa da diferença citada acima, era importante criar um ambiente de validação que não tivesse dados sobre o mesmo termo de busca no treino e no teste.

Em vez de fazer uma validação aleatória comum, sorteei termos de busca, de maneira que fossem criadas 5 divisões, cada uma contendo todas as linhas para os termos de busca atribuídos a ela.

Isso foi fundamental para obter um bom resultado na competição, já que os resultados locais estavam bastante próximos dos resultados na validação do Kaggle (Public Leaderboard), o que me dava mais segurança sobre a capacidade de meu modelo generalizar para os dados privados.

Como as Soluções Eram Avaliadas

A métrica escolhida pelos patrocinadores foi o RMSE (raiz quadrada da média dos erros elevados ao quadrado). É uma métrica bem popular e basicamente aplica uma penalidade proporcional à diferença entre a previsão e a realidade.

Como Modelar Esta Tarefa

Num primeiro momento vi muita gente tentando criar modelos baseados em representações de “bag-of-words” dos dados. Esta representação consiste em criar uma matriz cujas linhas são os exemplos e as colunas são as palavras contidas nos exemplos. Em sua forma mais simples, se a palavra está no documento, o valor para a coluna, naquela linha é 1, caso contrário 0.

Mas esta tarefa requer um pensamento diferente. Na verdade o conteúdo até tinha poder preditivo, mas o mais importante não eram as palavras, e sim a relação entre o produto e termo de busca. E isso dificilmente é capturado da melhor maneira pela abordagem acima.

Pensando nisso, decidi me focar em criar variáveis que representassem a similaridade entre os produtos e os termos de busca correspondentes.

Limpando e Preparando o Texto Original

Um dos passos para o processamento de dados textuais é descobrir se a limpeza de algumas partes do texto pode ajudar o modelo a encontrar uma solução melhor.

Uma das sugestões dadas no fórum era substituir “medidas” expressas de maneiras diferentes por um termo comum. Um exemplo seria “m2” se tornar “metro quadrado”. Isso evita que algumas métricas de similaridade determinem que estes são conceitos diferentes, apesar de se referirem à mesma coisa.

Além disso, remover toda a pontuação e excluir palavras muito comuns, com pouco valor preditivo (como artigos), também ajudou a tornar o modelo melhor.

Stemming

Uma técnica bastante útil nestes casos, stemming significa retirar partes que flexionam uma palavra. Por exemplo, transformar a palavra “training” em “train”. Isso ajuda em algumas tarefas nas quais estas diferenças entre as palavras não influenciam, ou até acabam atrapalhando o modelo.

Neste caso, fazer o stemming sobre o texto ajudou as medidas de similaridade a capturar com maior precisão os valores corretos entre termos e produtos.

Correção Ortográfica

Como estamos tratando de texto gerado por usuários, podem acontecer erros de digitação, ou até mesmo diferenças de escrita em nomes de marcas mais complicadas de produtos.

Por isso, foi importante encontrar uma maneira de corrigir os possíveis erros ortográficos. Utilizei uma tabela disponibilizada nos fóruns, na qual um usuário usou o corretor ortográfico do Google para arrumar as frases de busca. Este foi um dos passos que mais ajudou a reduzir o erro do modelo.

N-gramas

N-gramas na análise de texto normalmente podem significar trechos de caracteres ou de palavras.

Nesta competição usei os dois tipos. Quando a unidade mínima é uma palavra, um unigrama pode ser “tinta” ou “azul”. Mas também é possível utilizar bigramas, trigramas, etc. Um bigrama seria “escada branca”, simplesmente uma string com duas palavras.

Quando a unidade mínima do n-grama é um caractere, o N se refere ao número de letras do trecho, sendo “abc” um trigrama.

Apesar de existirem similaridades que podem ser aplicadas diretamente a caracteres, como a Levenshtein, usar as similaridades descritas aqui com n-gramas de caracteres ajudou o modelo.

Similaridades Entre Termos de Busca e Produto

Uma das maneiras mais simples de se retornar resultados para um termo de busca é retornar os produtos com títulos e descrições mais similares às palavras buscadas. Normalmente este método já dá resultados bons, mas claro que existem detalhes que não são capturados por ele., e itens que possuem as mesmas palavras, mas são irrelevantes.

Além disso é preciso definir como será feita a comparação entre as palavras dos termos de busca e a descrição do produto. Para fazer isso existem algumas medidas bastante populares. Neste caso específico, utilizei o valor das medidas para um determinado par de busca e produto como variável no modelo.

Coeficiente de correspondência simples

Uma das variáveis mais poderosas, a correspondência simples é apenas a proporção de palavras de um campo que estão presentes no outro campo. Neste caso, um exemplo é o número de palavras do termo de busca que estão presentes no título do produto divido pelo número total de palavras do primeiro.

Como um exemplo simples: para um termo de busca “tinta azul para exterior” e um produto com título “galão de tinta para exterior – azul”, teríamos as 4 palavras do termo presentes no título, o que daria um coeficiente 4/4 = 1. Já um produto com título “galão de tinta para interior – amarela”, teria um coeficiente de 2/4 = 0,5.

Este coeficiente foi computado nas duas direções, verificando quais palavras do termo de busca estavam no título, e também qual a proporção de palavras do título no termo de busca.

Similaridade Cosseno

Esta similaridade também é bastante pupular e parece funcionar muito bem na prática. Primeiro é necessário transformar o texto original em uma matriz. A forma mais popular de fazer isso é considerar cada documento em uma linha da matriz, criando uma coluna para cada palavra e colocando um valor na célula correspondente à presença ou ausência daquela palavra no documento da linha.

Este valor pode ser um simples indicador binário da presença da palavra, ou também o número de vezes que a palavra aparece no documento. Mas uma maneira mais avançada, e a que utilizei nesta competição, é computar o coeficiente TF-IDF e usar como valor. Este coeficiente leva em conta a frequência da palavra no documento atual e também com relação aos outros documentos.

Após transformar os campos de texto originais em matrizes, normalizei os vetores para que cada um tivesse tamanho igual a 1, e computei o produto escalar entre eles. Como exemplo, computei o produto escalar entre o termo de busca e o título do produto para cada linha.

Similaridade Jaccard

Outra métrica de similaridade bastante interessante é a Jaccard. Originalmente ela é uma medida para conjuntos. No caso, para usá-la com texto, consideramos cada frase como um conjunto de palavras (ou n-gramas).

Para computar a métrica, basta dividir o número de elementos da intersecção entre os dois grupos pelo número de elementos da união dos mesmos. Por exemplo, se considerarmos o termo de busca “tinta azul para exterior” e o título “galão de tinta para exterior – azul” teremos uma intersecção de tamanho 4 e uma união de tamanho 6, então a similaridade Jaccard é igual a 0,667.

Existe uma versão bastante similar à Jaccard, chamada Similaridade Tanimoto, que pode ser computada diretamente sobre vetores de palavras, mas aqui usei a versão tradicional.

O Modelo Utilizado

O modelo que utilizei, sem surpresas, foi Gradient Boosted Trees, através da implementação do XGBoost.

Para tentar extrair valor do texto “bruto” tentei usar um SVM linear e Random Forests, mas nenhum deles foi capaz de me dar uma performance muito boa. Isso já era esperado, já que o conteúdo, apesar de importante, não é o foco da tarefa, e sim a similaridade entre campos diferentes.

Ideias Que Não Funcionaram

Em todo projeto de ciência de dados existem vários métodos a serem testados, mas boa parte deles acaba não sendo útil na tarefa específica. Apesar de machine learning ser uma área acadêmica de exatas, aplicar os modelos a dados reais envolve bastante tentativa e erro guiada, claro, por experiências anteriores. Por isso acho importante relatar algumas coisas que tentei mas não funcionaram.

Olhando os dados parecia que a correspondência entre as palavras finais de um termo de busca e título do produto era bastante preditiva quanto à relevância. Tentei criar várias variáveis baseadas nessa ideia, mas elas não funcionaram. Entendo que qualquer padrão relacionado a isso já era capturado pelas outras variáveis.

Outro método bastante comum em competições, o ensemble de vários modelos para melhorar a pontuação, não funcionou bem desta vez. Outros times também relataram que era mais produtivo juntar as variáveis de todos os integrantes e treinar um modelo, do que tentar criar um ensemble com os modelos de cada um.

Apesar do pequeno ganho, os times com as melhores colocações usaram ensembles com uma quantidade considerável de modelos.

Deixe uma resposta

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