타임트리

컨텐츠 기반 모델 본문

추천시스템

컨텐츠 기반 모델

sean_j 2023. 3. 9. 03:32

정의

  • 사용자가 이전에 구매한 상품 중에서 좋아하는 상품과 유사한 상품을 추천하는 방법
    • 협업 필터링(Collaborative Filtering)과 차이점
      • 협업 필터링: 유사한 User 혹은 Item을 평점 기반으로 찾아내어 그들을 이용한 추천
      • 컨텐츠 기반 모델: 유사한 Item을 Item 자체의 Featrue를 통해 찾아내어 추천

  • 유사한 상품을 어떻게 찾을까?
    1. 상품을 벡터로 표현 - 도메인마다 다른 방법을 적용
      • Text: TD-IDF, Beat, Word2Vec, CounterVectorizer etc
      • Image: CNN, ResNet, VGG etc
    1. 자신을 제외한 나머지 벡터 중 유사한 벡터를 추출(유사도 계산)

유사도 함수

  1. 유클리디안 유사도 (Euclidean Similarity)

Euclidean Similarity = 1xy+ϵ,    wherexy=i(xiyi)2\frac{1}{|| \bold{x} -\bold{y}||+ \epsilon},~~~~where ||\bold{x}-\bold{y}|| = \sqrt{\sum_i{(x_i-y_i)^2}}

  • 장점
    • 계산하기 쉬움
  • 단점
    • x\bold{x}y\bold{y}의 scale이나 분포가 다른 경우 상관성을 놓치기 쉬움

  1. 코사인 유사도 (Cosine Similarity)

cos(θ)=xyxy=ixiyiixi2 iyi2cos(\theta)=\frac{\bold{x}\cdot\bold{y}}{||\bold{x}|| ||\bold{y}||} = \frac{\sum_i{x_i y_i}}{\sqrt{\sum_i{{x_i}^2}} ~ \sqrt{\sum_i{{y_i}^2}}}

  • 장점
    • Scale의 영향을 받지 않음
    • 즉, 문서 내에서 단어의 빈도 수를 벡터화한 경우, 문서들의 길이기 고르지 않더라도 각 문서 내에서의 단어 출현 비중을 확인하기 때문에 가능
  • 단점
    • 벡터의 크기가 중요한 경우에 대해서 잘 작동하지 않음

  1. 피어슨 유사도 (Pearson Similarity)
    • 피어슨 상관계수를 활용한 유사도 계산
    • 1이면 양의 상관관계, -1이면 음의 상관관계, 0이면 독립(정규분포 시)

    rxy=i(xix)(yiy)i(xix)2i(yiy)2r_{xy} = \frac{\sum_{i} (x_{i} - \overline{x}) (y_{i} - \overline{y})}{\sqrt{\sum_{i} (x_{i} - \overline{x})^2}\sqrt{\sum_{i} (y_{i} - \overline{y})^2}}

  1. 자카드 유사도 (Jaccard Similarity)
    • 집합의 개념을 사용 - 합집합과 교집합 사이의 비율
    • 즉, 두 집합이 얼마나 많은 아이템을 동시에 갖고 있는가를 수치로 환산
    • 교집합이 없으면 0, 모두 같다면 1

    J(X,Y)=ABAB=ABA+BAB,   A:# of elements in set AJ(X,Y)=\frac{|A\cap B|}{|A\cup B|}=\frac{|A \cap B|}{|A|+|B|-|A\cap B|},~~~ |A|: \#~of~elements ~in~set~A

  • 유사도 계산 예시
    • 아래와 같이 4개의 문서(문서1 - 문서4)를 Countvectorizer 처리 가정 (단어빈도 변환)
    • 문서1과 문서2의 유사도를 계산해보자.
    1. 유클리디안 유사도

      112+12+1e05=0.707\frac{1}{\sqrt{1^2+1^2} + 1e-05}=0.707

    1. 코사인 유사도

      ixiyiixi2iyi2=1+11+1+11+1+1=2/3=0.667\frac{\sum_i{x_i y_i}}{\sqrt{\sum_i{x_i^2}} \sqrt{\sum_i{y_i^2}}} =\frac{1+1}{\sqrt{1+1+1} \cdot \sqrt{1+1+1}} = 2/3=0.667

    1. 피어슨 유사도

      i(xix)(yiy)i(xix)2i(yiy)2=19+19+19+492929+49+19+19(619+349)(619+349)=1/2\frac{\sum_i{(x_i-\overline{x})(y_i-\overline{y})}} {\sum_i{(x_i-\overline{x})^2} \sum_i{(y_i-\overline{y})^2}}=\frac{\frac{1}{9} + \frac{1}{9}+ \frac{1}{9}+\frac{4}{9}-\frac{2}{9}-\frac{2}{9}+\frac{4}{9}+\frac{1}{9}+\frac{1}{9}}{\sqrt{(6\cdot\frac{1}{9}+3\cdot\frac{4}{9})} \cdot \sqrt{(6\cdot\frac{1}{9}+3\cdot\frac{4}{9})}} = 1/2

    1. 자카드 유사도

      ABAB=ABA+BAB=23+32=1/2\frac{|A\cap B|}{|A\cup B|} = \frac{|A\cap B|}{|A|+|B|-|A\cap B|}=\frac{2}{3+3-2} = 1/2

