-
[scikit-surprise] Dataset 이해하기AI-ML 2024. 5. 14. 07:23728x90반응형
- 목차
키워드.
- scikit-surprise
- Collaborative Filtering
- Recommender System
- movielens
들어가며.
이번 글에서는 "scikit-surprise" 라이브러리가 제공하는 "Trainset" 모듈에 대해서 알아보려고 합니다.
surprise 라이브러리는 Recommender System 의 구축을 도와주는 라이브러리이구요.
구체적으로 "Collaborative Filtering" 의 기능을 손쉽게 구현하기 위한 모듈들을 내장합니다.
특히 Matrix Factorization 기반의 상품 추천 기능을 효과적으로 구현할 수 있는데,
이 과정에서 사용되는 Trainset 모듈의 특징과 사용법에 대해서 알아보도록 하겠습니다.
참고로 surprise 라이브러리의 Github 주소를 아래와 같습니다.
https://github.com/NicolasHug/Surprise
Collorative Filtering.
Collaborative Filtering 의 상세한 내용은 아래 링크의 페이지를 참고해주세요.
https://westlife0615.tistory.com/297
먼저 "Collaborative Filtering (협업필터링)" 에 대해서 간단히 살펴보겠습니다.
협업 필터링은 user 와 item 간의 상호작용 데이터를 활용합니다.
보통 아래와 같은 데이터셋이 흔히 사용됩니다.
사용자 A 가 상품 B 에 몇점의 점수를 주었는지에 대한 Rating Dataset 이 활용되구요.
이렇게 쌓인 Rating Dataset 을 통해서 user 와 item 간의 관계를 분석합니다.
Rating Dataset 은 아래와 같은 Matrix 로 표현이 가능한데요.
movieId 에 해당하는 각각의 Vector 들은 유사도를 비교하여 유사 상품들은 알아낼 수 있습니다.
이를 다른 관점에서 표현하자면,
Item A 와 Item B 를 선호하거나 비선호하는 User 들의 패턴이 유사하다면, Item A 와 B 는 유사한 상품으로 취급할 수 있다는 의미입니다.
이러한 방식으로 Collaborative Filtering 이 동작합니다.
scikit-surprise 사용하기.
먼저 아래의 명령어를 통해서 scikit-surprise 라이브러리를 설치할 수 있습니다.
pip install scikit-surprise
Load Movielens Dataset.
숫자 인식 데이터를 제공하는 MNIST 처럼 추천 시스템 모델링에선 Movielens 데이터셋이 활용됩니다.
그리고 scikit-surprise 의 Dataset 모듈은 Movielens 데이터셋을 로드하는 내장함수를 가집니다.
활용 예시는 아래와 같습니다.
from surprise import Dataset data = Dataset.load_builtin("ml-100k")
load_builtin 함수를 통해서 Movielens 의 데이터셋을 조회할 수 있구요.
load_builtin 함수는 Dataset 객체를 반환하게 됩니다.
raw_ratings.
Dataset 객체는 내부적으로 raw_ratings 변수를 가집니다.
raw_ratings 는 List 타입의 변수로써 Ratings Dataset 을 그 값으로 취합니다.
raw_ratings 는 길이가 4인 Tuple 을 가지는 List 로 구현되어 있구요.
Tuple 의 각 값들은 user, item, rating, timestamp 을 값을 가집니다.
raw_ratings 변수를 DataFrame 으로 변환하면 아래와 같습니다.
import pandas as pd pd.DataFrame(Dataset.load_builtin("ml-100k").raw_ratings, columns=['user', 'item', 'rating', 'timestamp'])
load_from_df.
load_from_df 함수는 Pandas DataFrame 으로부터 Dataset 을 생성합니다.
load_from_df 함수는 입력값으로 사용된 DataFrame 을 파싱하여 Dataset 객체를 생성합니다.
파싱하는 칼럼의 순서는 user, item, rating 와 같습니다.
또한 Reader 라는 추가적인 인자를 필요로 하는데요.
Reader 는 rating 의 범위를 제한합니다.
저의 경우에는 0 ~ 5 점의 범위를 가지므로 Reader(rating_scale=[0, 5]) 를 입력하였습니다.
from surprise import Dataset, Reader import pandas as pd ratings = [ ['user1', 'item1', 1], ['user1', 'item2', 2], ['user1', 'item3', 3], ['user1', 'item4', 4], ['user2', 'item1', 5], ['user2', 'item2', 1], ['user2', 'item3', 2], ['user2', 'item4', 3], ] ratings_df = pd.DataFrame(ratings) ratings_df dataset = Dataset.load_from_df(ratings_df, reader=Reader(rating_scale=[0, 5]))
print(dataset.raw_ratings)
construct_trainset.
construct_trainset 는 Training Dataset 으로 사용할 메모리 상의 데이터들을 Dataset 객체로 변환하는 함수입니다.
from surprise import Dataset, Reader ratings = [ ['user1', 'item1', 1, None], ['user1', 'item2', 2, None], ['user1', 'item3', 3, None], ['user1', 'item4', 4, None], ['user2', 'item1', 5, None], ['user2', 'item2', 1, None], ['user2', 'item3', 2, None], ['user2', 'item4', 3, None], ] dataset = Dataset(reader=Reader(rating_scale=[0, 5])) trainset = dataset.construct_trainset(ratings)
to_inner_uid.
Trainset 객체는 to_inner_uid 함수를 가집니다.
to_inner_uid 함수는 Raw User Id 를 Encoded User Id 로 변환시켜주는 Mapper 함수입니다.
Trainset 객체는 학습을 위해서 내부적으로 사용자 정보를 숫자로 인코딩하게 되는데요.
원본 데이터와 인코딩된 데이터를 위한 Mapper 함수로 생각하시면 됩니다.
trainset.to_inner_uid('user1') --> 0 trainset.to_inner_uid('user2') --> 1 trainset.to_inner_uid('user3') --> ValueError: User user3 is not part of the trainset.
to_inner_iid.
to_inner_uid 함수와 마찬가지로 to_inner_iid 는 원본의 상품 아이디를 인코딩된 상품 아이디로 변환해주는 Mapper 함수입니다.
아마 to_inner_iid 를 풀어 쓰면 "to inner item id" 가 될 것 같네요.
trainset.to_inner_iid('item1') --> 0 trainset.to_inner_iid('item10') --> ValueError: Item item10 is not part of the trainset.
to_raw_uid.
to_raw_uid 함수는 to_inner_uid 의 Inverse Mapper 함수입니다.
즉, 인코딩된 User Id 를 원본 User Id 로 변환시키는 기능을 수행합니다.
trainset.to_raw_uid(0) --> 'user1' trainset.to_raw_uid(1) --> 'user2' trainset.to_raw_uid(2) --> ValueError: 2 is not a valid inner id.
to_raw_iid.
to_raw_iid 는 to_raw_uid 와 마찬가지로 상품 아이디에 대한 디코딩을 수행합니다.
trainset.to_raw_iid(0) --> 'item1' trainset.to_raw_iid(10) --> ValueError: 10 is not a valid inner id.
ir , ur (Item Ratings, User Ratings)
Trainset 객체는 ir 이라는 변수를 가집니다.
ir 는 Item Ratings 의 약자로 List 와 Dictionary 를 함께 취하는 자료형입니다.
Trainset.ir 는 아래와 같은 형태를 취하는데요.
특정 Item 에 평점을 매긴 User 과 Rating 정보를 List 형식으로 취합니다.
trainset.ir
구체적인 예시로 아래와 같이 user1, user2 그리고 item1, item2, item3 에 대한 Ratings 데이터셋이 존재한다고 가정합니다.
이 상태에서 Trainset 를 생성하게 되면 ir 의 값은 아래와 같이 생성됩니다.
from surprise import Dataset, Reader import pandas as pd ratings = [ ('user1', 'item1', 4), ('user1', 'item2', 2), ('user2', 'item3', 3) ] dataset = Dataset.load_from_df(pd.DataFrame(ratings), reader=Reader(rating_scale=[1, 5])) trainset = dataset.build_full_trainset() print(f"trainset.ur : {trainset.ur}") print(f"trainset.ir : {trainset.ir}")
trainset.ur : defaultdict(<class 'list'>, {0: [(0, 4.0), (1, 2.0)], 1: [(2, 3.0)]}) trainset.ir : defaultdict(<class 'list'>, {0: [(0, 4.0)], 1: [(0, 2.0)], 2: [(1, 3.0)]})
ur 변수에서 확인할 수 있는 정보는
- 0번 User 는 0번 Item 에 4 의 Rating 을 주었고, 1번 Item 에 2 의 Rating 을 주었습니다.
- 1번 User 는 2번 Item 에 3 의 Rating 을 주었습니다.
여기서 0번 User 는 'user1' 에 해당하며, 1 번 User 는 'user2' 에 해당합니다.
ir 변수에서 확인할 수 있는 정보는
- 0 번 Item 은 0 번 User 에 의해서 4 의 Rating 을 받았고,
- 1 번 Item 은 0 번 User 에 의해서 2 의 Rating 을 받았고,
- 2 번 Item 은 1 번 User 에 의해서 3 의 Rating 을 받았습니다.
construct_testset.
construct_testset 함수는 Ratings 데이터로부터 테스트를 위한 데이터셋을 생성합니다.
Dataset 와 Trainset 은 별도의 Class 가 존재하지만, Testset 은 단순한 파이썬 리스트 객체입니다.
from surprise import Dataset, Reader ratings = [ ['user1', 'item1', 1, None], ['user1', 'item2', 2, None], ['user1', 'item3', 3, None], ['user1', 'item4', 4, None], ['user2', 'item1', 5, None], ['user2', 'item2', 1, None], ['user2', 'item3', 2, None], ['user2', 'item4', 3, None], ] dataset = Dataset(reader=Reader(rating_scale=[0, 5])) trainset = dataset.construct_trainset(ratings) testset = dataset.construct_testset(ratings) type(trainset) --> surprise.trainset.Trainset type(dataset) --> surprise.dataset.Dataset type(testset) --> list
build_full_trainset.
build_full_trainset 은 모든 Dataset 을 Trainset 으로 변환하는 함수입니다.
즉, Testset 으로 Split 하지 않습니다.
일반적인 머신러닝의 예측 모델의 경우에는 새로운 데이터가 추가되어도 예측이 가능합니다.
Linear Regression 을 예로 들면, 새로운 데이터가 추가되더라고 데이터의 Feature 들을 활용하여 Output 을 예측할 수 있습니다.
반면 Matrix Factorization 의 경우에는 새로운 User 또는 Item 은 예측할 수가 없습니다.
왜냐하면 이어지는 글에서 또다시 설명드리겠지만,
User 와 Item 자체가 곧 Feature 이기에 새로운 User 와 Item 은 학습된 feature 에 존재하지 않죠.
그래서 Cold Start 문제가 야기됩니다.
만약 Dataset 을 Trainset 과 Testset 으로 분할한 이후에 Trainset 으로만 학습된다면,
Trainset 에서 누락된 Testset 의 User 와 Item 은 예측 과정에서 활용할 수 없게 되는 문제가 있습니다.
사실 Dataset 의 양이 많다면 이렇게 누락되는 경우는 드물긴하지만,
그렇지 않는 현실적인 상황이 존재하기 때문에 build_full_trainset 함수가 제공됩니다.
그래서 어느 정도 Parameter 들이 최적화된다면 ( n_factors, reg_all, biased 등 )
build_full_trainset 함수를 통해 Testset 으로 데이터가 누락되는 경우를 차단합니다.
build_full_trainset 의 사용법은 아래와 같습니다.
from surprise import Dataset dataset = Dataset.load_builtin("ml-100k") trainset = dataset.build_full_trainset()
반응형'AI-ML' 카테고리의 다른 글
[ scikit-surprise ] SVD Regularization Terms 알아보기 (0) 2024.05.18 [scikit-surprise] SVD 모델 생성하기 (0) 2024.05.18 [seaborn] Violin Plot 알아보기 (0) 2024.05.07 [scikit-surprise] SVD Model 알아보기 ( Singular Value Decomposition ) (0) 2024.05.07 [seaborn] Count Plot 그리기 ( sns.countplot, sns.catplot ) (0) 2024.05.06