티스토리 뷰

교육/AIFFEL(대전)1기

[Exploration] E08 영화 추천 시스템

무엇보다_빛나는_샤트 2022. 2. 17. 00:11

2021.2.19 16:50

 

안녕하세요

프로그래밍을 배우는 빛나는 샤트입니다.

 

AIFFEL 대전 1기 Explortaion 8. 영화 추천 시스템

*프로젝트 소개: 추천 시스템을 이용해 내가 좋아하는 아티스트(영화)와 관련된 다른 아티스트(영화)를 추천 받아보기

 

<목차>

1️⃣ 개념 정리

2️⃣ 내가 좋아하는 영화와 그렇지 않은 영화를 통해 추천 모델 파악(dot product 이용)

3️⃣ 특정 영화와 비슷한 영화 추천 받기

4️⃣내가 좋아할만한 영화 추천 받기

 

1️⃣ 개념 정리

1. 추천 시스템?

  • 사용자가 선호할 만한 아이템을 추측함으로써 여러 가지 항목 중 사용자에게 적합한 특정 항목을 선택(information filtering)하여 제공하는 시스템

2. 고전척 추천 시스템 - 출처: http://www.kocca.kr/insight/vol05/vol05_04.pdf

1) 협업 필터링

  • 대규모의 기존 사용자 행동 정보를 분석하여 해당 사용자와 비슷한 성향의 사용자들이 기존에 좋아했던 항목을 추천하는 기술
  • 예시: '이 상품을 구매한 사용자가 구매한 상품들' - 라면을 구매한 소비자가는 생수를 많이 구입 --> 라면을 산 고객에게 생수를 추천
  • 장점: 직관적, 항목의 구체적은 분석이 필요없다 (라면과 생수가 식품인지 같이 사용되는 물품인지 분석할 필요가 없다) 또한 용자들이 자연스럽게 사이트를 사용하면서 검색을 하고, 항목을 보고, 구매한 내역을 사용할 수 있다.
  • 단점: 콜드 스타트(Cold start) - ‘새로 시작할 때 곤란함 계산량이 비교적 많은 알고리즘이므로 사용자 수가 많은 경우 효율적으로 추천할 수 없다. 
  • 롱테일(Long-tail) - 시스템 항목이 많다 하더라도 사용자들은 소수의 인기 있는 항목에만 관심을 보이기 때문에 정보의 비대칭적 쏠림
  • 핵심 기술: 비슷한 패턴을 가진 사용자나 항목을 추출하는 기술(행렬분해(Matrix Factorization), k-최근접 이웃 알고리즘 (k-Nearest Neighbor algorithm; kNN) 등의 방법 등)

2) 콘텐츠 기반 필터링

  • 항목 자체를 분석하여 추천을 구현
  • 항목을 분석한 프로파일(item profile)과 사용자의 선호도를 추출한 프로파일(user profile)을 추출하여 이의 유사성을 계산
  • 예시: 음원 사이트 판도라 - 신곡이 출시되면 음악을 분석하여 장르, 비트, 음색 등 약 400여 항목의 특성을 추출한다. 그리고 사용자로부터는 ‘like’를 받은 음악의 특색을 바탕으로 해당 사용자의 프로파일을 준비*
  • 핵심: 콘텐츠의 내용을 분석해야 하므로 아이템 분석 알고리즘 / 군집분석(Clustering analysis), 인공신경망(Artificial neural network), tf-idf(term frequency-inverse document frequency)\
  • 장점: 내용 자체를 분석하므로 협업 필터링에서 발생하는 콜드 스타트 문제를 자연스럽게 해결
  • 단점: 다양한 형식의 항목을 추천하기 어려운 단점

3. Explict Dataset VS Implict Dataset (추천 시스템의 데이터셋 구축)

1) Explict Dataset(명시적 데이터셋)

  • 유저가 자신의 선호도를 직접(Explict) 표현한 Data
  • 좋아요, 싫어요, 리뷰, 구독, 차단 등
  • 장점: 유저의 호불호를 정확히 판단 가능
  • 단점: 데이터를 얻기 힘들다. (유저들의 자발적인 참여가 필요함)

