TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 머신러닝>

[머신러닝] 추천 시스템: Surprise를 이용한 영화 시스템 구축

by 기록자_Recordian 2024. 11. 6.
728x90
반응형
추천 시스템이란?
 

[머신러닝] 추천시스템

이전 내용 [머신러닝] 텍스트 분석이전 내용 [머신러닝] 군집화 (Clustering)군집화(Clustering) [군집]군집은 비슷한 샘플을 클러스터 또는 비슷한 샘플의 그룹으로 할당하는 작업으로, 데이터 분석,

puppy-foot-it.tistory.com


이전 내용
 

[머신러닝] 추천 시스템: 파이썬 패키지 Surprise

추천 시스템이란? [머신러닝] 추천시스템이전 내용 [머신러닝] 텍스트 분석이전 내용 [머신러닝] 군집화 (Clustering)군집화(Clustering) [군집]군집은 비슷한 샘플을 클러스터 또는 비슷한 샘플의

puppy-foot-it.tistory.com


Surprise를 이용한 개인화 영화 추천 시스템 구축

 

Surprise를 이용해 잠재 요인 협업 필터링 기반의 개인화된 영화 추천을 구현해 본다.

Surprise 패키지로 학습된 추천 알고리즘을 기반으로 특정 사용자가 아직 평점을 매기지 않은 영화 중에서 개인 취향에 가장 적절한 영화를 추천해 본다.

 

ratings.csv 데이터를 학습 데이터와 테스트 데이터로 분리하지 않고 전체를 학습 데이터로 사용한다.

 

MovieLens

