Sistemas de recomendação : Filtragem colaborativa baseada no usuário usando N Vizinhos Mais Próximos

>

>

Ashay Pathak>
Ashay Pathak

Follow

25 de fevereiro, 2019 – 9 min leia-se

Ashay Pathak, Chatana Mandava, Ritesh Patel

Collaborative Filtering é uma técnica amplamente utilizada em sistemas de recomendação e está avançando rapidamente na área de pesquisa. Os dois métodos mais utilizados são baseados em memória e baseados em modelos.

Neste post, vamos focar apenas em (User-Based Collaborative Filtering) UB-CF que é um método baseado em memória. A idéia principal por trás do UB-CF é que pessoas com características semelhantes compartilham gostos semelhantes. Por exemplo, se você estiver interessado em recomendar um filme ao nosso amigo Bob, suponha que eu e o Bob tenhamos visto muitos filmes juntos e os classificamos de forma quase idêntica. Faz sentido pensar que no futuro também gostaríamos de continuar a gostar de filmes semelhantes e usar essa métrica de similaridade para recomendar filmes.

Vamos tentar implementar o UB-CF e gerar uma lista de filmes que nosso amigo Bob, também conhecido como um usuário ativo, possa estar interessado em assistir. A motivação por trás de escrever este post é mergulhar profundamente no algoritmo e entender como o UB-CF realmente funciona. A maior parte do conteúdo deste post é inspirado por um Curso em Coursera.

Filtragem Colaborativa Usuário-Usuário

O método identifica usuários que são similares ao usuário consultado e estima que a classificação desejada seja a média ponderada das classificações desses usuários similares.

Filtragem Colaborativa: fonte aqui

Estaríamos fazendo as recomendações no MovieLens Dataset. A linguagem de programação usada é python e o trabalho de análise de dados é feito principalmente usando a biblioteca de pandas. A IDE utilizada é jupyter notebook.

Então antes de começar eu gostaria de dar a lista de bibliotecas utilizadas :

  1. Pandas
  2. Numpy
  3. sklearn

Então vamos avançar e entender os conceitos por trás das recomendações. Eu anexei alguns trechos de código e saídas no blog para melhor compreensão. Todo o arquivo ipynb está anexado no final do blog.

Score function

É fácil criar uma função para filtragem colaborativa não personalizada (ou seja, não consideramos os gostos, aversões e classificações de usuários ativos do passado) que retorna uma pontuação tomando o usuário u e o item i como parâmetros de entrada. A função produz uma pontuação que quantifica o quanto um usuário u gosta/prefere o item i.

Então isso geralmente é feito usando as classificações de outras pessoas similares ao usuário. Tudo isso seria discutido em detalhes mais tarde. Por enquanto a fórmula que usei é,

função de pontuação

Onde ‘s’ é a pontuação prevista, ‘u’ é o usuário, ‘i’ é o item, ‘r’ é a pontuação dada pelo usuário e ‘w’ é o peso.

Neste caso nossa pontuação é igual à soma das classificações que cada usuário deu a esse item subtraindo a classificação média desse usuário multiplicada com algum peso que é do quanto esse usuário é semelhante ou supostamente contribui para as previsões de outro usuário. Este é o peso entre o usuário u e v. A pontuação varia entre 0 a 1 onde 0 é baixo e 1 é alto. Tudo parece perfeito, então porque subtraímos as classificações médias de cada usuário e porque usamos a média ponderada em vez da simples média?

O problema é com os tipos de usuários que estamos lidando. Começa com o fato de que as pessoas classificam frequentemente em escalas muito diferentes. Posso ser um usuário positivo e otimista onde vou classificar o filme que gostei como 4 em 5, mas algum outro usuário menos otimista ou com alguns padrões altos pode classificar seu filme favorito como 2 em 5. Aqui o seu 2 é o meu 4. Os ajustes para o tornar melhor é, podemos aumentar a eficiência deste algoritmo se normalizarmos a classificação do utilizador. Uma maneira de fazer isso é dizer que vamos calcular s(u,i) ou seja, pontuar como a classificação média que o usuário dá a cada item mais algum desvio e o desvio vai ser quanto este item é melhor ou pior que a média.

