Ssul's Blog
[추천시스템#3]CF-UBCF(유저기반 협업필터링) 본문
1. 활용 데이터 이해하기
앞으로 추천시스템에 활용할 데이터는 movielens-100k 데이터다. 총 3개의 데이터가 있다.
[ratings]

유저id와 영화id를 기반으로 해당 영화에 유저가 몇점을 주었는지 기록되어 있는 데이터.
평점은 1-5점으로 구성. timestamp는 날짜시간데이터(위 스샷에선 삭제)
[user 데이터]

user_id를 기준으로 해당 유저의 나이/성별/직업/우편번호 정보가 있음
[item(movie)데이터]

movie_id를 기준으로 해당 영화의 제목, 출시일, 장르 등 영화에 대한 정보가 있음
2. CF(협업필터링)중 UBCF(유저 기반 추천)
import pandas as pd
import numpy as np
# Read rating data
r_cols = ['user_id', 'movie_id', 'rating', 'timestamp']
ratings = pd.read_csv('./u.data', names=r_cols, sep='\t',encoding='latin-1')
ratings = ratings.drop('timestamp', axis=1)
# Rating 데이터를 test, train으로 나누고 train을 full matrix로 변환
from sklearn.model_selection import train_test_split
x = ratings.copy()
y = ratings['user_id']
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25, stratify=y, random_state=12)
- rating 정보 가져오기
- train 75%, test 25%로 데이터 분류
rating_matrix = x_train.pivot(values='rating', index='user_id', columns='movie_id')
- IBCF와 달리, user_id가 인덱스에 위치
# 모든 가능한 사용자 pair의 Cosine similarities 계산
from sklearn.metrics.pairwise import cosine_similarity
matrix_dummy = rating_matrix.copy().fillna(0)
user_similarity = cosine_similarity(matrix_dummy, matrix_dummy)
user_similarity = pd.DataFrame(user_similarity, index=rating_matrix.index, columns=rating_matrix.index)
- matrix_dummy = rating_matrix.copy().fillna(0) -> nan값을 0으로 채우기
- user_similarity = cosine_similarity(matrix_dummy, matrix_dummy)
user_similarity = pd.DataFrame(user_similarity, index=rating_matrix.index, columns=rating_matrix.index)
-> user간 유사도 측정, 원래는 0부터 시작하던 index를 1부터 시작하게 만들기
# 모든 user의 user별 rating 평균 계산
rating_mean = rating_matrix.mean(axis=1)
- 각 유저의 rating평균
def ubcf_bias(user_id, movie_id):
import numpy as np
# 현 user의 평균 rating 가져오기
user_mean = rating_mean[user_id]
if movie_id in rating_matrix:
# 현 user와 다른 사용자의 유사도 가져오기 : 나와 0, 1, 2, 3...user들과 상관관계
sim_scores = user_similarity[user_id]
# 현 movie의 모든 rating 가져오기
movie_ratings = rating_matrix[movie_id]
# 모든 사용자의 rating 평균 가져오기
others_mean = rating_mean.copy()
# 현 movie에 대한 rating이 없는 user 삭제
none_rating_idx = movie_ratings[movie_ratings.isnull()].index
movie_ratings = movie_ratings.drop(none_rating_idx)
sim_scores = sim_scores.drop(none_rating_idx)
# 현재 movie에 대한 평가가 없는 user 평균 삭제
others_mean = others_mean.drop(none_rating_idx)
# 편차 예측치 계산
# 현재 movie의 user 평점 - 각 user의 평균
movie_ratings = movie_ratings - others_mean
# 현재 유저와 다른유저의 유사도 * 해당영화의 평점(각 user 평균을 뺀)
prediction = np.dot(sim_scores, movie_ratings) / sim_scores.sum()
# 예측값에 현 사용자의 평균 더하기
prediction = prediction + user_mean
else:
prediction = user_mean
return prediction
- user_mean = rating_mean[user_id] > 입력된 현재유저의 평점 평균(보통 몇점을 평점으로 하는지)
- sim_scores = user_similarity[user_id] > 입력된 유저와 다른 모든 사용자간 유사도
- movie_ratings = rating_matrix[movie_id] > 입력된 영화의 모든 평점 리스트
- none_rating_idx = movie_ratings[movie_ratings.isnull()].index > 입력된 영화를 평가하지 않은 user 인덱스
- movie_ratings = movie_ratings.drop(none_rating_idx) > 입력된 영화를 평가한 유저의 평점list
- sim_scores = sim_scores.drop(none_rating_idx) > 입력된 영화를 평가하지 않은 유저는 삭제(해당 영화를 평가한 유저의 유사도만 사용)
- movie_ratings = movie_ratings - others_mean > 입력된 영화의 모든 평점리스트 - 입력된 영화를 평가한 각 유저들의 평균값 = 각 유저가 해당 영화를 어떻게 평가하고 있는지 알수 있음 +이면 자신의 평균보다 높게, -이면 자신의 평균보다 낮게
(중요)
- prediction = np.dot(sim_scores, movie_ratings) / sim_scores.sum()
(예)
모든유저들의 유사도합을 분모,
입력된 영화를 평가한 user들과의 유사도 * 각 유저가 해당 영화에 대한 평가
입력된 영화에 대해서 user2는 -0.1, user3 +0.5, user4는 +1.5 일때,
입력된 유저와 유사도가 user2는 0.9, user3은 0.01, user4는 0.01이면,
영화에 대한 긍정적인 평가들이 많지만, 나는 user2와 유사도가 높으므로... -0.1이 높은 영향을 주게됨.
이 값을 기반으로
- prediction = prediction + user_mean > 입력된 유저의 평점 평균에, 예측 평점을 더해주면, 최종 예측값이 나옴
3. UBCF정리 및 결론
- 유저간 유사도를 구하고,
- 입력된 영화를 평가한 유저들을 기준으로, 자신의 평균대비 +평가인지 -평가인지 구함
- 최종적으로 입력된 유저와 유저간 유사도(해당영화를 평가한 유저만) x 해당 영화에 대한 각 유저의 평가를 가중치 곱해서,
- 입력된 유저의 평점평균에 더해주면 최종 예측값 도출
- 나와 유사한 유저가 평가한 영화의 평점을 높게 반영, 나와 유사하지 않은 영화의 평점은 적게 반영
4. 추천하기
def recommender(user, n_items=10):
# 현재 사용자의 모든 아이템에 대한 예상 평점 계산
predictions = []
rated_index = rating_matrix.loc[user][rating_matrix.loc[user] > 0].index # 이미 평가한 영화 확인
items = rating_matrix.loc[user].drop(rated_index)
for item in items.index:
predictions.append(ubcf_bias(user, item)) # 예상평점 계산
recommendations = pd.Series(data=predictions, index=items.index, dtype=float)
recommendations = recommendations.sort_values(ascending=False)[:n_items] # 예상평점이 가장 높은 영화 선택
recommended_items = movies.loc[recommendations.index]['title']
return recommended_items
- 앞에 글과 내용이 동일해서 생략
다음 글은 CB(컨텐츠 기반 추천)
'AI & ML' 카테고리의 다른 글
[추천시스템#6] FM(Factorization Machines) (2) | 2024.01.03 |
---|---|
[추천시스템#5] MF(Matrix Factorization) (1) | 2023.12.29 |
[추천시스템#4]CB(콘텐츠 기반 필터링) (0) | 2023.12.22 |
[추천시스템#2]CF-IBCF(아이템기반 협업필터링) (1) | 2023.12.21 |
[추천시스템#1] 추천관련 개요 (0) | 2023.12.21 |