scikit learn으로 잠재요인 협업 필터링을 구현해 보았습니다.
Scikit Learn
pip install scikit-learn
## 해당 명령어로 scikit learn 설치 가능 ##
기본적으로 임의로 데이터를 csv 에 넣어 놓았다.
rating = pd.read_csv('user_rating.csv')
store = pd.read_csv('store_info.csv')
# 상점명(store)을 기준으로 rating 와 store 를 결합함
store_ratings = pd.merge(rating, store, on='store')
미리 셋팅해둔 user 별점이 등록된 csv와 상점 데이터가 들어있는 csv를
store명 즉 store라벨 기준으로 pandas로 결합 하였다.
# user별로 상점에 부여한 rating 값을 볼 수 있도록 pivot table 사용
title_user = store_ratings.pivot_table('rating', index='userid', columns='store')
# 평점을 부여안한 상점은 그냥 0이라고 부여
title_user = title_user.fillna(0)
# 모든 유저간의 코사인 유사도를 구함
user_based_collab = cosine_similarity(title_user, title_user)
# 위는 그냥 numpy 행렬이니까, 이를 데이터프레임으로 변환
user_based_collab = pd.DataFrame(user_based_collab, index=title_user.index, columns=title_user.index)
유저별로 상점에 부여한 별점을 확인하기 위해 pivot table을 사용하였고,
평점을 부여안한 상점도 있을테니 그건 0이라고 그냥 부여 하였습니다.
유저간의 코사인 유사도를 구하고, 이것을 데이터 프레임으로 변환 하였습니다.
# 현재 유저와 가장 비슷한 유저를 뽑고
user = user_based_collab[userid].sort_values(ascending=False)[:10].index[1]
# 위에 유저의 가장높게 부여한 가게를 내림차순으로 정렬
recommand_store = title_user.query(f"userid == {user}").sort_values(ascending=False, by=user, axis=1)
# 위에꺼 리스트로 10개만 가져옴
recommand_list = recommand_store.columns.tolist()[:10]
현재 로그인된 유저를 기준으로 평점을 매긴 가장 비슷 유저를 뽑고, 그 유저중 평점을 가장 높게 부여한 가게를 평점순으로
저장 합니다. 그 이후 10개만 를 리스트 형식으로 가져 왔습니다.
user_index_list = user_based_collab[userid].sort_values(ascending=False)[:10].index.tolist()
user_weight_list = user_based_collab[userid].sort_values(ascending=False)[:10].tolist()
store_list = []
for i in recommand_list:
try:
store = Food.objects.get(store=i)
except:
pass
store_list.append(store)
star_result = []
#위에 10개의 상점을 돌면서 현재 유저가 부여될 평점을 예측
for i in store_list:
try:
store = i.store
except:
pass
weighted_sum = []
weighted_user = []
for i in range(1, 10):
# 해당 상점에 평점을 부여한 사람들의 유사도와 평점만 추가 (즉, 0이 아닌 경우에만 계산에 활용)
if int(title_user[store][user_index_list[i]]) != 0:
# 평점 * 유사도 추가
weighted_sum.append(title_user[store][user_index_list[i]] * user_weight_list[i])
# 유사도 추가
weighted_user.append(user_weight_list[i])
# 총 평점*유사도 / 총 유사도를 토대로 평점 예측
result = sum(weighted_sum)/sum(weighted_user)
star_result.append(result)
(어떤 유저와 비슷한 정도 * 그 유저가 영화에 대해 부여한 평점) 을 더해서 (유저와 비슷한 정도의 합)으로 나눠보면 됨!
평점 예측은 실무에서도 사용이 가능할것 같다. 사전 데이터만 잘 되어있다고 한다면...