GroupLens Research has collected and made available rating data sets from the MovieLens web site ( The data sets were collected over various periods of time, depending on the size of the set. …

grouplens.org

 

그런데 Surprise는 데이터 세트를 train_test_split() 을 이용해 내부에서 사용하는 TrainSet 클새르 객체로 변환하지 않으면 fit()을 통해 학습할 수가 없다. (오류 발생) 따라서 데이터 세트 전체를 학습 데이터로 사용하려면 DatasetAutoFolds 클래스를 이용하면 된다. DatasetAutoFolds 객체를 생성한 뒤 build_full_trainset() 메서드를 호출하면 전체 데이터를 학습 데이터로 만들 수 있다.

from surprise.dataset import DatasetAutoFolds

reader = Reader(line_format='user item rating timestamp', sep=',', rating_scale=(0.5, 5))
# DatasetAutoFolds 클래스를 ratings_noh.csv 파일 기반으로 생성
data_folds = DatasetAutoFolds("C:/Users/niceq/Documents/DataScience/Python ML Guide/Data/09. ml-latest-small/ratings_noh.csv", reader=reader)

# 전체 데이터를 학습 데이터로 생성
trainset = data_folds.build_full_trainset()

 

[SVD 이용하여 학습 수행]

DatasetAutoFolds의 build_full_trainset() 메서드를 이용해 생성된 학습 데이터를 기반으로 학습 수행

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

 

[특정 사용자가 아직 보지 않은 영화 목록 확인]

특정 사용자는 userId=9 인 사용자로 지정하고, 해당 사용자가 아직 평점을 매기지 않은 영화를 movieId = 42로 선정한 뒤 예측 평점 계산.

영화의 상세 정보는 movies.csv 파일에 있으므로 해당 파일을 DataFrame으로 로딩.

# 영화에 대한 상세 속성 정보 DataFrame 로딩
movies = pd.read_csv("C:/Users/niceq/Documents/DataScience/Python ML Guide/Data/09. ml-latest-small/movies.csv")

userId = 9
movieId = 42

# userId=9의 movieId 추출 (42 데이터 있는지 확인)
movieIds = ratings[ratings['userId']==userId]['movieId']
if movieIds[movieIds==movieId].count() == 0:
    print('사용자 아이디 {0}는 영화 아이디 {1}의 평점 없음'.format(userId, movieId))
print(movies[movies['movieId']==movieId])

 

[특정 사용자의 추천 예상 평점 확인하기]

이 movieId 42인 영화에 대해서 userId 9인 사용자의 추천 예상 평점은 predict() 메서드를 이용하면 알 수 있다.

학습된 SVD 객체에서 predict() 메서드 내에 userId 와 movieId 값을 입력해주면 된다. (모두 문자열이어야 한다)

userId = 9
movieId = 42

uid = str(userId)
iid = str(movieId)

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

▶ 추천 예측 평점은 est 값으로 3.13이다.

 

[사용자가 평점을 매기지 않은 전체 영화를 추출]

먼저 추천 대상이 되는 영화를 추출 하기 위해 get_unseen_surprise() 함수를 만들어 이를 이용해 9인 사용자가 아직 평점을 매기지 않은 영화 정보를 반환한다.

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('평점 매긴 영화 수:', len(seen_movies), '추천 대상 영화 수:', len(unseen_movies), '전체 영화 수:', len(total_movies))

    return unseen_movies

unseen_movies = get_unseen_surprise(ratings, movies, userId)

▶ 사용자 아이디 9번은 전체 영화 중 46개의 영화만 평점을 매겨 추천 대상 영화는 9696개이다.

 

[예측 평점 순으로 영화 추천]

학습된 알고리즘 클래스인 SVD를 이용해 높은 예측 평점을 가진 순으로 영화를 추천해 본다. 

이를 위해 recomm_movie_by_surprise() 함수를 생성하며, 인자로 학습이 완료된 추천 알고리즘 객체, 추천 대상 사용자 아이디, 추천 대상 영화의 리스트 객체, 추천 상위 N개 개수를 받는다.

 

또한 이 함수는 추천 대상 영화 모두를 대상으로 추천 알고리즘 객체의 predict() 매서드를 호출하고 그 결과인 Prediction 객체를 리스트 객체로 저장한다. 그리고 이렇게 저장된 리스트 내부의 Prediction 객체를 예측 평점이 높은 순으로 다시 정렬한 뒤 Top-N 개의 Prediction 객체에서 영화 아이디, 영화 제목, 예측 평점 정보를 추출해 반환한다.

def recomm_movie_by_surprise(algo, userId, unseen_movies, top_n=10):
    # 알고리즘 객체의 predict() 메서드를 평점이 없는 영화에 반복 수행한 후 결과를 list 객체로 저장
    predictions = [algo.predict(str(userId), str(movieId)) for movieId in unseen_movies]

    # predictions list 객체는 surprise의 Predictions 객체를 원소로 가지고 있음
    # [Prediction(uid='userId', iid='1', est=3.69), Prediction(uid='userId', iid='2', est=2.98)...]

    # 이를 est 값으로 정렬하기 위해서 아래의 sortkey_est 함수를 정의함
    # sortkey_est 함수는 list 객체의 sort() 함수의 키 값으로 사용되어 정렬 수행
    def sortkey_est(pred):
        return pred.est

    # sortkey_est()반환 값의 내림 차순으로 정렬 수행하고 top_n개의 최상위 값 추출
    predictions.sort(key=sortkey_est, reverse=True)
    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)]

    return top_movie_preds

unseen_movies = get_unseen_surprise(ratings, movies, userId)
top_movie_preds = recomm_movie_by_surprise(algo, userId, unseen_movies, top_n=10)

print('### Top-10 추천 영화 리스트 ###')
for top_movie in top_movie_preds:
    print(top_movie[1], ":" , top_movie[2])

9번 아이디 사용자에게는 '유주얼 서스펙트', '스타워즈: 에피소트 4', '펄프픽션' 등과 같은 서스펜스/스릴러/범죄/ 액션 영화 등이 추천되었다.

출처: 안될 공학 IT 테크 신기술 (YouTube)

 

Surprise 패키지는 복잡한 알고리즘을 직접 구현하지 않고도 쉽고 간결한 API를 이용해 파이썬 기반에서 추천 시스템을 구축할 수 있도록 해준다.


다음 내용

 

 

 


[출처]

파이썬 머신러닝 완벽 가이드

728x90
반응형