Alura > Cursos de Data Science > Cursos de Machine Learning > Conteúdos de Machine Learning > Primeiras aulas do curso Machine Learning: intro a sistemas de recomendação em Python

Machine Learning: intro a sistemas de recomendação em Python

Heurísticas de recomendação - Introdução

Bem vindo ao nosso curso de introdução a sistemas de recomendação utilizando Machine Learning. Temos dois objetivos nesse curso: o primeiro é entender o que é um sistema de recomendação e utilizá-lo para gerar recomendações em um conjunto de dados de filmes, no caso as avaliações dos filmes do site MovieLens, que usaremos para gerar um sistema de recomendações para os usuários; e o segundo é entender que somos capazes de implementar algoritmos de machine learning por trás dos panos.

Aqui, iremos implementar uma variação do k-NN, que significa k-nearest neighbors, ou "os k vizinhos mais próximos" de um usuário que assistiu filmes. Iremos implementar esse algoritmo do zero por baixo dos panos em um notebook Python à medida em que vamos trabalhando com os conjuntos de dados e gerando recomendações baseadas neles.

O pré-requisito para esse curso é conhecer o Python, o Pandas e ter um conhecimento introdutório de machine learning e problemas de classificação. Nesse módulo não utilizaremos classificação em si, mas entender o que é um problema de machine learning e como resolvê-lo é a base do trabalho que faremos aqui, que envolverá bastante Pandas, um pouco de Numpy e algumas visualizações.

Tendo esses requisitos, você será capaz de aprender a implementar esse algoritmo por trás dos panos e ganhar confiança para estudar outros algoritmos quando achar interessante para a sua carreira. Como iremos implementar tudo isso manualmente, se você quiser, depois do curso, poderá utilizar bibliotecas que já implementam esses algoritmos, como o Surprise no Python.

Vamos lá?

Heurísticas de recomendação - Heurística de recomendação e entendendo o que é colaboração

Vamos começar o nosso projeto? O conjunto de dados que utilizaremos é o do Movielens, um site pertencente ao Grouplens que tem um sistema de avaliação de vários filmes - ou seja, as pessoas podem dar notas de alguma maneira e encontrar outros filmes que lhes interessam, tudo muito ligado à questão de recomendação.

No Movielens, é possível baixar um conjunto de dados enorme contendo 20 milhões de avaliações dos usuários, ou outras duas variações desse conjunto, contendo 27 milhões ou 100 mil avaliações. Usaremos essa última, que é uma versão menor e mais simples. Claro, no momento que você tiver um algoritmo que julga ser bom, poderá baixar o arquivo com o conjunto completo de dados e rodar o algoritmo para ele.

Após baixarmos e descompactarmos o .ZIP disponibilizado no site, teremos dois arquivos que nos interessam: movies.csv, que são as informações gerais do filme; e ratings.csv, que são diversas avaliações.

Como plataforma, utilizaremos o Google Colaboratory, mas você pode utilizar um notebook Python local, no Kaggle ou onde quiser. Criaremos um Python 3 notebook, que renomearemos como "Introdução a Recomendação". Clicando em "Files" no lado esquerdo, o notebook irá se conectar com uma máquina virtual do Python e subiremos os arquivos, começando com movies.csv. Enquanto ele sobe, o Colab mostrará um aviso de que quando fecharmos a conexão, perderemos o espaço virtual e também esse arquivo, mas não tem problema.

Quando o arquivo terminar de subir, ele será listado no menu à esquerda. Poderemos então utilizar o pandas para ler esse arquivo, chamando pd.read_csv("movies.csv"). Atribuiremos essa leitura a uma variável filmes, e faremos filmes.head() para listarmos os 5 primeiros elementos.

Teremos os cinco primeiros filmes desse conjunto de dados, com os movieIds, os titles e os genres desses filmes. Queremos trabalhar com as colunas em português, portanto iremos sobrescrever as três colunas (ignorando o índice) com filmeId, título e gêneros.