Represented Items

  • Item을 벡터 형태로 표현 - 도메인마다 다른 방법을 적용

Item의 벡터화 (Item이 Text인 경우)

  1. TF-IDF (Term Frequency - Inverse Document Frequency)
    • 정의
      • TF-IDF는 특정 문서 내에 특정 단어가 얼마나 자주 등장하는지를 의미하는 단어 빈도(TF)와 전체 문서에서 해당 특정 단어를 포함한 문서가 얼마나 있는지를 의미하는 역문서 빈도(IDF) 사용
      • 여기서, 역문서 빈도는 다른 문서에도 자주 등장한다면 해당 단어에 대한 가중치를 줄여주는 역할
      • “다른 문서에서는 등장하지 않은 단어지만, 해당 문서에서만 자주 등장하는 단어”를 찾아 문서 내 단어의 가중치 계산 방법
      • 용도로는 문서의 핵심어 추출, 문서 간 유사도 계산, 검색 결과의 중요도 설정 작업 등에 활용 가

    • 계산 방법

    • TF-IDF를 사용하는 이유

    1. Item이라는 컨텐츠를 벡터로 변환하는 Feature Extract 과정 수행
    1. 빈도수를 기반으로 많이 등장하는 중요한 단어들을 선택. 이러한 방법을 Counter Vectorizer라고 부른다.
    1. 하지만, Counter Vectorizer 단순 빈도만을 계산하기 때문에, 위 예시의 경우처럼 I, movie, this, like와 같은 조사, 관사처럼 의미는 없지만 문장에 많이 등장하는 단어들을 중요하게 여기는 한계가 존재한다.
    1. TF-IDF는 위 예시에서 I, movie, this, like와 같은 단어는 DF가 2이므로 IDF(log(21+2)=0.41\log(\frac{2}{1+\bold{2}})=-0.41)의 가중치를, best, worst와 같은 단어는 DF가 1이므로 IDF(log(21+1)=0\log{(\frac{2}{1+\bold{1}})}=0)의 가중치를 준다.
    1. 이처럼 TF-IDF는 의미는 없지만 모든 문장에서 많이 등장하는 조사, 관사 등 중요하지 않은 단어는 필터링하고, 중요한 단어만 잡아내는 기법이다.

    • TF-IDF 예시
      • 아래와 같이 4개의 문서가 존재한다고 하자.
        문서내용
        1먹고 싶은 사과
        2먹고 싶은 바나나
        3길고 노란 바나나 바나나
        4저는 과일이 좋아요
      • 위 4개 문서를 Counter Vectorizer를 통해 벡터화한 결과는 아래와 같다. (TF)
      문서과일이길고노란먹고바나나사과싶은저는좋아요
      1000101100
      2000110100
      3011020000
      4100000011
      • 문서 빈도 (DF)는 다음과 같다(바나나는 전체 문서 중 2개 문서에서 등장했다).
      과일이길고노란먹고바나나사과싶은저는좋아요
      총합111221211
      • 역문서 빈도(IDF)를 계산하는 아래의 공식과, 각 단어의 역문서 빈도는 다음과 같다. (n=4n=4)

        idf(t)=log(n1+df(t))idf(t)=\log{(\frac{n}{1+df(t)})}

        단어(tt)IDF
        과일이ln(4/(1+1)) = 0.693
        길고ln(4/(1+1)) = 0.693
        노란ln(4/(1+1)) = 0.693
        먹고ln(4/(1+2)) = 0.288
        바나나ln(4/(1+2)) = 0.288
        사과ln(4/(1+1)) = 0.693
        싶은ln(4/(1+2)) = 0.288
        저는ln(4/(1+1)) = 0.693
        좋아요ln(4/(1+1)) = 0.693
      • 따라서, 각 단어의 TF-IDF 값은 다음과 같다.
      문서과일이길고노란먹고바나나사과싶은저는좋아요
      10000.28800.6930.28800
      20000.2880.28800.28800
      300.6930.69300.5750000
      40.6930000000.6930.693

      • 이를 이용해 문서1과 문서2의 유사도를 계산하면 다음과 같다(코사인 유사도 사용)
        • cos(θ)=ABAB=0.2882+ 0.28820.2882+0.6932+0.28820.2882+0.2882+0.2882=0.413 \cos(\theta) = \frac{A\cdot B}{||A||\cdot||B||}=\frac{0.288^2+~ 0.288^2}{\sqrt{0.288^2+0.693^2+0.288^2} \cdot \sqrt{0.288^2+0.288^2+0.288^2}}=0.413 

    • TF-IDF의 장점
      • 직관적인 해석이 가능
    • TF-IDF의 단점
      • 대규모 말뭉치를 다룰 때 메모리상의 문제 발생
        • 높은 차원을 가짐
        • 매우 sparse한 형태의 데이터
        • 예를 들어, 100권의 문서가 있고 1권 당 30,000개의 단어가 등장한다면 최대 (100x3,000,000)의 행렬이 생성됨

  1. Word2Vec
    • TF-IDF 기반 방법은 다음과 같은 문제점을 가짐
      1. 대규모 말뭉치를 다룰 때 메모리상의 문제
        • 높은 차원을 가지고 매우 sparse한 형태의 데이터
        • 만약 100만 개의 문서를 다루는 경우, 100만 개 문서에 등장한 모든 단어를 추출해야 하며 이때, 1문서 당 새로운 단어가 10개씩 등장한다면, 1000만 개의 말뭉치가 형성 (100만 x 1000만 matrix)
      1. 한 번에 학습 데이터 전체를 사용함
        • 큰 작업을 처리하기 어려움
        • GPU와 같은 병렬처리를 기대하기 힘듦
      1. 학습을 통해서 결과 개선을 할 수 없음

    ⇒ 단어 벡터 간 유의미한 유사도를 반영하면서 위 3가지 문제점을 개선한 방법 → Word2Vec

    • 정의
      • 단어 간 유사도를 반영하여 단어를 벡터로 바꾸는 임베딩 방법
      • 원-핫 벡터 형태의 sparse matrix가 갖는 단점을 해소하고자, 저차원 공간의 벡터로 mapping
      • 가정: 비슷한 문맥에서 등장하는 단어들은 비슷한 의미를 갖는다.
      • 저차원에 학습된 단어의 의미를 분산하여 표현하기 때문에 단어 간 유사도 계산 가능

    • 추론 기반의 방법이란?
      • 주변 단어(맥락)이 주어졌을 때, “?”에 어떤 단어(중심 단어)가 들어가는지를 추측하는 작업

    • 방법론은 크게 2가지 존재
      1. CBOW: 주변에 있는 단어로 중간에 있는 단어를 예측하는 방법
      1. Skip-Gram: 중간에 있는 단어로 주변 단어를 예측하는 방법

  1. CBOW
    1. 입력으로 주변 단어의 원-핫 벡터를, 정답으로 중심 단어의 원-핫 벡터를 사용
      • you → [Say] 예측 & goodbye → [Say] 예측
      • window_size로 주변 단어 개수가 달라짐
      • 만약 window size = 2라면, you, goodbye, and로 각각 Say 예측
    1. 중간 WinW_{in}은 사용자가 지정한 Embedding_size에 맞도록 shape가 정해짐(여기서는 Embedding_size=3이므로 input_size x Embedding_size=7×37\times3)
      • 각 입력에 대해 hidden state를 계산 ( h1h_1, h2h_2 )
      • window size로 정해진 입력 개수만큼 결과를 평균 ( 여기서는 h=(h1+h2)2h =\frac{(h_1 + h_2)}{2} )이 은닉층의 결과값
    1. WoutW_{out}과 hidden state hh를 곱해 출력값 yy 계산 ( hWouth\cdot W_{out} [(1x3) \cdot (3x7)] )
    1. 출력값 yy에 Softmax 활성화 함수를 취해 각 단어가 중심 단어일 확률을 계산하고 정답(중심 단어)의 원-핫 벡터와 비교하여 Cross Entropy Loss 계산 후 파라미터 갱신
    # 입력값은 원-핫 벡터 형태 (중심단어는 index=1)
    input1 = np.array([1, 0, 0, 0, 0, 0, 0])
    input2 = np.array([0, 0, 1, 0, 0, 0, 0])
    
    # (입력 x 임베딩 차원) - Embedding_size는 사용자 정의 - 여기서는 3으로 설정
    W_in = np.random.randn(7, 3)
    
    # hidden_state 계산 (hidden state shape: 1x3)
    h1 = np.matmul(input1, W_in)
    h2 = np.matmul(input2, W_in)
    
    hidden_state = (h1 + h2) / 2
    
    # input_size로 원복하여 score 계산 및 각 단어가 나올 확률 계산
    W_out = np.random.randn(3, 7)
    
    score = np.matmul(hidden_state , W_out)
    
    pred = softmax(score)
    
    # 이후 Categorical Cross Entropy Loss 계산 후, 역전파 진행
    1. 위 과정을 다른 문맥에 대해서도 수행

  1. Skip-gram
    • CBOW와 알고리즘 상 거의 동일하나, Input을 하나로 받고 Output이 2개가 되는 구조
    • 즉, 중심 단어로 주변 단어를 예측

  1. 입력으로 중심 단어의 원-핫 벡터를, 정답으로 주변 단어의 원-핫 벡터를 사용
    • [Say] → [you] 예측 & [Say] → [goodbye] 예측
    • 만약 window size = 2라면, [Say]를 통해 you, goodbye, and로 예측
  1. 중간 WinW_{in}은 사용자가 지정한 Embedding_size에 맞도록 shape가 정해짐(여기서는 7×37\times3)
    • 입력(중심 단어)에 대해 hidden state를 계산 ( hh )
  1. hidden state hhWoutW_{out}과 곱해서 Score 추출
    • hWout=s1,  hWout=s2h\cdot W_{out} = s_1, ~~h\cdot W_{out} = s_2
  1. Score에 Softmax를 취해서 각 단어가 나올 확률을 계산
    • softmax(s1)softmax(s_1)
    • softmax(s2)softmax(s_2)
  1. 각 주변 단어에 대한 Loss를 합한 뒤 역전파
    • Loss=Loss1+Loss2Loss = Loss_1 + Loss_2
