Link
10-22 10:21
«   2020/10   »
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
535
Total
1,079,665
관리 메뉴

꿈 많은 사람의 이야기

파이썬으로 추천 시스템 구현하기(Python recommender system) - Matrix Factorization(행렬 분해)를 사용 본문

machine learning(머신러닝)

파이썬으로 추천 시스템 구현하기(Python recommender system) - Matrix Factorization(행렬 분해)를 사용

이수진의 블로그 이수진의 블로그 2020. 1. 25. 16:47

포스팅 개요

해당 글에 대한 코드는 아래 github 링크에 전부 올려두었습니다.

 

lsjsj92/recommender_system_with_Python

recommender system tutorial with Python. Contribute to lsjsj92/recommender_system_with_Python development by creating an account on GitHub.

github.com

 

이번 포스팅은 파이썬(Python)으로 추천 시스템(Recommendation system) 기본을 구현해보는 포스팅입니다.

지난 포스팅에는 추천 시스템 협업 필터링(Collaborative Filtering)을 구현해봤습니다. 

그 중 아이템 기반 협업 필터링(Item based Collaborative Filtering)을 구현했습니다.

https://lsjsj92.tistory.com/568

 

파이썬으로 추천 시스템(recommendation system) 구현해보기 - collaborative filtering

포스팅 개요 이번 포스팅은 파이썬(Python)으로 추천 시스템(recommendation system)을 개발해보는 포스팅입니다. 개발이라고 썼지만, 추천 시스템 개발이라기 보다는 공부하는 것이기 때문에 '구현'이라는 표현이..

lsjsj92.tistory.com

 

이번 포스팅은 이전 포스팅에 이어서 파이썬으로 추천 시스템 구현(Recommender system with Python)해보기 3탄으로 이어집니다.

그 중 협업 필터링을 구현할 것인데요. 지난 포스팅과 다르게 행렬 분해(Matrix Factorization)을 기반(잠재 요인 협업 필터링, latent factor collaborative filtering)으로 한 추천 시스템을 파이썬으로 구현해봅니다.

Python Recommendation System(Recommender system) : Collaborative Filtering Matrix Factorization

 

해당 자료는 아래에서 참고했습니다.