Voltando ao menu "files", subiremos também o arquivo ratings.csv, que tem 800mb e contém as avaliações. Carregaremos as notas com pd.read_csv("ratings.csv"), chamaremos esse conjunto de notas e imprimiremos os cinco primeiros elementos para visualizá-los.

Renomearemos as colunas para usuarioId (quem deu a avaliação), filmeId (o filme que foi avaliado), nota (a avaliação) e momento (quando a avaliação foi feita). Podemos utilizar outras funções para descrever e entender melhor esse conjunto de dados. Por exemplo, com o Pandas, podemos fazer notas.describe(), verificando que as notas vão de um mínimo 0,5 até o máximo 5; que a mediana é 3,5; temos 492 mil avaliações; entre outras informações.

A grande questão agora é: queremos recomendar algo, mas como fazer isso? Temos vários filmes e várias notas que as pessoas deram para eles. Nesse cenário, que filme recomendar?

Na nossa primeira tentativa de recomendação, vamos analisar as notas, que representam votos que pessoas que assistiram aos filmes deram na plataforma. Vamos acreditar que essas notas são uma representação razoavelmente justa do mundo real, que é o nosso objeto de análise, apesar disso ser discutível.

Com base nesses dados, verificaremos que existem filmes que foram assistidos por muitas pessoas, e outros que foram assistidos por poucas pessoas. Vamos pensar, então, em um cenário bem genérico, no qual não sabemos nada sobre o usuário do sistema. Nessa situação, como iremos recomendar um filme ao usuário?

Bom, sabemos muito sobre os filmes! Sabemos que temos uma amostra das notas desses filmes, e podemos analisar, por exemplo, quantas pessoas deram nota para o filme Jumanji, para Toy Story ou para O Pai da Noiva Parte 2. Se assumirmos que há uma representatividade desses dados para a vida real, "saberemos" o quão populares esses filmes são.

Podemos, então, pegar todas essas notas (que foram fornecidas por outros usuários do sistema) e agrupá-las pelo campo filme. Veremos, então, que a primeira nota foi para o filme 307, a segunda para o 481, depois 1091, e assim por diante. Agora, com value_counts(), contaremos quantas vezes cada filme apareceu - ou seja, a frequência.

Com isso, teremos que, nesse conjunto de dados, o filme 318 foi avaliado 1739 vezes; o filme 352, 1698 vezes; o filme 296, 1628 vezes; e assim por diante. Se assumirmos essas avaliações como medida de popularidade, podemos recomendar o filme 318 para um usuário sobre o qual não temos nenhuma informação, apenas com base na colaboração de diversos outros usuários.

Agora vamos descobrir que filme é o 318. Antes disso, para facilitarmos nossa busca, setaremos o index como o próprio filmeId. Para isso, faremos filmes = filmes.set_index("filmeId"). Com filmes.loc[318], iremos localizar esse elemento pelo seu índice. Como retorno, teremos o filme The Shawshank Redemption.

Se procurarmos por esse nome no IMDB, veremos que o filme é muito bem avaliado e muitíssimo popular, estando no top 100 filmes da história do site. Portanto, parece razoável recomendarmos o filme mais popular (no nosso caso, o mais votado). Na prática, queremos ordenar pelos filmes mais votados e recomendar os primeiros - afinal, podemos concluir que muitas pessoas têm interesse neles. Claro, estamos tirando uma heurística para definir um padrão de recomendação, sem provas do que estamos concluindo.

Nesse cenário, no qual não temos informações sobre nosso usuário, utilizar o critério do mais popular (que é uma informação colaborativa) parece funcionar. Se soubéssemos que o usuário é brasileiro, poderíamos filtrar apenas filmes brasileiros. É isso, por exemplo, que o Youtube tenta fazer: se um usuário usa um navegador em português no Brasil para acessar o Youtube, ele infere que esse usuário é brasileiro e lhe recomenda conteúdos que são mais populares ou que funcionam melhor no Brasil (dois critérios que não são necessariamente a mesma coisa).

