Como usar o aprendizado de máquina no Compute Engine para fazer recomendações de produtos

Last reviewed 2016-02-26 UTC

Use o Google Cloud com o objetivo de criar um serviço eficaz, eficiente e escalonável para fornecer recomendações de produtos relevantes aos usuários em uma loja on-line.

A concorrência em sites de venda on-line nunca foi tão feroz quanto agora. Os clientes gastam mais dinheiro em todos os fornecedores, mas menos por varejista. O tamanho médio de um carrinho diminuiu, em parte devido ao fato de que a concorrência está a apenas um clique de distância. Oferecer recomendações relevantes para potenciais clientes pode desempenhar um papel central na conversão de visitantes em consumidores e no aumento do tamanho médio do pedido.

Depois de ler esta solução, configure um ambiente que suporte um mecanismo básico de recomendação, que pode ser ampliado e melhorado com base nas necessidades da sua carga de trabalho específica. A execução de um mecanismo de recomendação no Google Cloud oferece flexibilidade e escalabilidade nas soluções que você quiser executar.

Nesta solução, você verá como uma empresa de aluguel de imóveis pode calcular recomendações relevantes e apresentá-las aos clientes que estão navegando em um site.

Cenário

Samantha procurando uma casa para alugar nas férias. Ela tem um perfil em um site de aluguel para temporada e já alugou e avaliou vários pacotes de férias. Ela está procurando por recomendações com base nas próprias preferências e gostos. O sistema já precisa conhecer os gostos de Sam. Com base na página de avaliação dela, ela parece gostar de acomodações tipo house. O sistema precisa recomendar algo semelhante.

A interface do usuário ativa propriedades de aluguel para temporada

Visão geral da solução

Para fazer recomendações, seja em tempo real enquanto os clientes navegam ou por e-mails, várias coisas precisam acontecer. Primeiro, enquanto você souber pouco a respeito dos gostos e das preferências dos usuários, as recomendações serão baseadas apenas nos atributos dos itens. Mas o sistema precisa aprender com os usuários, coletando dados sobre os gostos e preferências deles. Com o tempo e dados suficientes,você pode usar algoritmos de aprendizado de máquina para fazer análises úteis e gerar recomendações significativas. As entradas de outros usuários também podem melhorar os resultados, permitindo que o sistema seja novamente treinado periodicamente. Nesta solução, é abordado um sistema de recomendações que já tem dados suficientes para aproveitar algoritmos de aprendizado de máquinas.

Um mecanismo de recomendação normalmente processa dados por meio das quatro fases a seguir:

Fases de coleta, armazenamento, análise e recomendação

A arquitetura de um sistema assim pode ser representada pelo seguinte diagrama:

Arquitetura com front-end, armazenamento e machine learning

Cada passo pode ser personalizado para atender aos requisitos. O sistema consiste em:

  1. Um front end escalonável que registra as interações do usuário para coletar dados.

  2. Armazenamento permanente que pode ser acessado por uma plataforma de aprendizagem de máquinas. A tarefa de carregar os dados para esse armazenamento pode incluir várias etapas, como importação-exportação e transformação dos dados.

  3. Uma plataforma de aprendizado de máquina que pode analisar o conteúdo existente para gerar recomendações relevantes.

  4. Armazenamento que pode ser usado pelo front-end, em tempo real ou posteriormente, com base nos requisitos de tempo para as recomendações.

Como escolher os componentes

Nesta solução, para alcançar um bom equilíbrio entre velocidade, simplicidade, controle de custos e precisão, usa-se o App Engine, Cloud SQL e o Apache Spark em execução. no App Engine usando o Dataproc.

O App Engine pode lidar com dezenas de milhares de consultas por segundo, sem grandes necessidades de gerenciamento. No App Engine, você pode escrever seu código e implantá-lo na produção em questão de segundos, seja criando o site ou salvando os dados em um armazenamento de back-end.

No Cloud SQL, a implantação também é simples. O Cloud SQL pode escalar máquinas virtuais de até 32 núcleos com até 208 GB de RAM, e pode aumentar o armazenamento sob demanda para 10 TB com 30 IOPS por GB e milhares de conexões simultâneas. Essas especificações são mais do que o suficiente para o exemplo desta solução e para um grande número de mecanismos de recomendação no mundo real. Há também a vantagem de que o Cloud SQL pode ser acessado diretamente por meio do Spark.