Eu usei a similaridade cosseno para calcular o peso dado na fórmula acima. Eu também usei a noção de vizinhança que seria discutida neste blog à medida que avançamos.

Para normalizar os dados da maneira acima, algumas análises de dados são necessárias em pandas. Você pode obter o código inteiro no final. Para o blog, vou focar nos conceitos importantes.

import pandas as pdmovies = pd.read_csv("movies.csv",encoding="Latin1")
Ratings = pd.read_csv("ratings.csv")
Tags = pd.read_csv("tags.csv",encoding="Latin1")Mean = Ratings.groupby(by="userId",as_index=False).mean()
Rating_avg = pd.merge(Ratings,Mean,on='userId')
Rating_avg=Rating_avg-Rating_avg
Rating_avg.head()

Notações normalizadas

Então agora terminamos de calcular a classificação normalizada para um usuário. Os dados acima seriam usados para calcular a nota final para o usuário mais tarde.

Daqui vamos agora focar em alguns conceitos importantes relacionados a sistemas de recomendação.

Cosine Similarity

Para a fórmula acima precisamos encontrar os usuários que têm pensamentos similares. Isto soa tão interessante para encontrar um usuário que tenha gostos e desgostos semelhantes. Mas a questão é como encontrar a semelhança?

Para responder a isto, vamos usar a Cosine Similarity e ver como os utilizadores são semelhantes. Normalmente é calculado sobre as classificações que ambos os usuários classificaram no passado.

No nosso exemplo, eu usei a função de similaridade cosine_similaridade do sklearn para calcular a similaridade. Mas antes disso temos que fazer algum pré-processamento e limpar os dados.

from sklearn.metrics.pairwise import cosine_similarityfinal=pd.pivot_table(Rating_avg,values='adg_rating',index='userId',columns='movieId')

tabela pivot

>

Contém muito valor de NaN já que todos os usuários não viram todos os filmes e esta é a razão pela qual este tipo de matriz é chamada de matriz esparsa. Métodos como a factorização matricial são usados para lidar com esta sparsity, mas não nos focaríamos nela neste blog. O próximo passo e um dos passos importantes é substituir estes valores NaN.

Existem dois métodos comumente usados para isto :

  1. Utilizar a média do usuário sobre a linha.
  2. Utilizar a média do filme sobre a coluna.

Utilizei ambos os métodos e você pode obtê-la no código abaixo. Mas para explicar eu usaria o método da média do filme.

# Replacing NaN by Movie Average
final_movie = final.fillna(final.mean(axis=0))

Substituir os valores de NaN pela média do filme

Agora, o próximo passo é calcular a similaridade entre os usuários.

# user similarity on replacing NAN by item(movie) avg
cosine = cosine_similarity(final_movie)
np.fill_diagonal(cosine, 0 )
similarity_with_movie =pd.DataFrame(cosine,index=final_movie.index)
similarity_with_movie.columns=final_user.index
similarity_with_movie.head()
Similaridade cosseno do usuário

Vejamos se o que calculamos faz realmente sentido !!

a = get_user_similar_movies(370,86309)
a = a.loc]
a.head()

filmes semelhantes

Da imagem acima podemos ver que a similaridade que geramos é verdadeira já que ambos os usuários (370.86309) têm quase as mesmas classificações e gostos.

Então terminamos de calcular as semelhanças entre os usuários, mas ainda não estou satisfeito. Eu discutiria a razão no próximo passo.

Neighborhood for User (K)

Então de cima podemos ver que calculamos as semelhanças para todos os usuários. Mas como sou um estudante de Grandes Dados, a complexidade do problema sempre me impulsiona. Com isto quero dizer que o sistema de recomendação funciona com os dados enormes e por isso torna-se muito importante manter e capturar apenas os destaques importantes e necessários dos dados.

