추천 시스템이란?
이전 내용
행렬 분해를 이용한 잠재 요인 협업 필터링 실습
일반적으로 행렬 분해에는 SVD가 자주 사용되지만 사용자-아이템 평점 행렬에는 사용자가 평점을 매기지 않은 널(NaN) 데이터가 많기 때문에 주로 SGD나 ALS 기반의 행렬 분해를 이용한다.
[머신러닝] 경사 하강법(GD, gradient descent)
※ ALS : User Latent, Item Latent 중 하나를 고정시킨 후 다른 행렬을 최적화하고, 최적화된 행렬을 고정시킨 후 다른 행렬을 최적화하는 방식으로 convex형태로 바꿔 수렴된 행렬을 찾는 방식.
- 확률적 경사 하강법을 이용한 행렬 분해 get_rmse() 함수 사용
- 행렬 분해 로직은 matrix_factorization() 함수 사용
▶ matrix_factorization(R, K, steps=200, learning_rare=0.01, r_lambda=0.01)
- R: 원본 사용자-아이템 평점 행렬
- K: 잠재 요인의 차원 수
- steps: SGD 반복 횟수
- r_lambda: L2 규제 계수
from sklearn.metrics import mean_squared_error
import pandas as pd
import numpy as np
# RMSE 계산 함수 수정
def get_rmse(R, P, Q, non_zeros):
# 분해된 행렬 P와 Q.T의 내적으로 예측 R 행렬 생성
full_pred_matrix = np.dot(P, Q.T)
# 실제 R 행렬에서 널이 아닌 값의 위치 인덱스 추출
x_non_zero_ind = [non_zero[0] for non_zero in non_zeros]
y_non_zero_ind = [non_zero[1] for non_zero in non_zeros]
# 예측 행렬에서 널이 아닌 실제 값 위치의 예측 값 추출
full_pred_values = full_pred_matrix[x_non_zero_ind, y_non_zero_ind]
R_non_zeros = R[x_non_zero_ind, y_non_zero_ind]
# MSE를 구하고 이를 통해 RMSE 계산
mse = mean_squared_error(R_non_zeros, full_pred_values)
rmse = np.sqrt(mse)
return rmse
# 행렬 분해 함수 수정
def matrix_factorization(R, K, steps=200, learning_rate=0.01, r_lambda=0.01):
num_users, num_items = R.shape
np.random.seed(1)
P = np.random.normal(scale=1./K, size=(num_users, K))
Q = np.random.normal(scale=1./K, size=(num_items, K))
non_zeros = [(i, j, R[i, j]) for i in range(num_users) for j in range(num_items) if not np.isnan(R[i, j])]
for step in range(steps):
for i, j, r in non_zeros:
eij = r - np.dot(P[i, :], Q[j, :].T)
P[i, :] += learning_rate * (eij * Q[j, :] - r_lambda * P[i, :])
Q[j, :] += learning_rate * (eij * P[i, :] - r_lambda * Q[j, :])
# 지정된 주기에 따라 RMSE를 계산하여 출력
if (step % 50) == 0:
rmse = get_rmse(R, P, Q, non_zeros)
print('### iteration step: ', step, 'rmse: ', rmse)
return P, Q
[영화 평점 행렬 데이터 로딩 후 사용자-아이템 평점 행렬 생성]
영화 평점 행렬 데이터를 DataFrame으로 로딩한 뒤에 사용자-아이템 평점 행렬로 만든다.
import pandas as pd
import numpy as np
movies = pd.read_csv("C:/Users/niceq/Documents/DataScience/Python ML Guide/Data/09. ml-latest-small/movies.csv")
ratings = pd.read_csv("C:/Users/niceq/Documents/DataScience/Python ML Guide/Data/09. ml-latest-small/ratings.csv")
ratings = ratings[['userId', 'movieId', 'rating']]
ratings_matrix = ratings.pivot_table('rating', index='userId', columns='movieId')
# title 칼럼을 얻기 위해 movies와 조인 수행
rating_movies = pd.merge(ratings, movies, on='movieId')
# colums = 'title'로 title 칼럼으로 피벗 수행
ratings_matrix = rating_movies.pivot_table('rating', index='userId', columns='title')
[사용자-아이템 평점 행렬을 행렬 분해]
사용자 -아이템 평점 행렬을 matrix_factorization() 함수를 이용해 행렬 분해 한다.
P, Q = matrix_factorization(ratings_matrix.values, K=50, steps=200, learning_rate=0.01, r_lambda=0.01)
pred_matrix = np.dot(P, Q.T)
[예측 사용자-아이템 평점 행렬을 DataFrame으로 변경]
더 쉽게 영화 아이템 칼럼을 이해하기 위해 반환된 예측 사용자-아이템 평점 행렬을 영화 타이틀을 칼럼명으로 가지는 DataFrame으로 변경한다.
ratings_pred_matrix = pd.DataFrame(data=pred_matrix, index=ratings_matrix.index,
columns=ratings_matrix.columns)
ratings_pred_matrix.head()
[개인화된 영화 추천 수행]
이렇게 만들어진 예측 사용자-아이템 평점 행렬 정보를 이용해 개인화된 영화 추천을 수행해 본다.
이전에 아이템 기반 최근접 이웃 협업 필터링에서 생성했던 get_unseen_movies() 함수와 recomm_movie_by_userid() 함수를 이용해 추천 영화를 추출한다.
def get_unseen_movies(ratings_matrix, userId):
# userId로 입력받은 사용자의 모든 영화 정보를 추출해 Series로 변환
# 반환된 user_rating은 영화명(title)을 인덱스로 가지는 Series 객체
user_rating = ratings_matrix.loc[userId, :]
# user_rating이 0보다 크면 기존에 관람한 영화. 대상 인덱스를 추출해 list 객체로 만듦.
already_seen = user_rating[ user_rating > 0].index.tolist()
# 모든 영화명을 list 객체로 만듦.
movies_list = ratings_matrix.columns.tolist()
# list comprehension 으로 already_seen에 해당하는 영화는 movies_list에서 제외
unseen_list = [ movie for movie in movies_list if movie not in already_seen]
return unseen_list
def recomm_movie_by_userid(pred_df, userId, unseen_list, top_n=10):
# 예측 평점 DataFrame에서 사용자 id 인덱스와 unseen_list 로 들어온 영화명 칼럼을 추출해 가장 예측 평점이 높은 순으로 정렬
recomm_movies = pred_df.loc[userId, unseen_list].sort_values(ascending=False)[:top_n]
return recomm_movies
# 조회하고자 하는 사용자
userid = 9
# 사용자가 관람하지 않은
unseen_list = get_unseen_movies(ratings_matrix, userid)
# 잠재 요인 협업 필터링으로 영화 추천
recomm_movies = recomm_movie_by_userid(ratings_pred_matrix, userid, unseen_list, top_n=10)
# 평점 데이터를 DataFrame으로 생성
recomm_movies = pd.DataFrame(data=recomm_movies.values, index=recomm_movies.index, columns=['pred_score'])
# 보지 않은 영화를 기준으로 영화 추천
print('{0} 유저를 위한 추천 영화 리스트:'.format(userid))
recomm_movies
아이템 기반 최근접 이웃 협업 필터링 결과와는 추천된 영화가 다르다.
아이템 기반 최근접 이웃 협업 필터링 때는 비교적 높은 흥행성을 가진 유명한 영화가 추천됐으나,
잠재 요인 협업 필터링을 이용한 결과는 '사우스파크', '라운더스', 블레이드 러너' 등 비교적 어둡고 무거운 주제의 영화가 추천되었다.
최근접 이웃 협업 필터링 vs 잠재 요인 협업 필터링
주어진 상황에서 아이템 기반 최근접 이웃 협업 필터링(Item-based Collaborative Filtering)과 잠재 요인 협업 필터링(Latent Factor Collaborative Filtering)이 서로 다른 유형의 영화를 추천하게 된 이유를 다음과 같은 요인들로 분석할 수 있다:
1. 추천 알고리즘의 차이
◆ 아이템 기반 협업 필터링:
이 방식은 주로 영화 간의 유사성을 기반으로 추천을 제공한다.
유사도가 높은 영화들끼리 추천되기 때문에, 특정 사용자가 이전에 평가한 인기 있는 영화와 비슷한 대중적인 영화를 추천할 확률이 높다. 따라서 상대적으로 많이 리뷰되거나 점수가 높은 영화를 추천하는 경향이 있다.
◆ 잠재 요인 협업 필터링:
이 방식은 사용자와 아이템의 숨겨진 잠재 요인을 추출하여 추천을 제공한다.
이는 사용자와 영화의 이면에 존재하는 선호도 패턴을 분석하여 추천하는 방식으로, 개인화된 추천이 가능해진다.
예를 들어, 사용자가 특정한 장르나 무거운 주제를 선호하는 패턴이 있다면 그에 맞춘 영화를 추천한다.
엔트로피가 더 높은 더 다양한 취향이 반영될 수 있기 때문에 대중적이지 않은 영화도 추천될 가능성이 높다.
2. 영화 데이터의 특징
◆ 데이터의 편향:
아이템 기반 협업 필터링은 사용자가 많이 평가한 아이템에 집중하는 경향이 있어, 많은 사람들이 평점을 매긴 영화는 흥행성이 높은 경우가 많다.
잠재 요인 모델은 매트릭스 분해를 통해 사용자의 선호도를 보다 정밀하게 반영하기 때문에, 특정 사용자의 독특한 취향을 반영한 결과를 도출할 수 있다.
◆ 사용자 선호도의 반영:
만약 사용자가 이전에 어둡고 무거운 주제의 영화를 많이 평가했거나 높은 점수를 주었다면 잠재 요인 모델은 이를 기반으로 유사한 영화를 추천하게 된다.
잠재 요인 모델은 평가 수가 적더라도 그 특성을 추출할 수 있으므로, 주류가 아닌 영화도 추천할 수 있다.
3. 장르 다양성
◆ 아이템 기반 협업 필터링:
영화 데이터에서 대중적인 영화는 다양한 장르가 섞여 있을 수 있으며, 이는 특정 사용자에게는 보편적인 추천으로 느껴질 수 있다. 유명한 영화들은 다양한 사용자에게 높은 평가를 받았을 가능성이 높고, 이는 널리 보편적으로 높은 유사성을 가지기 때문이다.
◆ 잠재 요인 협업 필터링:
이 모델은 특정 사용자의 이전 평가를 바탕으로 독특한 취향을 더 잘 반영할 수 있다.
예를 들어, 특정 사용자가 무거운 주제의 영화를 일관되게 높게 평가했다면, 이 모델은 그러한 취향을 학습하고 반영한다.
4. 결론
잠재 요인 협업 필터링이 '사우스파크', '라운더스', '블레이드 러너' 등 비교적 어둡고 무거운 주제의 영화를 추천한 이유는 이 모델이 사용자의 세부적인 취향과 숨겨진 패턴을 더 잘 반영하기 때문일 가능성이 크다. 사용자가 해당 유형의 영화를 선호하는 경향이 있었다면, 이 모델은 그 정보를 학습하여 보다 개인화된 추천을 제공할 것이다.
다음 내용
[출처]
파이썬 머신러닝 완벽 가이드
velog.io/@ttogle918/Recommendation-03
'[파이썬 Projects] > <파이썬 머신러닝>' 카테고리의 다른 글
[머신러닝] 추천 시스템: Surprise를 이용한 영화 시스템 구축 (8) | 2024.11.06 |
---|---|
[머신러닝] 추천 시스템: 파이썬 패키지 Surprise (0) | 2024.11.04 |
[머신러닝] 추천 시스템: 아이템 기반 최근접 이웃 협업 필터링 실습 (1) | 2024.11.03 |
[머신러닝] 추천 시스템: 협업 필터링 (0) | 2024.11.03 |
[머신러닝] 추천 시스템: 콘텐츠 기반 필터링 (1) | 2024.11.01 |