O desempenho do Spark é muito melhor do que o de uma configuração Hadoop típica. O Spark pode ser de dez a cem vezes mais rápido. Com o Spark MLlib, é possível analisar centenas de milhões de avaliações em minutos, o que aumenta a agilidade das recomendações e faz com que o administrador possa executar o algoritmo com mais frequência. A memória é aproveitada o máximo possível na computação reduzindo as idas e voltas ao disco. Essa solução tenta minimizar a E/S E usa o Compute Engine para hospedar a infraestrutura de análise. O preço por minuto e sob demanda do Compute Engine ajuda a manter o preço da análise o mais baixo possível.

No diagrama a seguir, mapeia-se o diagrama de arquitetura anterior, mas com a exibição da tecnologia usada em cada passo:

A arquitetura usa o App Engine, o Cloud SQL, o Spark e o Compute Engine

Como coletar os dados

Um mecanismo de recomendação pode coletar dados sobre os usuários com base no comportamento implícito ou na entrada explícita deles.

Os dados de comportamento são fáceis de coletar porque é possível manter registros das atividades do usuário. A coleta desses dados também é direta porque não exige qualquer ação adicional do usuário. Ele já está usando o aplicativo. A desvantagem dessa abordagem é que é mais difícil analisar. Por exemplo, filtrar os registros interessantes dos menos interessantes pode ser complicado.

Os dados de entrada podem ser mais difíceis de coletar porque os usuários precisam fazer outras ações, como escrever uma avaliação. Talvez os usuários não queiram fornecer esses dados por diversos motivos. Mas, quando se trata de compreender as preferências do usuário, esses resultados são bastante precisos.

Como armazenar os dados

Quanto mais dados puderem ser acessados pelos algoritmos, melhores serão as recomendações. Isso significa que qualquer projeto de recomendações pode se transformar rapidamente em um projeto de Big Data.

O tipo de dados usado para criar recomendações pode ajudar você a decidir o tipo de armazenamento a ser usado. Pode-se escolher entre um banco de dados NoSQL, um banco de dados SQL padrão ou até algum tipo de armazenamento de objetos. Cada uma dessas opções é viável se você estiver capturando a entrada ou o comportamento do usuário e depende de fatores como a facilidade de implementação, a quantidade de dados que o armazenamento pode gerenciar, a integração com o resto do ambiente e a portabilidade.

Ao salvar avaliações ou eventos do usuário, um banco de dados escalonável e gerenciado minimiza a quantidade de tarefas operacionais necessárias e ajuda a se concentrar na recomendação. Com o Cloud SQL, as duas necessidades são atendidas e também é mais fácil carregar os dados diretamente do Spark.

No código de exemplo a seguir, pode-se ver os esquemas das tabelas do Cloud SQL. A tabela Accommodation representa a propriedade para aluguel e a tabela Rating representa a avaliação de um usuário para uma propriedade específica.

CREATE TABLE Accommodation
(
  id varchar(255),
  title varchar(255),
  location varchar(255),
  price int,
  rooms int,
  rating float,
  type varchar(255),
  PRIMARY KEY (ID)
);

CREATE TABLE Rating
(
  userId varchar(255),
  accoId varchar(255),
  rating int,
  PRIMARY KEY(accoId, userId),
  FOREIGN KEY (accoId)
    REFERENCES Accommodation(id)
);

O Spark pode receber dados de várias fontes, como o Hadoop HDFS ou o Cloud Storage. Esta solução recebe os dados diretamente do Cloud SQL usando o conector Java Database Connectivity (JDBC) do Spark. Como os trabalhos Spark são executados em paralelo, o conector precisa estar disponível em todas as instâncias do cluster.

Como analisar os dados

Projetar a fase de análise requer uma compreensão dos requisitos do aplicativo. Esses requisitos incluem:

  • O tempo de uma recomendação. As recomendações precisam ser apresentadas pelo aplicativo com que velocidade?

  • A abordagem de filtro para os dados. Apenas os gostos do usuário serão usados como base para as recomendações, ou os dados serão colocados em tabela dinâmica com base no que outros usuários pensam ou em quais produtos se encaixam de maneira lógica?

