In [48]:
import math, random
from collections import defaultdict, Counter
from linear_algebra import dot
In [49]:
users_interests = [
["Hadoop", "Big Data", "HBase", "Java", "Spark", "Storm", "Cassandra"],
["NoSQL", "MongoDB", "Cassandra", "HBase", "Postgres"],
["Python", "scikit-learn", "scipy", "numpy", "statsmodels", "pandas"],
["R", "Python", "statistics", "regression", "probability"],
["machine learning", "regression", "decision trees", "libsvm"],
["Python", "R", "Java", "C++", "Haskell", "programming languages"],
["statistics", "probability", "mathematics", "theory"],
["machine learning", "scikit-learn", "Mahout", "neural networks"],
["neural networks", "deep learning", "Big Data", "artificial intelligence"],
["Hadoop", "Java", "MapReduce", "Big Data"],
["statistics", "R", "statsmodels"],
["C++", "deep learning", "artificial intelligence", "probability"],
["pandas", "R", "Python"],
["databases", "HBase", "Postgres", "MySQL", "MongoDB"],
["libsvm", "regression", "support vector machines"]
]
In [50]:
popular_interests = Counter(interest
for user_interests in users_interests
for interest in user_interests).most_common()
# 단순히 인기 있는 것을 추천
print (popular_interests)
In [51]:
# 사용자가 관심사로 선택하지 않은 항목들을 전체 인기순으로 사용자에게 추천
def most_popular_new_interests(user_interests, max_results=5):
suggestions = [(interest, frequency)
for interest, frequency in popular_interests
if interest not in user_interests]
return suggestions[:max_results]
In [52]:
# 사용자 1의 관심사
print (users_interests[1])
# 사용자 1의 관심사 이외의 인기순 추천
print (most_popular_new_interests(users_interests[1], 5))
print()
# 사용자 3의 관심사
print (users_interests[3])
# 사용자 3의 관심사 이외의 인기순 추천
print (most_popular_new_interests(users_interests[3], 5))
'많은 사람들이 파이썬에 관심을 가지고 있으니 당신도 좀 관심을 가져봐' 라는 접근은 마케팅적으로 그리 좋은 방법은 아니다. 관심사에 대한 데이터가 어느 정도 축적되었다면 조금 더 개인화된 추천을 어떻게 할 수 있을지 생각해 보는 게 좋다.
In [53]:
#
# user-based filtering
#
def cosine_similarity(v, w):
return dot(v, w) / math.sqrt(dot(v, v) * dot(w, w))
코사인 유사도는 벡터 v, w 사이의 '각도'를 잰다.
완전히 같은 방향 = 1
정반대 방향 = -1
In [54]:
unique_interests = sorted(list({ interest
for user_interests in users_interests
for interest in user_interests }))
# 관심사 목록
print (unique_interests)
In [55]:
def make_user_interest_vector(user_interests):
"""given a list of interests, produce a vector whose i-th element is 1
if unique_interests[i] is in the list, 0 otherwise"""
"""unique_interests[i]가 관심사 list에 존재한다면
i번째 요소가 1이고, 존재하지 않는다면 0인 벡터를 생성"""
return [1 if interest in user_interests else 0
for interest in unique_interests]
# 사용자 관심사에 대한 행렬
user_interest_matrix = list(map(make_user_interest_vector, users_interests))
# 사용자 간 유사도 계산
user_similarities = [[cosine_similarity(interest_vector_i, interest_vector_j)
for interest_vector_j in user_interest_matrix]
for interest_vector_i in user_interest_matrix]
print (user_interest_matrix)
print ()
print (user_similarities)
In [56]:
def most_similar_users_to(user_id):
# 유사도가 0이 아닌 모든 사용자들을 찾는다.
pairs = [(other_user_id, similarity) # find other
for other_user_id, similarity in # users with
enumerate(user_similarities[user_id]) # nonzero
if user_id != other_user_id and similarity > 0] # similarity
# 유사도 기준으로 정렬
return sorted(pairs, # sort them
key=lambda pair: pair[1], # most similar
reverse=True) # first
# 이 결과값을 이용해서,
# 각각의 관심사에 대해 해당 관심사에 관심이 있는 다른 사용자와의 유사도를 모두 더해 준다.
def user_based_suggestions(user_id, include_current_interests=False):
# sum up the similarities
# 모든 유사도를 더함
suggestions = defaultdict(float)
for other_user_id, similarity in most_similar_users_to(user_id):
for interest in users_interests[other_user_id]:
suggestions[interest] += similarity
# convert them to a sorted list
# 정렬된 list로 변환
suggestions = sorted(suggestions.items(),
key=lambda pair: pair[1],
reverse=True)
# and (maybe) exclude already-interests
# (원한다면) 이미 관심하로 표시한 것은 제외한다.
if include_current_interests:
return suggestions
else:
return [(suggestion, weight)
for suggestion, weight in suggestions
if suggestion not in users_interests[user_id]]
In [57]:
# 사용자 0과 유사도가 가장 높은 사용자 출력
print (most_similar_users_to(0))
print ()
# 사용자 기반 추천
print (user_based_suggestions(0, False))
In [58]:
#
# Item-Based Collaborative Filtering
#
# 사용자-관심사 행렬의 전치행렬(transpose)
interest_user_matrix = [[user_interest_vector[j]
for user_interest_vector in user_interest_matrix]
for j, _ in enumerate(unique_interests)]
# 관심사들의 유사도
interest_similarities = [[cosine_similarity(user_vector_i, user_vector_j)
for user_vector_j in interest_user_matrix]
for user_vector_i in interest_user_matrix]
print (interest_user_matrix)
print ()
print (interest_similarities)
In [59]:
def most_similar_interests_to(interest_id):
similarities = interest_similarities[interest_id]
pairs = [(unique_interests[other_interest_id], similarity)
for other_interest_id, similarity in enumerate(similarities)
if interest_id != other_interest_id and similarity > 0]
return sorted(pairs,
key=lambda pair: pair[1],
reverse=True)
def item_based_suggestions(user_id, include_current_interests=False):
# 비슷한 관심사를 더함
suggestions = defaultdict(float)
user_interest_vector = user_interest_matrix[user_id]
for interest_id, is_interested in enumerate(user_interest_vector):
if is_interested == 1:
similar_interests = most_similar_interests_to(interest_id)
for interest, similarity in similar_interests:
suggestions[interest] += similarity
# 가중치 기준으로 정렬
suggestions = sorted(suggestions.items(),
key=lambda pair: pair[1],
reverse=True)
if include_current_interests:
return suggestions
else:
return [(suggestion, weight)
for suggestion, weight in suggestions
if suggestion not in users_interests[user_id]]
In [60]:
# 관심사 0과 유사도가 가장 높은 관심사 출력
print (most_similar_interests_to(0))
print ()
# 사용자 기반 추천
print (item_based_suggestions(0, False))
In [61]:
print("Popular Interests")
print(popular_interests)
print()
print("Most Popular New Interests")
print("already like:", ["NoSQL", "MongoDB", "Cassandra", "HBase", "Postgres"])
print(most_popular_new_interests(["NoSQL", "MongoDB", "Cassandra", "HBase", "Postgres"]))
print()
print("already like:", ["R", "Python", "statistics", "regression", "probability"])
print(most_popular_new_interests(["R", "Python", "statistics", "regression", "probability"]))
print()
In [62]:
print("User based similarity")
print("most similar to 0")
print(most_similar_users_to(0))
print("Suggestions for 0")
print(user_based_suggestions(0))
print()
print("Item based similarity")
print("most similar to 'Big Data'")
print(most_similar_interests_to(0))
print()
print("suggestions for user 0")
print(item_based_suggestions(0))
Grab 추천 시스템 프레임워크 : http://muricoca.github.io/crab/
추천 시스템 툴킷 : https://turi.com/learn/userguide/recommender/using-trained-models.html
넷플릭스 추천 시스템 공모전 : http://www.netflixprize.com/