본문 바로가기

모델/추천시스템

추천시스템 - Incremental Singular Value Decomposition Algorithms(2)

안녕하세요. 이번 시간엔 Incremental Singular Value Decomposition Algorithms을 구현해보겠습니다. 

 

참고한 자료는 다음과 같습니다(지난 번과 유사합니다).

 

Incremental Singular Value Decomposition Algorithms for Highly Scalable Recommender Systems (B Sarwar외, 2002)

: 알고리즘 논문

 

Evaluation of standard SVD-based techniques for Collaborative Filtering (M Vozalis외, 2009)

: matrix factorization을 할 때 평가하는 방법에 대한 논문

 

https://drive.google.com/file/d/0BylQe2cRVWE_RmZoUTJYSGZNaXM/viewdrive.google.com/file/d/0BylQe2cRVWE_RmZoUTJYSGZNaXM/view

 

Bachelor_thesis_ibrahim_incremental_svd.pdf

 

drive.google.com

: matrix factorization을 할 때 평가하는 방법에 대한 논문

기본 준비

아래에 올라오는 jupyter 파일은 제 github에 모두 있으니 필요하신 분들은 여기서 코드 복사하셔서 사용하시면 되겠습니다.

github.com/Hwan-I/Study/tree/master/Recommend/incremental_SVD

 

Hwan-I/Study

Contribute to Hwan-I/Study development by creating an account on GitHub.

github.com

 

* 데이터 링크입니다. 

grouplens.org/datasets/movielens/100k/

 

MovieLens 100K Dataset

MovieLens 100K movie ratings. Stable benchmark dataset. 100,000 ratings from 1000 users on 1700 movies. Released 4/1998. README.txt ml-100k.zip (size: 5 MB, checksum) Index of unzipped files Permal…

grouplens.org

코드실행

1. 패키지를 불러옵니다. 여기서 utils는 제가 경로 설정을 위해 만든 py파일이라 저 부분은 없애시고 실행하시면 됩니다.

 

2. 기본셋팅(main 위의 함수 중 experiment를 제외하면 전처리하는 코드라 따로 설명을 넣지 않았습니다. 자세한 부분은 주석을 참조하시거나 질문 주시면 답변 드리겠습니다)

 

  - data_path와 raw_path : 점수 데이터를 불러오기 위한 path입니다.

  - ratings : 점수 데이터입니다. (위의 링크에서 다운 받으시고 압축을 푼 뒤, raw_path를 다운 받으신 폴더로 하시면 열 수 있습니다)

  - seed_num : 랜덤으로 값을 추출할 때 똑같은 결과가 나오게 하기 위해 번호를 지정합니다. 저는 0번으로 했지만 아무 번호를 하셔도 상관없습니다.

  - X_ind : ratings의 index 값을 저장하는 변수입니다.

 

3. 실험셋팅 : 실험 관련 변수를 셋팅합니다.

 

  - k : SVD로 matrix 분해 이후 몇 차원을 사용하여 복구할지 정하는 값입니다. 저는 논문에서 나온대로 14차원을 선택했습니다.

  - origin_pivot : user x item matrix로 구성된 dataframe입니다.

  - key_dict : 'user'와 'item'을 key값으로 가지는 dict입니다.

    - user : key값은 user번호, value는 key값에 해당하는 origin_pivot의 index값입니다.

    - item : key값은 user번호, value는 key값에 해당하는 origin_pivot의 column값입니다.

 

4. 실험

 

  - 저는 test_rate0.2, 0.5, 0.8로 주어 실험했습니다. 여기서 test_ratetest 데이터의 비율을 의미하는데 0.2면 전체 데이터의 20%를 test 데이터로 쓴다는 의미입니다.

  - 추천시스템에서 test 데이터를 어떻게 써야하는지는 여러 기준이 있는데 저는 test에 해당하는 user, item 값을 NaN으로 처리한 뒤에 train 했습니다. 이후 예측값이 나오면 그 값과 실제값을 비교하여 mae를 구했습니다. 이러한 기준은 위의 참고 자료를 참조하시기 바랍니다.

  - experiment의 매개변수에 대한 설명입니다.

    - 0.2 : test_rate

    - seed_num : 위의 기본셋팅에서 설정한 랜덤 고정 값입니다.

    - ratings : u.data 파일입니다. UserID, MovieID, Ratings 등을 column으로 가진 dataframe입니다.

    - origin_pivot : user x item matrix로 구성된 dataframe입니다.

    - key_dict : 'user'와 'item'을 key값으로 가지는 dict입니다.

    - True : 결과값을 반환할 때 True면 예측값, 예측 matrix 등을 추가로 반환하는 옵션입니다.

 

