Surprise 추천 시스템
- Surprise는 Python에서 추천 시스템을 구축하기 위한 라이브러리로, 협업 필터링(Collaborative Filtering) 알고리즘을 구현하는 데 유용하다.
- Surprise는 다양한 알고리즘을 지원하며, 기본적인 데이터셋 처리, 모델 평가 및 교차 검증 등을 쉽게 할 수 있도록 도와줌
- Surprise는 기본적인 협업 필터링 방법인 행렬 분해와 KNN (K-Nearest Neighbors) 기반의 추천을 제공
- Surprise 추천 시스템의 주요 알고리즘
- KNN (K-Nearest Neighbors)
- 유사한 사용자 또는 아이템을 찾아 추천
- User-based 와 Item-based 방식으로 구분
- SVD (Singular Vlaue Decomposition)
- 행렬 분해 기반으로 잠재요인(Latent Factor)을 추출하여 추천
- NMF (Non-negative Matrix Factorization)
- 비음수 행렬 분해 방법으로, 비음수의 행렬 요소를 찾기위해 사용
- Baseline
- 사용자와 아이템의 평균 평점, 사용자 편향, 아이템 편향 등을 기반으로 예측을 수행.
- KNN (K-Nearest Neighbors)
1. 데이터 준비
# Surprise 라이브러리는 Dataset.load_from_df() 메서드를 사용
import pandas as pd
from surprise import Reader, Dataset, SVD, accuracy
from surprise.model_selection import train_test_split
# 데이터 로드
movies_df = pd.read_csv('movies.csv')
rating_df = pd.read_csv('ratings.csv')
tags_df = pd.read_csv('tags.csv')
2. Surprise 데이터셋 변환
# Dataset.load_from_df()를 사용해서 rating_df에서 사용자, 영화, 평점을 Surprise 형식으로 변환
reader = Reader(rating_scale=(1, 5))
data = Dataset.load_from_df(rating_df[['userId', 'movieId', 'rating']], reader)
3.. 모델 학습
# 데이터셋 분할(훈련용, 테스트용)
trainset, testset = train_test_split(data, test_size=0.2)
# SVD 모델 학습
svd = SVD()
svd.fit(trainset)
4. 추천 제공
# 테스트셋으로 예측 평가
predictions = svd.test(testset)
accuracy.rmse(predictions)
RMSE (Root Mean Squared Error)는 예측값과 실제값의 차이를 평가하는 지표로,
추천 시스템의 정확도를 평가.
>>> 값이 작을수록 모델의 예측 정확도가 높다.
5. 결과
# 4. 사용자 x에게 추천할 영화 10개를 예측하기
x = 99 # 예시 사용자 ID
# 영화 목록 불러오기 (movies.csv)
movie_titles = movies_df.set_index('movieId')['title'].to_dict()
# 사용자가 이미 본 영화 제외하기
user_ratings = rating_df[rating_df['userId'] == x]
watched_movie_ids = user_ratings['movieId'].tolist()
# 추천할 영화 목록 만들기
recommendations = []
for movie_id in movies_df['movieId'].unique():
if movie_id not in watched_movie_ids:
# 예측 평점 계산
pred = svd.predict(x, movie_id)
recommendations.append((movie_id, pred.est))
# 예측된 평점 기준으로 정렬
recommendations.sort(key=lambda x: x[1], reverse=True)
# 상위 10개 추천 영화
top_10_recommendations = recommendations[:10]
# 추천 영화 제목 출력
print(f"사용자 {x}에게 추천할 영화 10개:")
for movie_id, est_rating in top_10_recommendations:
movie_title = movie_titles[movie_id]
print(f"영화 제목: {movie_title}, 예측 평점: {est_rating:.2f}")
예측 평점순으로 영화 추천
def get_unseen_surprise(ratings, movies, userId):
# 입력값으로 들어온 userId에 해당하는 사용자가 평점을 매긴 모든 영화를 리스트로 생성
seen_movies = ratings[ratings['userId'] == userId]['movieId'].tolist()
# 모든 영화의 movieId를 리스트로 생성
total_movies = movies['movieId'].tolist()
# 모든 영화의 movieId 중 이미 평점을 매긴 영화의 movieId를 제외한 후 리스트 생성
unseen_movies = [movie for movie in total_movies if movie not in seen_movies]
print(f"평점 매긴 영화 수: {len(seen_movies)}, 추천 대상 영화 수: {len(unseen_movies)}, 전체 영화 수: {len(total_movies)}")
return unseen_movies
# userId 9에 대해 평점 매기지 않은 영화 리스트 확인
user_id = 9
unseen_movies = get_unseen_surprise(rating_df, movies_df, user_id)
print('추천 대상 영화 ID:', unseen_movies)
def recomm_movie_by_surprise(svd, userId, unseen_movies, movies, top_n=10):
# 알고리즘 객체의 predict()를 평점 없는 영화에 반복 수행 후 결과를 list로 저장
predictions = [svd.predict(str(userId), str(movieId)) for movieId in unseen_movies]
# 예측값(est)을 기준으로 내림차순 정렬
predictions.sort(key=lambda pred: pred.est, reverse=True)
# top_n개의 예측된 영화 선택
top_predictions = predictions[:top_n]
# top_n으로 추출된 영화의 정보 추출
top_movie_ids = [int(pred.iid) for pred in top_predictions]
top_movie_rating = [pred.est for pred in top_predictions]
top_movie_titles = movies[movies.movieId.isin(top_movie_ids)]['title']
# (영화 아이디, 제목, 예상 평점) 순서로 목록 생성
top_movie_preds = [(id, title, rating) for id, title, rating in
zip(top_movie_ids, top_movie_titles, top_movie_rating)]
# 예상 평점 기준으로 내림차순 정렬
top_movie_preds.sort(key=lambda x: x[2], reverse=True)
return top_movie_preds
user_id = 123
unseen_movies = get_unseen_surprise(rating_df, movies_df, user_id)
recommended_movies = recomm_movie_by_surprise(svd, user_id, unseen_movies, movies_df, top_n=10)
# 추천된 영화 출력
print(f"사용자 {user_id}에게 추천할 영화 10개:")
for idx, movie in enumerate(recommended_movies, 1):
print(f"{idx}. 영화 제목: {movie[1]}, 예상 평점: {movie[2]}")
두 함수를 이용해서 예측 평점순 추천영화 출력하기
# 사용자 123이 평가하지 않은 영화 목록 가져오기
unseen_movies = get_unseen_surprise(rating_df, movies_df, 123)
# 추천 영화 목록 가져오기
top_movie_preds = recomm_movie_by_surprise(svd, 123, unseen_movies, movies_df, top_n=10)
# 추천 영화 출력
print()
print("***************Top-10 추천 영화 리스트***************")
for top_movie in top_movie_preds:
print(top_movie[1], ":", round(top_movie[2], 2)) # 예상 평점을 소수점 둘째 자리까지 출력
'Python' 카테고리의 다른 글
[Python] 클래스(Class) (0) | 2025.03.04 |
---|---|
[Python] 람다 표현식 (0) | 2025.03.02 |
[Python] 추천 시스템(1) (0) | 2025.03.01 |
[Python] 함수 사용하기 (0) | 2025.02.22 |
[Python] 2차원 리스트 (0) | 2025.02.22 |