Como entender o tempo

O primeiro fator a se considerar na análise dos dados é a rapidez com que é preciso apresentar as recomendações ao usuário. Para apresentar as recomendações imediatamente, como no momento em que o usuário visualiza um produto, é necessário fazer uma análise mais rápida do que ao enviar um e-mail contendo recomendações mais tarde, por exemplo.

  • Nos sistemas em tempo real, pode-se processar os dados à medida em que eles são criados. Esse tipo de sistema geralmente envolve ferramentas capazes de processar e analisar fluxos de eventos. Um sistema em tempo real seria necessário para dar recomendações no momento.

  • A análise em lote exige o processamento periódico dos dados. Nessa abordagem, a implicação é de que é preciso criar dados suficientes para que a análise possa ser relevante, como no caso do volume de vendas diário. O sistema em lote pode ser bom para enviar e-mails posteriormente.

  • Na análise quase em tempo real, é possível coletar dados rapidamente para atualizar a análise a cada poucos minutos ou segundos. O sistema quase em tempo real pode ser bom para oferecer recomendações durante a mesma sessão de navegação.

Uma recomendação pode entrar em qualquer uma dessas três categorias de tempo. Mas, para uma ferramenta de vendas on-line, pode-se usar algo entre o processamento quase em tempo real e o processamento em lote, dependendo da quantidade de tráfego e de entradas do usuário que o aplicativo receber. A plataforma que executa a análise pode funcionar diretamente do banco de dados em que os dados são salvos, ou em um despejo salvo periodicamente em armazenamento persistente.

Como filtrar os dados

Um componente central da criação de um mecanismo de recomendação é o filtro. As abordagens mais comuns incluem:

  • Com base no conteúdo: um produto conhecido e recomendado tem atributos parecidos com aquilo que o usuário visualiza ou que mais gosta.

  • Cluster: os produtos recomendados combinam um com o outro, não importa o que outros usuários tenham feito.

  • Colaborativo: outros usuários, que gostam dos mesmos produtos que o usuário visualizou ou gostou, também gostaram de um produto recomendado.

O Google Cloud é compatível com qualquer uma dessas abordagens. No entanto, nesta solução, o foco está na filtragem colaborativa, que é implementada usando o Apache Spark. Para mais informações sobre o filtro baseado em conteúdo ou o filtro de cluster, consulte o apêndice.

Com o filtro colaborativo, você pode abstrair os atributos de produtos e fazer previsões com base nos gostos dos usuários. A saída desse filtro baseia-se no pressuposto de que dois usuários diferentes que gostaram dos mesmos produtos no passado provavelmente gostariam dos mesmos produtos agora.

Pode-se representar os dados a respeito de avaliações ou interações como um conjunto de matrizes, com produtos e usuários como dimensões. No filtro colaborativo, a tentativa é de prever as células faltantes para um par usuário-produto específico em uma matriz. As duas matrizes seguintes são semelhantes, mas a segunda é deduzida da primeira com a substituição das classificações existentes pelo número 1 e das classificações faltantes pelo número 0. A matriz resultante é uma tabela em que o número um representa uma interação com um produto feita por usuários.

Matriz de avaliação Matriz de interação
Matriz de avaliação Matriz de avaliação

Há duas abordagens distintas para empregar o filtro colaborativo:

  • O filtro com base na memória calcula as semelhanças entre produtos ou usuários.

  • O filtro com base no modelo tenta aprender o padrão oculto que dita como os usuários avaliam ou interagem com os itens.

Nesta solução, é usada a abordagem com base no modelo, em que os usuários classificaram itens.

Todos os recursos de análise exigidos por essa solução estão disponíveis no PySpark, que fornece uma interface Python para a linguagem de programação Spark. Outras opções estão disponíveis usando Scala ou Java. Consulte a documentação do Spark.

Como treinar os modelos