5. 실험과정 (experiment 함수 부분입니다)

 

5-1. 실험 기본 셋팅

  user x item matrix를 정규화하고 test 할 user와 item을 추출하는 과정입니다. 여기서 정규화는 user x item matrix에 대해 test data는 NaN으로 처리하고 NaN 값을 채울 때 train의 모든 item의 평균값을 사용합니다(NaN 데이터 제외). 그 후 user x item matrix에서 user 단위로 각 user의 평균값을 뺍니다.(함수 normalized_df 부분을 참고하시기 바랍니다)

 

실험 기본셋팅

  - 변수 설명

    - X_ind : ratings의 index 값입니다.

    - test_dict : basis_num 단위로 mae값을 저장할 dict입니다.

    - rg : 랜덤으로 번호를 추출할 때 결과를 고정하기 위한 변수입니다.

    - test_index : test_rate를 기준으로 test 데이터 index를 추출합니다.

    - basis_num_list : basis 값을 가진 list로 for문을 활용하기 위해 list로 넣습니다.

    - count : 실험 진행을 나타내는 변수입니다.

    - test_ind : ratings에서의 최종 test_index값입니다.

    - test_pairs : [([(userid1, movieid1, rating1),(userid2, movieid2, rating2),...]와 같은 형태의 list입니다.

    - changed_origin_pivot : test값인 user, item에 대한 점수 값을 NaN으로 처리한 user x item matrix입니다.

    - norm_pivot : 정규화된 user x item matrix입니다.

    - mean_dict : key값은 index 번호, value는 index에 해당하는 user의 평균 점수 값을 가진 dict입니다.

    - result_dict : key값은 basis_num, value는 pred, true 값 등을 가진 dict입니다.

 

5-2. 반복 실험 : basis_num 단위로 실험을 진행합니다.

  - 변수 설명

    - model, model.fit() : incremental_svd를 만들고 fit합니다.

    - pred_list : test data에 해당하는 예측값입니다.

    - true_list : test data의 실제값입니다.

    - matrix : 예측값에 해당하는 user x item matrix입니다.

    - test_dict에 basis_num을 key값으로 각 mae를 저장합니다.

    - result_return_option이 True면 basis_num에 해당하는 pred 값 등도 result_dict에 저장합니다.

    - 이를 basis_num_list 만큼 진행합니다.

 

6. 결과

 

  x축은 basis 값, y축은 mae값입니다. basis가 600일 때는 별 차이가 없었으나 그 이후로는 test_rate가 0.2일 때 확실히 mae가 더 낮은 것을 볼 수 있습니다. user가 총 943명인데 800을 basis로 놓고 만든 incremental_SVD 모델과 단순히 SVD를 쓴 결과를 비교하면 크게 차이가 나지 않는 것을 볼 수 있습니다. 데이터가 작아서 모델링하는 시간은 2개 서로 비슷했습니다.

 

7. 결론 

 

  - 논문과 다른 결과가 나오긴 했으나 랜덤 seed 값을 어떻게 주느냐에 따라 결과가 상당히 달라지기 때문에 실험결과와 똑같이 구현하는 것은 불가능하다고 판단했습니다.(test 데이터에 대한 처리도 다를 수 있음)

  - item의 평균값으로 아무래도 채우다보니 오차는 아마 실제값이 평균값에서 멀수록 크게 나올 것입니다. 이러한 부분을 개선한다면 해당 모델의 성능이 더 높아질 것이라고 생각합니다.

 

긴글인데 읽어주셔서 감사합니다. 혹시 궁금하신 사항이나 잘못된 부분있으면 말씀해주세요!