본문 바로가기

ML Recommendation

포트폴리오를 위한 추천 알고리즘 구현 [3장] : Scikit-Surprise

반응형

 Surprise를 이용해 잠재 요인 협업 필터링 기반의 개인화된 영화 추천을 구현해 보겠습니다. 지금까지 살펴본 Surprise예제는 학습 데이터로 fit()을 호출해 학습한 뒤 테스트 데이터로 test()를 호출해 예측 평점을 계산하고 MSE/RMSE로 성능을 평가했습니다. 이제는 Surprise패키지로 학습된 추천 알고리즘을 기반으로 특정 사용자가 아직 평점을 매기지 않은(관람하지 않은) 영화 중에서 개인 취향에 가장 적절한 영화를 추천해 보겠습니다.

 

이번에는 데이터를 학습 데이터와 테스트 데이터로 분리하지 않고 전체를 학습 데이터로 사용하겠습니다. 그런데 Surprise는 데이터 세트를 train_test_split()을 이용해 내부에서 사용하는 TrainSet 클래스 객체로 반환하지 않으면 fit()을 통해 학습할 수가 없습니다. 따라서 데이터 세트를 그대로 fit()에 적용한 다음 코드는 오류를 일으키게 됩니다. 

 

ratings = pd.read_csv(r'C:\\Users\\HANA\\Downloads\\ml-latest-small\\ratings.csv')
reader = Reader(rating_scale=(0.5, 5.0))
data =Dataset.load_from_df(ratings[['userId', 'movieId', 'rating']], reader)
algo = SVD(n_factors=50, random_state=0)
algo.fit(data)

 

이런 경우 학습 데이터 전체를 사용하기 위해서는 DatasetAutoFolds 클래스를 이용하면 됩니다.  DatasetAutoFolds 객체를 생선 한 뒤에 Build_full_trainset() 메서드를 호출하면 전체 데이터를 학습 데이터로 이용하 수 있습니다.

 

from surprise.dataset import DatasetAutoFolds
reader = Reader(line_format='user item rating timestamp', sep=',', rating_scale=(0, 0.5))
data_folds = DatasetAutoFolds(ratings_file='C:\\Users\\HANA\\Downloads\\ml-latest\\ml-latest\\ratings_noh.csv', reader=reader)
trainset = data_folds.build_full_trainset()

 

DatasetFolds의 Build_full_trainset()메서드를 이용해 생성된 학습 데이터를 기반으로 학습을 수행하였습니다. 그리고 이후에 특정 사용자에 영화를 추천하기 위해 아직 보지 않은 영화 목록을 확인해 보겠습니다. 먼저 SVD를 이용해 학습을 수행합니다. 

algo = SVD(n_epochs=20, n_factors=50, random_state=0)
algo.fit(trainset)

 

특정 사용자는 userId = 9인 사용자로 지정하여 테스트를 진행해 봅니다. 간단하게 Surprise패키지의 API를 이용해 예제를 수행하기 위해 userId가 아직 평점을 매기지 않은 영화를 movieId 42로 선정한 뒤 예측 평점을 계산해 봅니다.

 

predict() 함수에 사용자 ID와 영화 평균점수를 넣어주면 예측값을 출력할 수 있습니다.

movies = pd.read_csv(r'C:\\Users\\HANA\\Downloads\\ml-latest-small\\movies.csv')
movieid = ratings[ratings['userId']==9]['movie']
print(movieid)

if movieid[movieid==42].count() == 0:
    print('There is no rating of 42 for user 9')

print(movies[movies['movieId']] == 42)

uid = str(9)
iid = str(42)

pred = algo.predict(uid, iid, verbose=True)

 

이제부터는 User ID가 9인 고객이 보지 않았던 전체 영화를 추철한 뒤 예측 평점순으로 영화를 추천해 보겠습니다.

def get_unseen_surprise(ratings, movies, userId):
    seen_movies = ratings[ratings['userId'] == userId]['movieId'].tolist()
    total_movies = movies['movieId'].tolist()
    unseen_movies = [movie for movie in total_movies if movie not in seen_movies]
    print('평점 매긴 영화 수:', len(seen_movies), '추천 대상 영화 수:', len(unseen_movies), '전체 영화 수:', len(total_movies))

    return unseen_movies

unseen_movies = get_unseen_surprise(ratings, movies, 9)

 

사용자가 보지 않았던 전체 영화를 구했으니 SVD를 이용해 높은 예측 평점을 가진 순으로 영화를 추천해 보겠습니다. 추천 대상 영화 모두를 대상으로 추천 알고리즘 객체의 predict() 메서드를 호출하고 그 결과인 Prediction객체를 리스트 객체로 저장합니다. 그리고 이렇게 저장된 리스트 내부의 Prediction객체를 예측 평점이 높은 순으로 다시 정렬한 뒤 Top-N개의 Prediction객체에서 영화를 추출합니다.

def recomm_movie_by_surprise(algo, userId, unseen_movies, top_n=10):

    predictions = [algo.predict(str(userId), str(movieid)) for movieId in unseen_movies]

    def sortkey_est(pred):
        return pred.est

    predictions.sort(key=sortkey_est, reverse=True)
    top_predictions = predictions[: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_pred = [(id, title, rating) for id, title, rating in zip(top_movie_ids, top_movie_titles, top_movie_rating)]

    return top_movie_pred
    
    
    unseen_movies = get_unseen_surprise(ratings, movies, 9)
top_movie_preds = recomm_movie_by_surprise(algo, 9, unseen_movies, top_n=10)

print('### Recommendation Top 10 #######')
for top_movie in top_movie_preds:
    print(top_movie[1], ":", top_movie[2])

 

 

포트폴리오를 위한 추천 알고리즘 구현 [1장] : Scikit-Surprise

포트폴리오 구성을 위한 첫 번째 시간입니다. 추천 알고리즘 구현을 위해 포트폴리오를 구성하기 위한 실습을 하겠습니다. 본 과정을 통해 초급자로서 기본적인 추천 알고리즘을 구현하고 차

nicola-ml.tistory.com

 

포트폴리오를 위한 추천 알고리즘 구현 [2장] : Scikit-Surprise

포트폴리오를 위한 추천 알고리즘 구현 [1장] : Scikit-Surprise 포트폴리오 구성을 위한 첫 번째 시간입니다. 추천 알고리즘 구현을 위해 포트폴리오를 구성하기 위한 실습을 하겠습니다. 본 과정을

nicola-ml.tistory.com

 

반응형