2) Implict Dataset(암묵적 데이터셋)

  • 유저가 간접적(Implice)으로 선호, 취향을 나타내는 Data
  • 검색 기록, 방문 페이지, 구매 내역, 마우스 움직임 등
  • 장점:수집 난이도가 낮고 활용할 수 있는 데이터가 다양하다
  • 특징
    1) 수집되지 않은 데이터도 모델링해야한다. (부정적인 정보가 포함되어 있을 수 있다.
    2) 데이터에 잡음이 많다. (실제 영화를 끝까지 시청했다하더라도 좋아서 본 것인지 과제때문인지 선호도를 정확히 파악할 수 없다)
    3) Explict Dataset에서는 시청시간과 선호도는 비례하지만 Implict Dataset에서는 꼭 그렇지는 않다. 하지만 그럼에도 수치와 선호도는 비례
    4) item의 availability나 반복되는 feeback 등을 고려
    • availability: 동시간에 방영되는 두 TV Show의 경우 한쪽만 볼 수 있어서 다른 프로그램을 좋아한다고 해도 Implicit Data가 쌓이지 않는 상황
    • 반복되는 Feedback은 유저가 한 번 이상 프로그램을 봤을 때 한 번 본 경우와 어떻게 다르게 평가할 것인가에 대한 고려

4. Matrix Factorization(MF)

  • 2006년 Netflix에서 개최한 추천시스템 챌린지를 통해 알려지게 되었다. (성능 10% 향상)
  • (m,n) 사이즈의 행렬 R을 (m,k) 사이즈의 행렬 P와 (k,n) 사이즈의 행렬 Q로 분해한다면 R이란 그저 P와 Q의 행렬곱으로 표현 가능할 수 있다
  • 아이디어의 단순함에도 불구하고 MF 모델은 성능이 준수하고 Scalability가 좋아서 많이 사용되는 모델