Vamos atribuir o retorno do nosso value_counts() a uma variável total_de_votos, e chamaremos total_de_votos.head() para exibirmos os cinco primeiros elementos da lista. Em seguida, aproveitaremos que o conjunto filmes e a série total_de_votos estão ambos indexados pelo Id para adicionarmos esse último conjunto como coluna do primeiro, fazendo filmes['total_de_votos'] = total_de_votos.

Com isso, teremos um dataframe que mostra também o total de votos de cada filme. Agora, vamos ordenar os filmes pelo total de votos com filmes.sort_values("total_de_votos"). Porém, a ordenação padrão do Pandas é crescente (do menor para o maior). Como queremos uma ordenação decrescente (do maior para o menor), utilizaremos o parâmetro nomeado ascending = False.

Agora temos uma lista com The Shashank Redemption, Forrest Gump, Pulp Fiction, The Silence of the Lambs, The Matrix, Star Wars: Episode IV, e por aí vai. Com .head(), mostraremos somente os cinco primeiros filmes dessa lista.

A primeira heurística de recomendação é: com base nas informações que outros usuários e usuárias passaram (o número de votos), podemos indicar os cinco filmes mais populares (que definimos como sendo os mais avaliados) para uma pessoa sobre quem não sabemos nada.

Heurísticas de recomendação - Total de votos, nota média e possíveis dificuldades de heurísticas simples

Vamos dar uma olhada mais a fundo nas recomendações que fizemos com essa heurística? Ao invés de recomendarmos 5 filmes, vamos recomendar 10. Nessa lista, realmente temos filmes que são "famosos", como Um Sonho de Liberdade e Pulp Fiction.

Agora, analisaremos as notas desses filmes. Com notas.groupby("filmeId").mean(), vamos agrupar as notas pelo filmeId e tirar as médias delas. Teremos, então, que o filmeId 1 teve a nota média 3.88, o filmeId 2 teve a nota 3.14, e assim por diante. Não estamos interessados nas médias de usuarioId ou de momento, portanto filtraremos apenas as notas médias com notas.groupby("filmeId").mean()["nota"].

Atribuiremos essa série a uma variável notas_medias. Como utilizamos o groupby() do Pandas, elas já estão indexadas pelo índice. Portanto, podemos colocá-las no dataframe dos filmes com filmes["nota_media"] = notas _medias. Em seguida, pediremos novamente os 10 filmes com o maior total de votos.

O primeiro filme da lista tem nota média 4.41, o segundo 4.08, o terceiro 4.17, e assim por diante. Repare que Jurassic Park tem uma nota média 3.65, ou seja, ele é muito popular em quantidade de votos, mas não tem uma nota tão alta. Inclusive, o filme seguinte, A Lista de Schindler, o próximo filme na lista, foi visto por menos pessoas, mas foi melhor avaliado.

Ou seja, ordenar os filmes pelos mais populares em votos não necessariamente irá implicar naqueles que as pessoas mais gostaram. Portanto, temos um problema na nossa heurística, que é a própria definição de popular. Seriam os filmes mais vistos? Mais próximos da nota 5? Só poderíamos criar a nossa heurística a partir de uma definição formal de popular, que inicialmente assumimos como sendo aqueles filmes com a maior quantidade de votos, mas que às vezes pode não fazer sentido.

Uma segunda heurística/abordagem que podemos utilizar para nos trazer resultados satisfatórios é ordenar os filmes pela nota média. Afinal, se muita gente gostou do filme, a nota média é alta; se quase ninguém gostou, a nota média é baixa. Com filmes.sort_values("nota_media", ascending = False).head(10), faremos essa ordenação e mostraremos os 10 primeiros da lista.