데이터는 캐글의 MovieLens 데이터를 사용했습니다. (https://www.kaggle.com/sengzhaotoo/movielens-small)


포스팅 본문

 

협업 필터링(Collaborative Filtering) 요약 

지난 포스팅에서 추천 시스템(Recommender System)의 협업 필터링(Collaborative Filtering)에는 크게 2가지 종류가 있다고 말씀드렸습니다.

  • 아이템 기반 협업 필터링(Item based Collaborative Filtering) - nearest neighbor collaborative filtering
  • 잠재 요인 기반 - SVD와 같은 행렬 분해(Matrix Factorization)를 사용

오늘 포스팅은 여기서 잠재 요인 기반 협업 필터링(Latent Factor Collaborative Filtering)을 파이썬(Python)으로 구현해봅니다. 

 

파이썬 코드 구현

 

 

자! 이제 파이썬으로 추천 시스템을 구현해보죠

데이터는 앞서 개요에서 말씀드린 것처럼 Kaggle에 있는 movielens 데이터를 사용하겠습니다. 

 

이 movielens 데이터는 2개로 나뉘어져 있는데요.

1. 사용자-영화 평점 기반 데이터

2. 영화 정보 데이터

 

영화 평점 데이터는 10만개가 넘고, 영화 데이터는 9000여개가 됩니다.

 

이렇게 말이죠!

이제 여기서 불필요한 데이터는 제거하고 필요한 데이터만 남기겠습니다.

 

timestamp와 genres는 잠재 잠재요인 기반 협업 필터링 추천 시스템에서 필요없습니다.

따라서 drop을 이용해 두 컬럼을 각각 제거해줍니다.

자! 이제 2개의 파일을 pandas의 merge를 이용해서 합쳐줍니다.

2개의 데이터는 movieId라는 공통 컬럼이 있습니다. pd.merge(rating_data, movie_data, on = 'movieId')를 이용해 하나로 합쳐주겠습니다.

 

 

하나로 합쳤습니다! 그러면 특정 유저가 영화에 대해 평점을 매겼는데 그 영화의 제목(title)이 무엇인지 알 수 있게 되었습니다.

 

자! 이제 pandas의 pivot table을 이용해서 데이터를 변경시켜주어야 합니다.

지금은 user, movie, rating이 각각 컬럼에 존재하는데요. 이렇게 생긴 데이터를 value를 평점으로 column은 movie로, row는 user id로 바꿔주어야 합니다. 아래 그림처럼요!

이렇게 변환하는 것을 pandas에서 pivot_table이라는 것으로 지원해줍니다.

바꿔주죠!

 

 

user_movie_data.pivot_table('rating', index = 'userId', columns='title')로 바꿔주면 사용자-영화 평점 데이터로 변경해줍니다. 

단, 단순히 저렇게만 하면 사용자가 평점을 매기지 않은 정보에는 NaN값이 들어가니 fillna을 사용해 0으로 채워줍시다.

 

이제 이 데이터를 어떻게 활용할까? 이것을 고민해야 하는데요.

이번 포스팅에서는 '특정 영화와 비슷한 영화를 추천' 해주는 컨셉으로 가볼까합니다.

그래서 현재 user-movie로 되어 있는 pivot table을 movie-user data로 바꿔줍시다.

numpy에서 .T를 사용하면 Transpose를 시켜줍니다. 즉, 전치를 시켜줍니다.

 

이렇게 전치로 바꿔주면 행은 9064개의 영화 데이터가 되고 열은 671개의 사용자 데이터가 됩니다.

 

이제 SVD라는 개념을 적용해서 사용해봅니다.

SVD(Singular Value Decomposition)란?

SVD라는 것은 특이값 분해라고도 불리웁니다. M x N 크기의 데이터 행렬 A를 아래와 같이 분해합니다.

출처 : https://ratsgo.github.io/from%20frequency%20to%20semantics/2017/04/06/pcasvdlsa/

 

제가 많이 참조하고 배우고 있는 ratsgo님의 블로그에 자세히 설명이 쓰어져 있는데요. 

간단히 말하면 SVD는 다음과 같습니다.

행렬 U와 V에 속한 열벡터는 특이 벡터(Singular Vector)라 불리고 이 특이 벡터들은 서로 직교하는 성질을 가지고 있습니다.

또한 가운데 시그마 모양(∑)을 가지고 있는 것도 행렬인데요. 
이 행렬은 대각 행렬(Diagonal Matrix) 성질을 가지고 있습니다. 
그래서 대각 성분이 행렬 A의 특이값이고 나머지는 0의 값을 가지고 있습니다.

저렇게 특이값으로 쪼개진 데이터를 U, ∑, Vt를 각각 행렬곱을 하면 원래 행렬 A로 되돌릴 수 있습니다.



파이썬 사이킷런(Python scikit learn)에서 제공해주는 TruncateSVD는 이러한 SVD의 변형입니다. 
TruncatedSVD는 시그마 행렬(∑)의 대각원소(특이값) 가운데 상위 n개만 골라낸 것입니다.

이렇게 하면 기존 행렬 A의 성질을 100% 원복할 수 없지만 (그 만큼 데이터 정보를 압축했기 때문) 
행렬 A와 거의 근사한 값이 나오게 됩니다.

 

 

여기서는 scikit learn의 TruncatedSVD를 사용합니다.

 

 

scikit learn의 TruncatedSVD를 사용하고 안에 latent 값을 12로 두겠습니다. 

그리고 SVD.fit_transform을 통해 변환을 하게 되면 9064개의 영화 데이터가 12개의 어떤 요소의 값을 가지게 됩니다.

 

이렇게 나온 데이터끼리 피어슨 상관계수를 통해 구해줍니다.

 

numpy에 있는 corrcoef를 이용하면 상관계쑤를 구할 수 있도록 해줍니다

 

 

seaborn의 heatmap을 사용하면 이 상관계수끼리의 관계를 볼 수 있습니다.

대각선이 하얀색인 이유는 자기 자신과의 관계니까 가장 높은 하얀색이 나온 것입니다.

 

이렇게 나온 상관계수를 이용해서 '특정 영화'와 관련하여 상관계수가 높은 영화를 뽑아주면 됩니다.

 

마블의 가디언즈 오브 갤럭시를 지정하여 상관계수가 높은 영화를 뽑아봤는데요.

영화 목록은 아래와 같습니다.

  • 영화 투 건즈
  • 영화 2012
  • 영화 300
  • 마블 엔트맨
  • 마블 어벤져스
  • 베트맨 

 

등등의 영화가 마블의 가디언즈 오브 갤럭시와 비슷하다고 추천되었습니다!

뭔가 그럴듯한 결과가 나왔네요!


이번 포스팅에서는 파이썬을 활용해 추천 시스템을 구현해보았습니다.

이번 추천 시스템 구현은 잠재 요인 협업 필터링(latent factor collaborative filtering)에 대해서 구현했고 이를 위해 행렬 분해(matrix factorization)을 사용했습니다. 행렬 분해를 위해서 SVD를 사용했구요.

이번 포스팅은 '특정 영화'와 비슷한 영화 들을 추천해주었습니다. 

마치 아이템 기반 협업 필터링과 비슷했죠?

 

이것은 사용자가 본 history를 생각하지 않은 결과입니다. 즉, 사용자에게 추천하기에는 부족하죠.

따라서 다음 포스팅에서는 사용자 맞춤 개인 추천 시스템을 구현하는 포스팅을 작성하겠습니다.

 

12 Comments
  • 프로필사진 볼록티 2020.02.15 17:35 신고 이해하기 쉽게 설명을 잘해주셔서 감사해요 :)
  • 프로필사진 이수진의 블로그 이수진의 블로그 2020.02.15 22:04 신고 도움 되셨다면 다행이에요 ㅎㅎㅎ
  • 프로필사진 추천 2020.06.11 17:36 좋은 포스팅 감사합니다.:)
    혹시 사용자 feature(성별, 나이)를 고려해서 상품 추천 시스템을 구현하려면, 어떤 방법이 좋을까요?
  • 프로필사진 이수진의 블로그 이수진의 블로그 2020.06.11 18:02 신고 안녕하세요.
    저도 미천한 경험자라 그냥 생각나는 것은

    1. 성별, 나이 등등의 user profile feature를 각각 vector화 한다.
    2. 해당 사용자들의 구매 이력 history를 가져온다.
    3. 구매 이력 history에 따른 정보(예를 들어 신발을 샀는데 이게 흰색이고, 운동할 때 좋고 등등) 를 vector화 한다.
    4. 이 정보를 한 raw로 두어서 training set으로 사용해서 추천 시스템을 구현한다

    이렇게 되겠네요. 좀 러프하지만요 ㅠㅠ
  • 프로필사진 호잇 2020.06.28 19:38 좋은 글 감사합니다.
    혹시 TruncatedSVD에서 나오는 값은 SVD에서 U에 해당하는 값인가요??
    맞다면 V값은 따로 나오지 않는 것인가요??
  • 프로필사진 이수진의 블로그 이수진의 블로그 2020.06.28 20:38 신고 안녕하세요~
    아 여기서 TruncatedSVD는 U, ∑, Vt를 거치고 난 후의 Matrix를 return 해줍니다.
    즉, original matrix -> T_SVD -> U, ∑, Vt를 다시 합침 -> return 이 되는 것이죠!

    이것을 U, ∑, Vt를 각각 뽑아내고 싶으시면 제 다음글에 Scipy 이었나.. 그걸로 활용한 것이 있습니다. 그걸 보시면 되어요~
  • 프로필사진 호잇 2020.06.30 01:12 답변 감사합니다!!

    하나 더 여쭤봐도 괜찮을까요??ㅠㅠ

    제가 여러 Matrix Factorization 글을 읽었는데 어디에서는 SVD 기법? 을 쓰고 어디서는 ALS 기법?을 써서 학습을 시킨다는데 두가지 방법이 MF라는 방법론에서 파생되는 여러 기법들인 건가요??
  • 프로필사진 이수진의 블로그 이수진의 블로그 2020.06.30 10:12 신고 안녕하세요.
    네 둘 다 비슷해보이네요.
    사실 저도 ALS는 이번에 처음 보네요 ㅎㅎ
    단 차이점은 X를 고정하고 Y를 optimize하고, Y를 고정시키고 X를 Optimize 하면서 원본 matrix에 가깝게 하는 방법이군요. ㅎㅎ 비슷해보입니다. 방법의 차이일뿐이죠
  • 프로필사진 김기남 2020.09.08 18:36 혹시 궁금한것좀 여쭈어 봐도 될까요!? T로 전치를 하셨는데 이것은 말씀하신대로 '특정 영화와 비슷한 영화를 추천'하려고 하신건데
    이들을 피어슨 상관계수로 유사도를 구하기 위해 영화명을 행으로 배치하신게 맞는건가요~?

    또 np.dot으로 복원을하셨는데 어떤 이유에서 하신건지 궁금합니다!


    아! 그리고 글 너무 잘 읽었습니다. 정리를 너무 잘해주셔서 쉽게 이해할 수 있었어요!.
    그럼 좋은 하루 되세요
  • 프로필사진 이수진의 블로그 이수진의 블로그 2020.09.08 22:06 신고 안녕하세요. 부족한 글인데 도움이 되셨다면 다행입니다!

    네 맞습니다. 상관계수를 활용해서 유사도를 구하는 방법을 사용했습니다.

    음. np.dot은 해당 글에서는 보이지 않는데 어떤 부분을 말씀하시는 걸까요?? github 코드에서 있는 np.dot 부분을 말씀하시는걸까요?
  • 프로필사진 김기남 2020.09.09 19:02 네 맞습니다 제가 깃헙에 올리신것도 봤는데 내적을 하셔서 행렬을 복원하셨더라구요!
    SVD에서 어떤 이유로 복원을 하는지에 대한 내용이 구글링해도 쉽게 나오지가 않아서 여쭈어봤습니다.!

    답글 달아주셔서 너무 감사해요!
  • 프로필사진 이수진의 블로그 이수진의 블로그 2020.09.10 22:11 신고 복구 시키는 이유는 SVD 기법으로 사용자가 해당 영화를 볼 지, 보지 않을 지 score 기반으로 점수를 추측하기 위함입니다.

    왜냐하면 0점으로 부여된 점수(평가를 안한) 것들이 있기 때문에 이들을 기반으로 사용자가 볼 만한 영화(SVD로 나온 score가 높은 데이터)를 추천해주기 위함입니다~
댓글쓰기 폼