O algoritmo ALS ("Alternating Least Squares") é implementado pelo Spark MLlib para treinar os modelos. Use várias combinações dos seguintes parâmetros para alcançar o melhor equilíbrio entre variância e compensação:

  • Classificação: o número de fatores desconhecidos que levou um usuário a dar uma avaliação. Estes podem incluir fatores como idade, gênero ou local. Quanto maior a classificação, melhor será a recomendação, até certo ponto. Uma boa abordagem é iniciar em cinco e aumentar em cinco até que a taxa de melhoria da recomendação fique mais lenta, conforme a memória e a CPU permitirem.

  • Lambda: um parâmetro de regularização para evitar sobreajuste, representado por alta variância e baixo viés. A variância representa o quanto as previsões flutuam em determinado ponto, ao longo de várias execuções, em comparação com o valor teoricamente correto para aquele ponto. O viés representa a distância entre as previsões geradas e o valor verdadeiro que se está tentando prever. O sobreajuste acontece quando o modelo funciona bem para treinar dados usando ruídos conhecidos, mas não tem um bom desempenho com os dados de teste reais. Quanto mais alto o lambda, mais baixo o sobreajuste, mas maior o viés. 0,01, 1 e 10 são bons valores para testar.

    A relação entre variância e compensação está demonstrada no diagrama a seguir. O alvo representa o valor que o algoritmo está tentando prever.

    Variância versus viés (o melhor está no canto superior esquerdo)
    Variância e viés
  • Iteração: o número de vezes em que o treinamento será executado. Neste exemplo, serão feitas 5, 10 e 20 iterações para várias combinações de classificação e lambda.

No código de exemplo a seguir, há uma demonstração de como iniciar um modelo de treinamento ALS em Spark.

from pyspark.mllib.recommendation import ALS
model = ALS.train(training, rank = 10, iterations = 5, lambda_=0.01)

Como encontrar o modelo certo

O filtro colaborativo que usa o algoritmo ALS é baseado em três conjuntos de dados diferentes:

  • Conjunto de treinamento: contém dados com saída conhecida. Este conjunto representa um resultado perfeito. Nesta solução, ele contém as avaliações dos usuários.

  • Conjunto de validação: contém dados que ajudarão a ajustar o treinamento para escolher a combinação certa de parâmetros e o melhor modelo.

  • Conjunto de testes: contém dados utilizados para avaliar o desempenho do modelo mais bem treinado. Seria o equivalente a executar a análise em um exemplo do mundo real.

Para encontrar o melhor modelo, calcule a raiz do erro médio quadrático (RMSE na sigla em inglês) com base no modelo que foi calculado, no conjunto de validação e no tamanho dele. Quanto menor o RMSE, melhor o modelo.

Como exibir as recomendações

Para disponibilizar os resultados para o usuário de maneira rápida e fácil, carregue-os em um banco de dados que possa ser consultado sob demanda. Novamente, o Cloud SQL é uma ótima opção para esse caso. Grave os resultados da previsão diretamente no banco de dados usando o PySpark a partir do Spark 1.4.

O esquema da tabela Recommendation tem esta aparência:

CREATE TABLE Recommendation
(
  userId varchar(255),
  accoId varchar(255),
  prediction float,
  PRIMARY KEY(userId, accoId),
  FOREIGN KEY (accoId)
    REFERENCES Accommodation(id)
);

Instruções do código

Nesta seção, oferecemos instruções sobre código para treinar os modelos.

Coletar os dados do Cloud SQL

Com o contexto do Spark SQL, é fácil se conectar com uma instância do Cloud SQL por meio do conector JDBC. Os dados carregados estão no formato DataFrame.

jdbcUrl    = 'jdbc:mysql://%s:3306/%s?user=%s&password=%s' % (CLOUDSQL_INSTANCE_IP, CLOUDSQL_DB_NAME, CLOUDSQL_USER, CLOUDSQL_PWD)
dfAccos = sqlContext.read.jdbc(url=jdbcUrl, table=TABLE_ITEMS)
dfRates = sqlContext.read.jdbc(url=jdbcUrl, table=TABLE_RATINGS)

Converta o DataFrame em RDD e crie os diversos conjuntos de dados

No Spark, é usado um conceito chamado Resilient Distributed Dataset (RDD), que facilita o trabalho com elementos em paralelo. Os RDDs são coleções somente de leitura criadas a partir do armazenamento persistente. Podem ser processados na memória, sendo adequados para o processamento iterativo.

