무냐의 개발일지

[04/04] 추천시스템 시작 ! 본문

Data Scientist Bootcamp

[04/04] 추천시스템 시작 !

무냐코드 2024. 4. 4. 18:08

추천시스템

  • 범주형 데이터를 다룬다. (범주형, 이산적인 데이터를 숫자 벡터로 변환합니다.)
    액션물, 로맨스물, 스릴러물, 한드, 미드, 일드, 영드 등의 영화 item 데이터와 A, B, C 같은 user 데이터를 취급했습니다. 이러한 데이터는 연속적(continuous)이지 않고 이산적(discrete)입니다. 이를 범주형(categorical) 데이터라고 합니다.
  • (숫자 벡터로 변환한 뒤) 유사도를 계산한다.  (숫자 벡터의 유사도를 계산하여 유사도가 가까운 (혹은 높은) 제품을 추천)
    범주형 데이터들을 좌표에 나타내었는데, 좌표에 나타내기 위해서는 숫자로 이루어진 벡터(numerical vector)로 변환해야 합니다. 그리고 그 거리를 계산하여 유사도를 계산합니다.

 

| 코사인 유사도(Cosine Similarity) 

 

 두 벡터 간의 코사인 값을 이용해 두 벡터의 유사도를 계산합니다. 코사인 유사도는 -1 ~ 1사이의 값이고, 1에 가까울 수록 유사도가 높다고 할 수 있습니다.

 

 

#코사인유사도 구하는법 (sklearn)
from sklearn.metrics.pairwise import cosine_similarity

t1 = np.array([[1, 1, 1]])
t2 = np.array([[2, 0, 1]])
cosine_similarity(t1,t2)

# Q. 아래 t1, t2 리스트의 요소 값을 조정해서 코사인 유사도 값이 0이 되게 만들어보세요.
# +코사인 유사도 값이 -1이 되게도 만들어보세요.
t1 = np.array([[1, 1, -2]])
t2 = np.array([[2, 0, 1]])
cosine_similarity(t1,t2)

#결과
array([[0.]])


# Q. 아래 t1, t2 리스트의 요소 값을 조정해서 코사인 유사도 값이 0이 되게 만들어보세요.
# +코사인 유사도 값이 -1이 되게도 만들어보세요.
t1 = np.array([[-2, 0, -1]])
t2 = np.array([[2, 0, 1]])
cosine_similarity(t1,t2)

#결과
array([[-1.]])

 

 

| 추천시스템 종류

 

▶︎ 콘텐츠 기반 필터링(Content Based Filtering)

▶︎ 협업 필터링(Collaborative Filtering)

  • 사용자 기반
  • 아이템 기반
  • 잠재요인 협업 필터링 (latent factor collaborative filtering) → 행렬 인수분해(matrix factorization)

▶︎ Deep Learning 적용 or Hybrid 방식

 

 

 

1. Content based filtering

영화로 따지면 장르, 배우, 감독 등 특징(feature)에 따라 콘텐츠가 비슷하다고 분류

 

2. Collaborative filtering 

 과거의 사용자 행동 양식(User Behavior) 데이터를 기반으로 추천하는 방식입니다.

 

 

 

user_id가 영화(item_id)에 각각 랭킹을 매기고, 그 시간이 기록되어 있다. (interaction matrix)

그거를 평점행렬도 변환 - 이렇게 되면 빈칸이 많은 sparse matrix가 생성된다

 

* 종류 : 사용자 기반 아이템 기반 그리고 잠재요인(latent factor) 방식이 있다고 했는데요. 사용자 기반과 아이템 기반은 유사도를 계산하는 방식이고 잠재요인은 행렬 인수분해(matrix factorization)를 이용해 잠재요인을 분석합니다.

 

1) 사용자기반 : 당신과 비슷한 고객들이 다음 상품을 구매했습니다.

 

user4와 유사한 user2가 매긴 평점을 바탕으로 item3를 user4에게 추천해주는 방식

 

2) 아이템기반 : 이 상품을 선택한 다른 고객들은 다음 상품을 구매했습니다.

- 아이템 간의 유사도를 측정하여 해당 아이템을 추천하는 방식 (사용자기반보다 더 정확도 높다)

 

 

user2가 item1을 좋아한다

item1을 좋아하는 다른 유저 (user4)를 찾는다

user4에게 user2가 좋아하는 다른 상품 item3을 추천한다

 

3) 행렬 인수분해 (matrix factorization)

  • SVD(Singular Vector Decomposition) : 특잇값 분해 (MxN형태 행렬 A를 3개의 행렬로 분해하는 것 U, Sigma, VT)

 

 

: Movie1은 comedy특징이 3만큼, action특징이 1만큼 있다. 1번 user는 comedy를 좋아하니까 -> 평점은 3

 

 

- SVD는 "정보 복원"을 위해 사용됩니다. 최대한 중요한 정보들만 부분 복원해서 사용하면 사진의 용량은 줄어들지만 여전히 사진이 보여주고자 하는 내용은 살릴 수 있을 것이다. 

 

* Turncated SVD

추천시스템에서는 Truncated SVD를 사용한다. Truncated SVD를 이용해 분해한 뒤 복원하면 SVD 처럼 완벽히 같은 행렬이 나오지 않습니다. 그 이유는 Truncated SVD는 차원을 축소한 다음 행렬을 분해하기 떄문. 

 

SVD를 평가행렬에 적용