Para explicar isto usando nosso exemplo de sistema de recomendação de filmes, a matriz que obtivemos acima é (862*862), já que existem 862 usuários únicos nos dados. Este número ainda é pequeno quando comparado com o sistema original de dados em que o sistema estaria trabalhando. Vamos pensar na Amazon. Teria mais de milhões de usuários em sua base de dados e assim, ao calcular a pontuação para qualquer item, não seria uma boa solução ou método para olhar para todos os outros usuários o tempo todo. Portanto, para superar isso, geramos uma noção de vizinhança. Isto inclui apenas o conjunto de (K) usuários similares para um determinado usuário.

Agora vamos dar mais passos para implementar a idéia. No nosso exemplo eu tomei o valor de k como 30. Então teríamos 30 vizinhos mais próximos para todos os usuários.

Utilizei minha função find_n_neighbours personalizada que toma a matriz de similaridade e o valor de n como input e retorna os n vizinhos mais próximos para todos os usuários. Você pode encontrar o código no notebook dado no final do blog.

# top 30 neighbours for each user
sim_user_30_m = find_n_neighbours(similarity_with_movie,30)
sim_user_30_m.head()

top 30 vizinhos para os usuários

Então agora se você pensa então nós reduzimos seriamente o número de cálculos desnecessários. Agora, estamos prontos para calcular a pontuação de um item agora.

Gerar a pontuação final S(u,i)

Wow! terminamos com o processo. Eu sei que passamos por algumas coisas técnicas reais, mas o tempo que gastamos vale a pena pois chegamos ao último passo.

Aqui vamos tentar prever a pontuação para o filme que o usuário não viu.

score = User_item_score(320,7371)
print(score)

pontuação prevista

Então o nosso sistema previu que a pontuação fosse de 4,25 o que é realmente bom. Eu acho que o usuário (370) poderia gostar do filme com id (7371).

Agora vamos dar um toque final ao nosso sistema. Eu acho que a maioria de nós teria usado Netflix ou Hotstar. Então quando abrimos o aplicativo ele mostra o item que você faz como.

Fico sempre fascinado com a recomendação, pois eles acabam sendo os filmes que eu gosto. Tudo isso acontece através do próprio sistema de recomendação. Agora vamos fazer o mesmo e tentar prever os 5 melhores filmes que o usuário pode gostar.

A lógica não é tão difícil assim. Nós já geramos a pontuação para um item. Da mesma forma podemos gerar a pontuação para os outros itens com o mesmo usuário.

Mas, agora novamente mantendo os Grandes Dados em consideração faz sentido gerar a pontuação para todos os outros itens ??

Eu penso NOOOOOOO!!!!

Vamos considerar usuário (U) e usuário (K). Agora suponha que K não esteja na vizinhança de U ,é possível para o usuário U gostar de um filme que K tenha visto e classificado. Na maioria das vezes No.

Pensei que você conseguiu o truque. Sim, estamos apenas interessados em calcular a pontuação dos itens que seus usuários vizinhos viram.

Somos realmente bem sucedidos. Reduzimos o cálculo de 2500 para N ( onde N é o conjunto de filmes que minha vizinhança gostava ) e que é muito inferior a 2500.

Então finalmente vamos recomendar os filmes.

User_item_score1 é a minha função personalizada que usa a nossa discussão acima para calcular previsões

user = int(input("Enter the user id to whom you want to recommend : "))
predicted_movies = User_item_score1(user)
print(" ")
print("The Recommendations for User Id : ",user)
print(" ")
for i in predicted_movies:
print(i)

>

>>>Finalmente em !!!! Conseguimos. Nós temos nosso próprio sistema de recomendação.

A representação do código abaixo pode não ser muito fácil de ler, então por favor vá até meu repositório GitHub para acessar o código.

Os conjuntos de dados necessários podem ser obtidos aqui.

Eu espero que você tenha gostado do blog. Para qualquer consulta, você pode me enviar um e-mail. Fique ligado para mais blogs, já que esta é uma das minhas áreas de interesse e eu definitivamente postaria algumas coisas novas.

Obrigado…!!

Deixe uma resposta

O seu endereço de email não será publicado.