<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Sistemas de Recomendação
A ideia aqui é bem simples
Step1:  O código abaixo cria um vetor global de todos os possíveis interesses.
Step3:  Montando a Matrix
Implemente a função make_user_interest_vector abaixo. Ela será usada para montar a matrix de interesse.
Step4:  Função de Similaridade
Implemente a função de similaridade cosseno. Essa função retorna valores entre 0 e 1. Quanto mais próximo de 1, mais semelhantes são os vetores. Quanto mais próximo de 0, mais diferentes eles são.
Step5:  Usando a função de similaridade implementada, o código abaixo cria uma outra matriz. Essa nova matriz é NxN, onde N é o número de usuários. Cada célula (i, j) contém a similaridade do vetor de interesse do usuário i com o vetor de interesse do usuário j.
Step6:  Algoritmo de Recomendação
A primeira etapa da implementação do nosso algoritmo envolve essa função auxiliar, definida abaixo. Ela deve ser implementada de acordo com a implementação do algoritmo abaixo.
Step7:  Implementada a função que obtém os usuários mais similares a um dado usuário, a segunda etapa do nosso algoritmo pode usá-la para obter uma lista de recomendações de interesses para um dado usuário. Basta implementar a função a seguir de acordo com a descrição dada
Step8:  Para vermos o resultado da recomendação, basta chamar a função user_based_suggestions informado o identificador do usuário
<ASSISTANT_TASK:>
Python Code:
import exercise_utils as eu
import math
from collections import defaultdict
# esse é o nosso dataset
users_interests = eu.get_users_interests() # se não tivermos o dataset, usar eu.get_users_interests_poor()
Explanation: Sistemas de Recomendação
A ideia aqui é bem simples: implementarmos um Sistema de Recomendação que vai recomendar áreas de estudo da computação para usuários. O nosso Sistema de Recomendação se baseará nos interesses dos outros usuários para efetuar a recomendação.
End of explanation
unique_interests = sorted(list({ interest 
                                for user_interests in users_interests
                                for interest in user_interests }))
unique_interests
Explanation: O código abaixo cria um vetor global de todos os possíveis interesses.
End of explanation
def make_user_interest_vector(user_interests):
     Essa função recebe uma lista de interesses de um usuário e 
        retorna a lista unique_interests substituindo o interesses 
        por 0 ou 1 seguindo a lógica: 
            1, se o item de unique_interests está na user_interest.
            0, se o item de unique_interests NÃO está na user_interest 
    return []
user_interest_matrix = map(make_user_interest_vector, users_interests)
# A user é formada dos seguintes dados:
#   - cada LINHA representa o interesse de um usuário para todos os interesses
#   - cada COLUNA é o índice global de um interesse
#   - cada CÉLULA(u, i) contém 1 ou 0: 1 se o usuário u se interessa em i, 0 caso contrário
eu.print_matrix(user_interest_matrix)
Explanation: Montando a Matrix
Implemente a função make_user_interest_vector abaixo. Ela será usada para montar a matrix de interesse.
End of explanation
def cosine_similarity(va, vb):
    return 0.0
Explanation: Função de Similaridade
Implemente a função de similaridade cosseno. Essa função retorna valores entre 0 e 1. Quanto mais próximo de 1, mais semelhantes são os vetores. Quanto mais próximo de 0, mais diferentes eles são.
End of explanation
user_similarities = [[cosine_similarity(user_i_interest_vector, user_j_interest_vector) 
                      for user_j_interest_vector in user_interest_matrix] 
                     for user_i_interest_vector in user_interest_matrix]
eu.print_matrix(user_similarities)
Explanation: Usando a função de similaridade implementada, o código abaixo cria uma outra matriz. Essa nova matriz é NxN, onde N é o número de usuários. Cada célula (i, j) contém a similaridade do vetor de interesse do usuário i com o vetor de interesse do usuário j.
End of explanation
# ALGORITMO: most_similar_users_to
# ENTRADA: usuario_id: identificador de um usuário. O índice do usuário na matriz dos dados.
# SAÍDA: Lista de 2-tuplas contendo ( outro usuário != user_id, similaridade entre o usuário e user_id).
#        A lista retornada deve ser ordenada pela similaridade entre os usuários.
#
# BEGIN
# 
# pares <- []
#
# FOR EACH outro_usuario_id, similaridade IN enumerate(user_similarities) THEN:
#   IF outro_usuario_id != user_id AND similaridade > 0 THEN:
#     pares.add((outro_usuario_id, similaridade))
#
# RETURN ordenar(pares, por=similaridade, em_ordem=decrescente)
# 
# END
def most_similar_users_to(user_id):
    return []
Explanation: Algoritmo de Recomendação
A primeira etapa da implementação do nosso algoritmo envolve essa função auxiliar, definida abaixo. Ela deve ser implementada de acordo com a implementação do algoritmo abaixo.
End of explanation
# ALGORITMO: user_based_suggestions
# ENTRADA: usuario_id: identificador de um usuário. O índice do usuário na matriz dos dados.
# SAÍDA: Uma lista de interesses não "marcados" pelo usuário ordenada pelo índice de recomendação do algoritmo.
#
# BEGIN
#
# // Somando as similaridades de cada interesse em um dicionário. A chave é o interesse e o valor o peso.
# sugestoes <- empty_float_dict()
# FOR EACH outro_usuario_id, similaridade IN most_similar_users_to(usuario_id) THEN:
#   FOR EACH interesse IN users_interests[outro_usuario_id] THEN:
#     sugestoes[intersse] += similaridade
#
# // convertendo dicionário para um lista ordenada
# sugestoes = ordernar(sugestoes.items(), por=peso, em_order=decrescente)
#
# sugestoes_final = []
# FOR EACH sugestao IN sugestoes THEN:
#   IF sugestao NOT IN users_interests[user_id] THEN:
#     suggestoes_final.add(sugestao)
# END
def user_based_suggestions(user_id):
    return []
Explanation: Implementada a função que obtém os usuários mais similares a um dado usuário, a segunda etapa do nosso algoritmo pode usá-la para obter uma lista de recomendações de interesses para um dado usuário. Basta implementar a função a seguir de acordo com a descrição dada:
End of explanation
user_based_suggestions(0)
Explanation: Para vermos o resultado da recomendação, basta chamar a função user_based_suggestions informado o identificador do usuário:
End of explanation
<END_TASK>