사용자가 평점을 매기는 요인을 그냥 "잠재요인"으로 취급한 뒤 그걸 SVD기법을 이용해 분해한 뒤 다시 합치는 방법으로 영화에 평점을 매긴 이유를 벡터화하여 이를 기반으로 추천합니다. 이 기법은 넷플릭스나 왓챠, 유튜브 같은 대 기업에서 사용하여 그 효과를 입증해 내었고 이후 많은 기업들이 이 기법을 채택하여 사용하고 있습니다. (링크)

 

* SVD vs Truncated SVD

1.계산 비용: SVD는 전체 데이터에 대한 분해를 수행하므로 계산 비용이 큽니다. 반면, Truncated SVD는 몇 개의 주요한 특이값과 이에 대응하는 특이 벡터만을 선택하므로 계산 비용이 상대적으로 적습니다.

2.노이즈 제거: Truncated SVD는 작은 특이값을 제거하고 이에 대응하는 특이 벡터를 사용하기 때문에, 노이즈를 제거하고 중요한 정보를 유지하는 효과가 있습니다.

3.해석 가능성: SVD는 전체 데이터에 대한 분해를 수행하므로, 각 특이 벡터가 전체 데이터에서 어떤 의미를 가지는지 해석하기 쉽습니다. 반면, Truncated SVD는 전체 데이터를 대표하는 특이 벡터들 중 일부만을 선택하므로, 전체 데이터에 대한 해석이 어렵습니다.

4.메모리 사용: SVD는 전체 데이터에 대한 분해를 수행하므로, 메모리 사용량이 큽니다. 반면, Truncated SVD는 몇 개의 주요한 특이값과 이에 대응하는 특이 벡터만을 선택하므로, 메모리 사용량이 상대적으로 적습니다.

따라서, Truncated SVD는 SVD와 비교하여 계산 비용과 메모리 사용량을 줄이면서도 노이즈를 제거하는 효과가 있으나, 해석 가능성이 낮다는 단점이 있습니다.

 

 

  • ALS(Alternating Least Squares)
  • NMF(Non-negative Matrix Factorization)

 

| 실제 추천 시스템

- 어떤 사이트에서 유입이 되었는지, 그리고 시청한 뒤 구매로 이어지기까지의 시간 등 우리의 족적들을 다 분석합니다. 이를 전문 용어로 Digital Footprint(디지털 발자국), Digital Shadow(디지털 그림자)라고 해요.

- 그리고 이중에서 가장 중요한 지표가 바로 클릭률 입니다. 전문 용어로는 CTR(Click Through Rate) 입니다. CTR은 마케팅에서도 중요한 지표로 작용하는 용어이기도합니다.

 

(넷플릭스의 성공 알고리즘 - 나이브베이즈)

cold start : 아무 기록도 없는 백지 상태 

prior 사전확률 (영화를 좋아할 확률 50%)

시청자가 좋아하고 싫어하는 기록을 업데이트한 것 : 사후확률 (액션영화를 좋아할 확률 75%)

액션장르일때 75%, 라이언레이놀즈가 80%

 

좋아한 액션영화 75% 중 80%에 라이언 레이놀즈 출현 - 0.6

싫어한 영화 25% 중 20%에 라이언 레이놀즈 출현 - 0.05

 

이렇게 나이브베이즈 알고리즘을 사용해 추천 (이 외에도 Matrix Factorization, GBDT, RBM, TF-IDF등 여러개를 섞어서 씀)

 

 

 

| CSR Matrix

대부분 유저가 평가하지 않은 sparse matrix일것이므로, 이 용량을 줄인 Compressed Sparse matrix를 사용한다

CSR Matrix는 data, indices, indptr 로 행렬을 압축하여 표현합니다. 

 

  • data는 0이 아닌 원소를 차례로 기입한 값입니다.

data = [1, 2, 3, 4, 5, 6]

  • indices는 data의 각 요소가 어느 열(column)에 있는지를 표현한 index입니다.

indices = [0, 4, 1, 3, 0, 3]

  • indptr은 [최초시작행번호,시작행에서의 데이타 개수,두번째 행에서의 데이타 누적 개수,...,마지막행에서의 데이타 누적개수] 입니다. 이를 통해 data의 요소들이 어느 행(row)에 있는지를 알 수 있습니다.

indptr = [0, 2, 4, 4, 6]

이를 통해 data[0:2]는 첫 번째 행, data[2:4]는 두 번째 행, data[4:4]는 세 번째 행, data[4:6]는 네 번째 행에 위치함을 나타낼 수 있게 됩니다.

 

 

 

 

| MF 모델 학습하기

이전 스텝에서 설명한 Matrix Factorization 모델을 implicit 패키지를 사용하여 학습해 봅시다.

  • implicit 패키지는 이전 스텝에서 설명한 암묵적(implicit) dataset을 사용하는 다양한 모델을 굉장히 빠르게 학습할 수 있는 패키지입니다.
  • 이 패키지에 구현된 als(AlternatingLeastSquares) 모델을 사용하겠습니다. Matrix Factorization에서 쪼개진 두 Feature Matrix를 한꺼번에 훈련하는 것은 잘 수렴하지 않기 때문에, 한쪽을 고정시키고 다른 쪽을 학습하는 방식을 번갈아 수행하는 AlternatingLeastSquares 방식이 효과적인 것으로 알려져 있습니다.

AlternatingLeastSquares 클래스의 __init__ 파라미터를 살펴보겠습니다.

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

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