1217
[17주차 - Day2] Recommendation system
무비렌즈 데이터를 활용한 사용자 협업 필터링
# 데이터 학습 부분 실습 코드 정리
# 후반에 사용할 ID/Name으로 각각 Name/ID와 장르 반환해 주는 함수 선언
def getMovieName(movie_ratings, movieID):
return movie_ratings[movie_ratings['movieId'] == movieID][['title', 'genres']].values[0]
def getMovieID(movie_ratings, movieName):
return movie_ratings[movie_ratings['title'] == movieName][['movieId', 'genres']].values[0]
!wget "https://grepp-reco-test.s3.ap-northeast-2.amazonaws.com/movielens/ratings.csv"
reader = Reader(line_format='user item rating timestamp', sep=',', skip_lines=1)
data = Dataset.load_from_file('ratings.csv', reader=reader)
from surprise import KNNBasic
import heapq
from collections import defaultdict
trainSet = data.build_full_trainset()
sim_options = {
'name': 'cosine',
'user_based': True
}
model = KNNBasic(sim_options=sim_options)
model.fit(trainSet)
simMatrix = model.compute_similarities()
testUser = '85'
k = 10
# 주어진 사용자와 가장 흡사한 사용자 N을 찾는다
# 먼저 이를 Surprise 내부 ID로 변환
testUserInnerID = trainSet.to_inner_uid(testUser)
# 이 사용자에 해당하는 레코드를 읽어 온다
similarityRow = simMatrix[testUserInnerID]
# users에 모든 사용자들을 일련번호와 유사도를 갖는 듀플의 형태로 저장
# 이때 본인은 제외
users = []
for innerID, score in enumerate(similarityRow):
if (innerID != testUserInnerID):
users.append((innerID, score))
# 이제 users 리스트에서 유사도 값을 기준으로 가장 큰 k개를 찾는다
kNeighbors = heapq.nlargest(k, users, key=lambda t: t[1])
# 이제 유사 사용자들을 하나씩 보면서 그들이 평가한 아이템들별로 원 사용자와 유사 사용자간의 유사도를 가중치로 준 평점을 누적한다
# candidates에는 아이템별로 점수를 누적한다
# 유사 사용자(u')의 평점 * 사용자(u)와 유사 사용자(u')의 유사도
candidates = defaultdict(float)
# 이 K명의 최고 유사 사용자를 한 명씩 루프를 돌면서 살펴본다
for similarUser in kNeighbors:
# similarUser는 앞서 enumerates로 만든 그 포맷 - (내부ID, 유사도값)
innerID = similarUser[0]
userSimilarityScore = similarUser[1]
# innerID에 해당하는 사용자의 아이템과 평점 정보를 읽어온다
# theirRatings는 (아이템ID, 평점)의 리스트임
theirRatings = trainSet.ur[innerID]
# innerID가 평가한 모든 아이템 리스트를 하나씩 보면서
# 아이템ID별로 평점 정보를 합산하되 사용자와의 유사도값을 가중치로 준다
for rating in theirRatings:
candidates[rating[0]] += (rating[1]) * userSimilarityScore
# 사용자가 이미 평가한 아이템들을 제거할 사전을 만든다
watched = {}
for itemID, rating in trainSet.ur[testUserInnerID]:
watched[itemID] = 1
# 앞서 candidates에서 합산된 스코어를 기준으로 내림차순으로 소팅한 후
# 사용자(u)가 아직 못 본 아이템인 경우 추천한다
pos = 0
for itemID, ratingSum in sorted(candidates.items(), key=lambda k: k[1], reverse=True):
if not itemID in watched:
movieID = trainSet.to_raw_iid(itemID)
print(movieID, getMovieName(movie_ratings, int(movieID)), ratingSum)
pos += 1
if (pos > 10):
break
# 위의 코드들 한 함수 안에, 주석 제거하고 모아 놓은 코드
def recommendForUser(userID):
testUserInnerID = trainSet.to_inner_uid(userID)
similarityRow = simMatrix[testUserInnerID]
users = []
for innerID, score in enumerate(similarityRow):
if (innerID != testUserInnerID):
users.append((innerID, score))
kNeighbors = heapq.nlargest(k, users, key=lambda t: t[1])
candidates = defaultdict(float)
for similarUser in kNeighbors:
innerID = similarUser[0]
userSimilarityScore = similarUser[1]
theirRatings = trainSet.ur[innerID]
for rating in theirRatings:
candidates[rating[0]] += (rating[1]) * userSimilarityScore
watched = {}
for itemID, rating in trainSet.ur[testUserInnerID]:
watched[itemID] = 1
pos = 0
for itemID, ratingSum in sorted(candidates.items(), key=lambda k: k[1], reverse=True):
if not itemID in watched:
movieID = trainSet.to_raw_iid(itemID)
print(movieID, getMovieName(movie_ratings, int(movieID)), ratingSum)
pos += 1
if (pos > 10):
break
recommendForUser('85')
'프로그래머스 데브 코스 > TIL' 카테고리의 다른 글
[6기] 프로그래머스 인공지능 데브코스 110일차 TIL (0) | 2023.12.19 |
---|---|
[6기] 프로그래머스 인공지능 데브코스 109일차 TIL (0) | 2023.12.18 |
[6기] 프로그래머스 인공지능 데브코스 107일차 TIL (0) | 2023.12.16 |
[6기] 프로그래머스 인공지능 데브코스 106일차 TIL (0) | 2023.12.15 |
[6기] 프로그래머스 인공지능 데브코스 105일차 TIL (0) | 2023.12.14 |