Lembre-se de que, para ter o melhor modelo para suas previsões, você precisa dividir os conjuntos de dados em três conjuntos diferentes. No código a seguir, usa-se uma função auxiliar que divide aleatoriamente valores não sobrepostos em uma base de porcentagem 60/20/20:

rddTraining, rddValidating, rddTesting = dfRates.rdd.randomSplit([6,2,2])

Treinar modelos com base em vários parâmetros

Lembre-se de que, ao usar o método ALS, o sistema precisa trabalhar com os parâmetros de classificação, regularização e iteração para encontrar o melhor modelo. As classificações existem. Portanto, os resultados da função train precisam ser comparados ao conjunto de validação. Os gostos do usuário também precisam estar no conjunto de treinamento.

for cRank, cRegul, cIter in itertools.product(ranks, reguls, iters):

  model = ALS.train(rddTraining, cRank, cIter, float(cRegul))
  dist = howFarAreWe(model, rddValidating, nbValidating)
  if dist < finalDist:
    print("Best so far:%f" % dist)
    finalModel = model
    finalRank  = cRank
    finalRegul = cRegul
    finalIter  = cIter
    finalDist  = dist
def howFarAreWe(model, against, sizeAgainst):
  # Ignore the rating column
  againstNoRatings = against.map(lambda x: (int(x[0]), int(x[1])) )

  # Keep the rating to compare against
  againstWiRatings = against.map(lambda x: ((int(x[0]),int(x[1])), int(x[2])) )

  # Make a prediction and map it for later comparison
  # The map has to be ((user,product), rating) not ((product,user), rating)
  predictions = model.predictAll(againstNoRatings).map(lambda p: ( (p[0],p[1]), p[2]) )

  # Returns the pairs (prediction, rating)
  predictionsAndRatings = predictions.join(againstWiRatings).values()

  # Returns the variance
  return sqrt(predictionsAndRatings.map(lambda s: (s[0] - s[1]) ** 2).reduce(add) / float(sizeAgainst))

Como calcular as principais previsões para o usuário

Agora, com um modelo que pode gerar uma previsão razoável, use-o para ver no que o usuário provavelmente estará mais interessado com base nos gostos dele e nas avaliações feitas por outros com gostos parecidos. Neste passo, você pode ver o mapeamento de matriz descrito anteriormente.

# Build our model with the best found values
# Rating, Rank, Iteration, Regulation
model = ALS.train(rddTraining, BEST_RANK, BEST_ITERATION, BEST_REGULATION)

# Calculate all predictions
predictions = model.predictAll(pairsPotential).map(lambda p: (str(p[0]), str(p[1]), float(p[2])))

# Take the top 5 ones
topPredictions = predictions.takeOrdered(5, key=lambda x: -x[2])
print(topPredictions)

schema = StructType([StructField("userId", StringType(), True), StructField("accoId", StringType(), True), StructField("prediction", FloatType(), True)])

dfToSave = sqlContext.createDataFrame(topPredictions, schema)
dfToSave.write.jdbc(url=jdbcUrl, table=TABLE_RECOMMENDATIONS, mode='overwrite')

Como salvar as principais previsões

Agora, com uma lista de previsões, salve as dez melhores no Cloud SQL para que o sistema possa oferecer algumas recomendações ao usuário. Por exemplo, uma boa hora para usar essas previsões seria quando o usuário fizer o login no site.

dfToSave = sqlContext.createDataFrame(topPredictions, schema)
dfToSave.write.jdbc(url=jdbcUrl, table=TABLE_RECOMMENDATIONS, mode='overwrite')

Como executar a solução

Para executar essa solução, siga as instruções passo a passo na página do GitHub. Ao seguir as instruções, você poderá calcular e exibir recomendações para o usuário.

O código SQL final busca a principal recomendação do banco de dados e a exibe na página de boas-vindas de Sam.

A consulta, quando executada no console do Google Cloud ou em um cliente MySQL, retorna um resultado semelhante ao exemplo a seguir:

Resultados da consulta SQL para cinco usuários