[- 출처: CuMF_SGD: Fast and Scalable Matrix Factorization( https://arxiv.org/pdf/1610.05838.pdf)]

  • MF 모델은 큰 평가행렬R을 두 개의 Feature Matrix P와 Q로 분해
  • 평가행렬 크기가 (m,n)일 때 P는 (m,k)크기의 Feature Matrix로 표현된다.
  • 아래 그림에서 첫 번째 벡터 P0=(1, 0.1)은 빨간 모자를 쓴 첫 번째 사용자 특성(Feature)벡터
  • 같은 방식으로 Q의 첫 번째 벡터 Q0(0.9, -0.2)는 해리포터 영화의 특성 벡터.
  • 즉, MF모델은 P, Q 두 벡터를 내적한 결과로 표현
    [출처: &nbsp; https://developers.google.com/machine-learning/recommendation/collaborative/matrix]

5. CSR(Compressed Sparse Row) Matrix

  • MF는 평가행렬을 생성하는데 평가행렬을 생성할 때 너무 많은 행과 열 개수로 인해 메모리가 부족하고 성능이 떨어질 수 있다.
  • Sparse한 matrix에서 0이 아닌 유효한 데이터로 채워지는 데이터의 값과 좌표 정보만으로 구성하여 메모리 사용량을 최소화하면서도 Sparse한 matrix와 동일한 행렬을 표현할 수 있도록 하는 데이터 구조
  • 즉, Sparse(수학에서는 대부분이 0으로 나타내진다)한 행을 압축해 불필요한 내용을 줄여 성능을 올릴 수 있다.

출처: https://rfriend.tistory.com/551

 

CSR Matrix 예시 코드 및 설명: [E08] CSR Matrix (tistory.com)
 

[E08] CSR Matrix

2021.2.26 16:07 안녕하세요 프로그래밍을 배우는 빛나는 샤트입니다. 먼저 CSR Matrix 개념을 이해하게 도와준 @vg-rlo님께 감사함을 표합니다. 추천시스템을 구축하다 보면 만나게 되는 개념인 CSR Matr

shinest-programming.tistory.com

 

6. MF 모델 학습하기

  • implicit 패키지를 사용하여 학습
  • implicit 패키지: 이전 스텝에서 설명한 암묵적(implicit) dataset을 사용하는 다양한 모델을 굉장히 빠르게 학습할 수 있는 패키지
  • als(AlternatingLeastSquares) 모델을 사용
  • 두 개로 쪼개진 행렬(위에서 언급한 P와 Q 행렬) 중 하나를 고정하고 다른쪽을 학습하는 방식을 번갈아 수행하는 AlternatingLeastSquares 방식이 효과적

<AlternatingLeastSquares 클래스의 init 파라미터>

  1. factors : 유저와 아이템의 벡터를 몇 차원으로 할 것인지
  2. regularization : 과적합을 방지하기 위해 정규화 값을 얼마나 사용할 것인지
  3. use_gpu : GPU를 사용할 것인지
  4. iterations : epochs와 같은 의미

 

2️⃣ 내가 좋아하는 영화와 그렇지 않은 영화를 통해 추천 모델 파악(dot product 이용)

 

내가 좋아하는 영화 = ['Star Wars: Episode IV - A New Hope (1977)', 
               'Star Wars: Episode V - The Empire Strikes Back (1980)', 
               'Star Wars: Episode VI - Return of the Jedi (1983)',
              'Star Trek: Generations (1994)',
              'Star Trek: Insurrection (1998)']

 

*스타워즈, 스타트랙 시리즈 선정

 

아래는 모델 설계 및 훈련 부분이며 CSR Matrix는 설정했다고 가정. (CSR Matrix에 대한 내용은 여기)

# 모델 설계
from implicit.als import AlternatingLeastSquares

# Implicit AlternatingLeastSquares 모델의 선언

"""
아래 파라미터의 의미
1. factors : 유저와 아이템의 벡터를 몇 차원으로 할 것인지 
2. regularization : 과적합을 방지하기 위해 정규화 값을 얼마나 사용할 것인지
3. use_gpu : GPU를 사용할 것인지
4. iterations : epochs와 같은 의미

1,4를 늘릴수록 학습데이터를 잘 학습하게 되지만 과적합의 우려가 있으니 좋은 값을 찾아야 함
"""

als_model = AlternatingLeastSquares(factors=100, regularization=0.01, use_gpu=False, iterations=15, dtype=np.float32)
# als 모델은 input으로 (item X user 꼴의 matrix를 받기 때문에 Transpose해줍니다.)
csr_data_transpose = csr_data.T

# 모델 훈련
als_model.fit(csr_data_transpose)

 

아래는 내 user_id와 내가 좋아하는 영화 중 하나의 벡터값을 내적한 결과이다. (1과 가깝다면 훈련이 잘 된것)

- 결과는 0.75 수준으로 잘 나왔다!

shate, Star_Wars_4 = 6041, movie_to_idx['Star Wars: Episode IV - A New Hope (1977)']
shate_vector, Star_Wars_4_vector = als_model.user_factors[shate], als_model.item_factors[Star_Wars_4]

np.dot(shate_vector, Star_Wars_4_vector) # 0.7495111

 

그렇다면 반대로 스타워즈나 스타트랙이 아닌 영화와는 내적값이 어떨까? 1과 굉장히 멀어야 한다.

나는 '벅스라이프'라는 영화와 비교해보기로 했다.

- 결과는 0.03 수준으로 내가 좋아하는 스타워즈와 스타트랙의 데이터 때문에 내적값이 예상대로 굉장히 1과 멀게 나왔다!

# Bugs_life 에피소드 1과 내적 = 0.028826598

Bugs_life = movie_to_idx['Bug\'s Life, A (1998)']
Bugs_life_vector = als_model.item_factors[Bugs_life]
np.dot(shate_vector, Bugs_life_vector) # 0.028826598

 

마지막으로 비슷한 SF장르라면 내적값이 어떻게 나올까? 그래도 0.5 이상은 나오지 않을까?

- 결과는 0.55 수준으로 꽤 높게 나왔다! 오 모델 훈련이 잘 된 느낌적인 느낌

# Star Wars 에피소드 1과 내적 = 0.5492575

Star_Wars_1 = movie_to_idx['Star Wars: Episode I - The Phantom Menace (1999)']
Star_Wars_1_vector = als_model.item_factors[Star_Wars_1]
np.dot(shate_vector, Star_Wars_1_vector) # 0.5492575

 

3️⃣ 특정 영화와 비슷한 영화 추천 받기

그럼 훈련한 모델을 가지고 특정 영화와 비슷한 영화를 추천받아보기로 하자.

스타워즈, 스타트랙같은 SF 장르말고 '애니메이션'을 추천받아보자!

사실 난 애니메이션 영화를 좋아한다...!!

- 결과는 '벅스라이프'를 입력으로 넣으면, '토이스토리', '알라딘' 등 애니메이션 영화가 많이 추천되었다!! 와 소리 질러

# 특정 영화와 비슷한 영화를 추천해주는 함수 구성
def get_similar_movie(movie_name: str):
    movie_id = movie_to_idx[movie_name]
    similar_movie = als_model.similar_items(movie_id)
    similar_movie = [idx_to_movie[i[0]] for i in similar_movie] # 위에서 정의한 idx_to_movie를 이용해 movie_id값을 이용해 제목 추출
    return similar_movie
    
get_similar_movie('Bug\'s Life, A (1998)') # 애니메이션들이 많이 추천되었다.

# ["Bug's Life, A (1998)",
# 'Toy Story 2 (1999)',
# 'Toy Story (1995)',
# 'Aladdin (1992)',
# 'Antz (1998)',
# 'Iron Giant, The (1999)',
# 'Bowfinger (1999)',
# 'Dinosaur (2000)',
# 'Beauty and the Beast (1991)',
# 'American Pie (1999)']

 

4️⃣내가 좋아할만한 영화 추천 받기

그렇다면 나한테 모델은 어떤 영화를 추천해줄까?

user_id를 기준으로 영화 추천을 받아보자!

- 결과는 SF 장르의 영화들을 많이 추천해줬다! 와우.... 놀랍군. 이런식으로 OTT 서비스에서 나에게 추천을 해주는구나.

  물론 이 모델은 매우 단순하다. 그럼에도 꽤 잘 나오네... 좀 더 고도화하는 재미가 있을것 같다

user = 6041 # 내 유저 아이디
# recommend에서는 user*item CSR Matrix를 받습니다.
movie_recommended = als_model.recommend(user, csr_data, N=20, filter_already_liked_items=True)

# idx_to_movie를 활용해 movie_id를 title로 변환
rec_list = [idx_to_movie[i[0]] for i in movie_recommended] 
rec_list

# ['Star Wars: Episode I - The Phantom Menace (1999)',
# 'Star Trek: First Contact (1996)',
# 'Star Trek VI: The Undiscovered Country (1991)',
# 'Raiders of the Lost Ark (1981)',
# 'Star Trek IV: The Voyage Home (1986)',
# 'Star Trek III: The Search for Spock (1984)',
# 'Star Trek: The Wrath of Khan (1982)',
# 'Star Trek V: The Final Frontier (1989)',
# 'Star Trek: The Motion Picture (1979)',
# 'E.T. the Extra-Terrestrial (1982)',
# 'Stargate (1994)',
# 'Princess Bride, The (1987)',
# 'Back to the Future (1985)',
# 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb (1963)',
# 'Indiana Jones and the Last Crusade (1989)',
# 'American Beauty (1999)',
# 'Glory (1989)',
# 'Saving Private Ryan (1998)',
# 'Alien (1979)',
# 'Terminator, The (1984)']

 

5️⃣출처 (내가 작성한 코드가 담긴 Github)

https://github.com/Shinest-changwon/AIFFEL_Exploration/blob/master/E09_My_First_Kaggle/%5BE09%5DMy_First_Kaggle.ipynb

 

GitHub - Shinest-changwon/AIFFEL_Exploration

Contribute to Shinest-changwon/AIFFEL_Exploration development by creating an account on GitHub.

github.com

 

LIST
댓글