input1 = np.array([0, 1, 0, 0, 0, 0, 0])
output1 = np.array([1, 0, 0, 0, 0, 0, 0])
output2 = np.array([0, 0, 1, 0, 0, 0, 0])

# (input_size x Embedding_size) weights
W_in = np.random.randn(7, 3)

# hidden state
h = np.matmul(input1, W_in)  # shape = (1, 3)

# input_size로 원복하여 예측
W_out = np.random.randn(3, 7)

score = np.matmul(h, W_out)

pred = softmax(score)


# output이 2개이므로 각각에 대한 loss 계산 후 미분값을 **더해서** 진행
loss1 = categorical_crossentropy(pred, output1)
loss2 = categorical_crossentropy(pred, output2)

# 역전파 과정 (categorical cross entropy의 미분은 prediction - true)
ds1 = (pred - output1)
ds2 = (pred - output2)
ds = ds1 + ds2

  1. 위 과정을 다른 문맥에 대해서도 수행

  • 일반적으로, CBOW보다 Skip-Gram이 성능이 좋다고 알려져 있음

컨텐츠 기반 모델의 장단점

  • 장점
    • 협업필터링은 다른 사용자들의 평점이 필요한 반면, 자신의 평점만으로 추천시스템을 만들 수 있음
    • Item의 feature를 통해서 추천을 하기 때문에 추천한 이유를 설명하기 용이함
    • 사용자가 평점을 매기지 않은 새로운 Item이 들어오는 경우에도 추천 가능
  • 단점
    • Item의 Feature를 추출해야 하고, 이를 통해 추천하기 때문에 제대로 feature를 추출하지 못하면 정확도가 낮음
    • 따라서, Domain Kwowledge가 분석시에 필요할 수도 있음
    • 기존의 item과 유사한 item 위주로만 추천하기에 새로운 장르의 item을 추천하기 어려움
    • 새로운 사용자에 대해서 충분한 평점이 쌓이기 전까지 추천하기 힘듦

'추천시스템' 카테고리의 다른 글

추천시스템의 평가함수  (1) 2023.03.15
협업 필터링(KNN, SGD, ALS)  (0) 2023.03.13