No site, a mesma consulta pode melhorar a página de boas-vindas e aumentar a probabilidade de conversão de um visitante em um cliente:

Interface de usuário com resultados

Isso parece ser bastante semelhante ao que a Sam gosta com base no que o sistema já sabia sobre ela, conforme discutido na descrição do cenário.

Tutorial

O conteúdo completo do tutorial, incluindo instruções de configuração e o código-fonte estão no GitHub.

Custos

Neste tutorial, usamos o seguinte componente faturável do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços.

Próximas etapas

Apêndice

Cruzamento de filtros

Agora que você já viu como criar uma solução de filtro colaborativo eficaz e escalonável, cruzar os resultados com outros tipos de filtros pode melhorar a recomendação. Lembre-se dos outros dois tipos principais de filtros: com base no conteúdo e em cluster. Uma combinação dessas abordagens pode produzir uma recomendação melhor para o usuário.

Tipos de filtros

Filtro com base no conteúdo

O filtro com base no conteúdo trabalha diretamente com os atributos dos itens e entende as semelhanças entre eles, o que facilita a criação de recomendações para itens que têm atributos, porém poucas avaliações de usuários. Conforme a base de usuários cresce, esse filtro se mantém gerenciável, mesmo com um grande número de usuários.

Para adicionar o filtro com base no conteúdo, use as avaliações anteriores de outros usuários para os itens do catálogo. Com base nessas avaliações, é possível encontrar os produtos mais parecidos com o atual.

A maneira comum de calcular a semelhança entre dois produtos é usar a similaridade de cossenos e encontrar os vizinhos mais próximos:

Fórmula da similaridade de cossenos

Diagrama da similaridade de cossenos

O resultado da similaridade estará entre 0 e 1. Quanto mais perto do um ele estiver, mais parecidos os produtos são.

Espectro da similaridade de cossenos

Pense na seguinte matriz:

Fórmula da similaridade de cossenos

Nessa matriz, a similaridade entre P1 e P2 pode ser calculada da seguinte maneira:

Fórmula da similaridade de cossenos com resultado

Pode-se conseguir um filtro com base no conteúdo usando várias ferramentas. Para saber mais, confira:

  • Similaridade para todos os pares do Twitter. É possível executar a função Scala CosineSimilarities adicionada ao MLlib no ambiente do Spark.

  • Mahout. Se quiser acessar mais bibliotecas para complementar ou substituir algum algoritmo MLlib, instale o Mahout no nó do controlador do Dataproc (mestre) usando ssh para se conectar à instância ou usando uma ação de inicialização:

    sudo apt-get update
    sudo apt-get install mahout -y
    

Cluster

Também é importante entender o contexto de navegação e o que o usuário está vendo no momento. A mesma pessoa navegando em momentos diferentes pode estar interessada em dois produtos completamente diferentes, ou até comprando um presente para outra pessoa. É essencial entender quais itens são semelhantes ao que está sendo exibido no momento. Usar o cluster K-mean possibilita que o sistema coloque itens parecidos em buckets, com base nos atributos principais deles.

Para essa solução, uma pessoa que procura uma casa para alugar em São Paulo, por exemplo, não está interessada em alugar algo em Lisboa. Portanto, o sistema precisa filtrar esses casos ao fazer uma recomendação.

from pyspark.mllib.clustering import KMeans, KMeansModel
clusters = KMeans.train(parsedData, 2,
                        maxIterations=10,
                        runs=10,
                        initializationMode="random")

Visualização em 360 graus

Melhore ainda mais a recomendação levando em conta os dados de outros clientes, como pedidos anteriores, suporte e atributos pessoais, como idade, local ou gênero. Esses atributos, que geralmente já estão disponíveis em um sistema de gestão do relacionamento com o cliente ou de gestão empresarial, ajudarão a reduzir as opções.

Pensando adiante, não apenas os dados internos do sistema têm impacto sobre as escolhas e o comportamento do usuário. Os fatores externos também importam. No caso de uso dessa solução de aluguel para temporada, saber a qualidade do ar pode ser importante para uma família de jovens. Portanto, integrar um mecanismo de recomendação criado no Google Cloud com outra API, como o Breezometer, trará uma vantagem competitiva.