Porém, dos 10 resultados, a maioria é bem desconhecido. Eu, por exemplo, só assisti ao último. Repare que todos eles têm média 5... mas também têm um total de votos 1. Complicado, não? Afinal, não dá para definirmos os melhores filmes como sendo aqueles que têm a maior nota se eles só possuem uma avaliação cada um.

Portanto, o problema de recomendação é mais complexo do que uma simples ordenação, mesmo que tenhamos dados coletados de maneira colaborativa.

Uma alternativa seria, por exemplo, criar mais variações de recomendação, como um sistema que recomenda os filmes mais vistos que o usuário ainda não viu, e outro que recomenda os filmes com maior média de notas. Porém, essa heurística que criamos possui diversos problemas. Por exemplo, imagine o caso dos filmes de nicho: são poucas pessoas avaliando, e quem avalia já tem uma disposição a gostar desses filmes. Portanto, a nota ficará alta, e acabaremos recomendo filmes de nichos muito específicos para o nosso usuário.

Para tentarmos resolver esse problema, criaremos uma query() que filtra os nossos filmando, excluindo aqueles cujo total de votos seja menor que 10. Em seguida, executaremos a mesma ordenação que fizemos anteriormente, mostrando so 10 de maior média.

Dessa vez, só temos filmes cuja nota média não é 5 (afinal, não foram avaliados somente por uma pessoa). Um dos filmes no nosso top de popularidade, Um Sonho de Liberdade, aparece nessa lista. Porém, também aparecem alguns filmes mais de nicho, como alguns que têm apenas 10 votos. Portanto, vamos filtrar novamente, dessa vez excluindo os filmes com menos de 50 votos, e atribuiremos o retorno a uma variável filmes_com_mais_de_50_votos.

Dessa vez, temos mais filmes famosos e interessantes nessa lista. Novamente, aqueles que não são tão conhecidos têm um número de votos razoavelmente baixo, o que é um problema que teríamos que lidar. Quando estamos atacando uma heurística, temos que, de alguma maneira, balancear o nosso filtro para excluir elementos que são muito específicos de modo a criar um sistema de recomendação para alguém sobre quem não sabemos nada a respeito.

Essa segunda heurística, que chamaremos de "nota média e filtrando votos", e a primeira, que chamaremos de "heurística de total de votos", trazem resultados interessantes. A de total de votos realmente está ligada à popularidade, ainda que seja possível que alguma comunidade na internet faça uma brincadeira em que todo mundo vote em algum filme para que ele apareça nos mais votados, deturpando os resultados. Porém, existem artigos científicos dizendo que esse tipo de recomendação acaba sendo razoavelmente bom. Ainda assim, percebemos que também é interessante levar as notas em consideração.

No fim, talvez você queira colocar o sistema de recomendações no ar e medir o resultado com seus clientes, verificando se ele está cumprindo o objeto que os usuários da sua plataforma estão buscando. Se as pessoas estiverem satisfeitas, você mantém; se não estiverem, você troca.

Implementamos essas duas heurísticas sem sabermos nada dos nossos usuários. Porém, muitas vezes temos informações sobre eles. Eu sei, por exemplo, os filmes que eu assisti. Se eu te passo essa informação, você poderá fazer recomendações um pouco melhores. Afinal, se eu disser que não gostei de Star Wars, mas gostei de Deadpool, você poderá me recomendar um filme mais relacionado a super-heróis e menos relacionado ao espaço.

Ou seja, com mais informações sobre o usuário é possível refinar as recomendações, e é isso que faremos daqui a pouco.

Sobre o curso Machine Learning: intro a sistemas de recomendação em Python

O curso Machine Learning: intro a sistemas de recomendação em Python possui 148 minutos de vídeos, em um total de 40 atividades. Gostou? Conheça nossos outros cursos de Machine Learning em Data Science, ou leia nossos artigos de Data Science.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Machine Learning acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas