정의
- 사용자가 이전에 구매한 상품 중에서 좋아하는 상품과 유사한 상품을 추천하는 방법
- 협업 필터링(Collaborative Filtering)과 차이점
- 협업 필터링: 유사한 User 혹은 Item을 평점 기반으로 찾아내어 그들을 이용한 추천
- 컨텐츠 기반 모델: 유사한 Item을 Item 자체의 Featrue를 통해 찾아내어 추천
- 협업 필터링(Collaborative Filtering)과 차이점
- 유사한 상품을 어떻게 찾을까?
- 상품을 벡터로 표현 - 도메인마다 다른 방법을 적용
- Text: TD-IDF, Beat, Word2Vec, CounterVectorizer etc
- Image: CNN, ResNet, VGG etc
- 자신을 제외한 나머지 벡터 중 유사한 벡터를 추출(유사도 계산)
- 상품을 벡터로 표현 - 도메인마다 다른 방법을 적용
유사도 함수
- 유클리디안 유사도 (Euclidean Similarity)
Euclidean Similarity = 자
- 장점
- 계산하기 쉬움
- 단점
- 와 의 scale이나 분포가 다른 경우 상관성을 놓치기 쉬움
- 코사인 유사도 (Cosine Similarity)
- 장점
- Scale의 영향을 받지 않음
- 즉, 문서 내에서 단어의 빈도 수를 벡터화한 경우, 문서들의 길이기 고르지 않더라도 각 문서 내에서의 단어 출현 비중을 확인하기 때문에 가능
- 단점
- 벡터의 크기가 중요한 경우에 대해서 잘 작동하지 않음
- 피어슨 유사도 (Pearson Similarity)
- 피어슨 상관계수를 활용한 유사도 계산
- 1이면 양의 상관관계, -1이면 음의 상관관계, 0이면 독립(정규분포 시)
- 자카드 유사도 (Jaccard Similarity)
- 집합의 개념을 사용 - 합집합과 교집합 사이의 비율
- 즉, 두 집합이 얼마나 많은 아이템을 동시에 갖고 있는가를 수치로 환산
- 교집합이 없으면 0, 모두 같다면 1
- 유사도 계산 예시
- 아래와 같이 4개의 문서(문서1 - 문서4)를 Countvectorizer 처리 가정 (단어빈도 변환)
- 문서1과 문서2의 유사도를 계산해보자.
- 유클리디안 유사도
- 코사인 유사도
- 피어슨 유사도
- 자카드 유사도
Represented Items
- Item을 벡터 형태로 표현 - 도메인마다 다른 방법을 적용
Item의 벡터화 (Item이 Text인 경우)
- TF-IDF (Term Frequency - Inverse Document Frequency)
- 정의
- TF-IDF는 특정 문서 내에 특정 단어가 얼마나 자주 등장하는지를 의미하는 단어 빈도(TF)와 전체 문서에서 해당 특정 단어를 포함한 문서가 얼마나 있는지를 의미하는 역문서 빈도(IDF) 사용
- 여기서, 역문서 빈도는 다른 문서에도 자주 등장한다면 해당 단어에 대한 가중치를 줄여주는 역할
- “다른 문서에서는 등장하지 않은 단어지만, 해당 문서에서만 자주 등장하는 단어”를 찾아 문서 내 단어의 가중치 계산 방법
- 용도로는 문서의 핵심어 추출, 문서 간 유사도 계산, 검색 결과의 중요도 설정 작업 등에 활용 가
- 계산 방법
- TF-IDF를 사용하는 이유
- Item이라는 컨텐츠를 벡터로 변환하는 Feature Extract 과정 수행
- 빈도수를 기반으로 많이 등장하는 중요한 단어들을 선택. 이러한 방법을 Counter Vectorizer라고 부른다.
- 하지만, Counter Vectorizer는 단순 빈도만을 계산하기 때문에, 위 예시의 경우처럼 I, movie, this, like와 같은 조사, 관사처럼 의미는 없지만 문장에 많이 등장하는 단어들을 중요하게 여기는 한계가 존재한다.
- TF-IDF는 위 예시에서 I, movie, this, like와 같은 단어는 DF가 2이므로 IDF()의 가중치를, best, worst와 같은 단어는 DF가 1이므로 IDF()의 가중치를 준다.
- 이처럼 TF-IDF는 의미는 없지만 모든 문장에서 많이 등장하는 조사, 관사 등 중요하지 않은 단어는 필터링하고, 중요한 단어만 잡아내는 기법이다.
- TF-IDF 예시
- 아래와 같이 4개의 문서가 존재한다고 하자.
문서 내용 1 먹고 싶은 사과 2 먹고 싶은 바나나 3 길고 노란 바나나 바나나 4 저는 과일이 좋아요
- 위 4개 문서를 Counter Vectorizer를 통해 벡터화한 결과는 아래와 같다. (TF)
문서 과일이 길고 노란 먹고 바나나 사과 싶은 저는 좋아요 1 0 0 0 1 0 1 1 0 0 2 0 0 0 1 1 0 1 0 0 3 0 1 1 0 2 0 0 0 0 4 1 0 0 0 0 0 0 1 1 - 문서 빈도 (DF)는 다음과 같다(바나나는 전체 문서 중 2개 문서에서 등장했다).
과일이 길고 노란 먹고 바나나 사과 싶은 저는 좋아요 총합 1 1 1 2 2 1 2 1 1 - 역문서 빈도(IDF)를 계산하는 아래의 공식과, 각 단어의 역문서 빈도는 다음과 같다. ()
단어() 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 값은 다음과 같다.
문서 과일이 길고 노란 먹고 바나나 사과 싶은 저는 좋아요 1 0 0 0 0.288 0 0.693 0.288 0 0 2 0 0 0 0.288 0.288 0 0.288 0 0 3 0 0.693 0.693 0 0.575 0 0 0 0 4 0.693 0 0 0 0 0 0 0.693 0.693 - 이를 이용해 문서1과 문서2의 유사도를 계산하면 다음과 같다(코사인 유사도 사용)
-
- 아래와 같이 4개의 문서가 존재한다고 하자.
- TF-IDF의 장점
- 직관적인 해석이 가능
- TF-IDF의 단점
- 대규모 말뭉치를 다룰 때 메모리상의 문제 발생
- 높은 차원을 가짐
- 매우 sparse한 형태의 데이터
- 예를 들어, 100권의 문서가 있고 1권 당 30,000개의 단어가 등장한다면 최대 (100x3,000,000)의 행렬이 생성됨
- 대규모 말뭉치를 다룰 때 메모리상의 문제 발생
- 정의
- Word2Vec
- TF-IDF 기반 방법은 다음과 같은 문제점을 가짐
- 대규모 말뭉치를 다룰 때 메모리상의 문제
- 높은 차원을 가지고 매우 sparse한 형태의 데이터
- 만약 100만 개의 문서를 다루는 경우, 100만 개 문서에 등장한 모든 단어를 추출해야 하며 이때, 1문서 당 새로운 단어가 10개씩 등장한다면, 1000만 개의 말뭉치가 형성 (100만 x 1000만 matrix)
- 한 번에 학습 데이터 전체를 사용함
- 큰 작업을 처리하기 어려움
- GPU와 같은 병렬처리를 기대하기 힘듦
- 학습을 통해서 결과 개선을 할 수 없음
- 대규모 말뭉치를 다룰 때 메모리상의 문제
⇒ 단어 벡터 간 유의미한 유사도를 반영하면서 위 3가지 문제점을 개선한 방법 → Word2Vec
- 정의
- 단어 간 유사도를 반영하여 단어를 벡터로 바꾸는 임베딩 방법
- 원-핫 벡터 형태의 sparse matrix가 갖는 단점을 해소하고자, 저차원 공간의 벡터로 mapping
- 가정: 비슷한 문맥에서 등장하는 단어들은 비슷한 의미를 갖는다.
- 저차원에 학습된 단어의 의미를 분산하여 표현하기 때문에 단어 간 유사도 계산 가능
- 추론 기반의 방법이란?
- 주변 단어(맥락)이 주어졌을 때, “?”에 어떤 단어(중심 단어)가 들어가는지를 추측하는 작업
- 방법론은 크게 2가지 존재
- CBOW: 주변에 있는 단어로 중간에 있는 단어를 예측하는 방법
- Skip-Gram: 중간에 있는 단어로 주변 단어를 예측하는 방법
- TF-IDF 기반 방법은 다음과 같은 문제점을 가짐
- CBOW
- 입력으로 주변 단어의 원-핫 벡터를, 정답으로 중심 단어의 원-핫 벡터를 사용
- you → [Say] 예측 & goodbye → [Say] 예측
- window_size로 주변 단어 개수가 달라짐
- 만약 window size = 2라면, you, goodbye, and로 각각 Say 예측
- 중간 은 사용자가 지정한 Embedding_size에 맞도록 shape가 정해짐(여기서는
Embedding_size=3
이므로input_size x Embedding_size
=)- 각 입력에 대해 hidden state를 계산 ( , )
- window size로 정해진 입력 개수만큼 결과를 평균 ( 여기서는 )이 은닉층의 결과값
- 과 hidden state 를 곱해 출력값 계산 ( [(1x3) (3x7)] )
- 출력값 에 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 계산 후, 역전파 진행
- 위 과정을 다른 문맥에 대해서도 수행
- 입력으로 주변 단어의 원-핫 벡터를, 정답으로 중심 단어의 원-핫 벡터를 사용
- Skip-gram
- CBOW와 알고리즘 상 거의 동일하나, Input을 하나로 받고 Output이 2개가 되는 구조
- 즉, 중심 단어로 주변 단어를 예측
- 입력으로 중심 단어의 원-핫 벡터를, 정답으로 주변 단어의 원-핫 벡터를 사용
- [Say] → [you] 예측 & [Say] → [goodbye] 예측
- 만약 window size = 2라면, [Say]를 통해 you, goodbye, and로 예측
- 중간 은 사용자가 지정한 Embedding_size에 맞도록 shape가 정해짐(여기서는 )
- 입력(중심 단어)에 대해 hidden state를 계산 ( )
- hidden state 를 과 곱해서 Score 추출
-
- Score에 Softmax를 취해서 각 단어가 나올 확률을 계산
-
-
- 각 주변 단어에 대한 Loss를 합한 뒤 역전파
-
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
- 위 과정을 다른 문맥에 대해서도 수행
- 일반적으로, CBOW보다 Skip-Gram이 성능이 좋다고 알려져 있음
컨텐츠 기반 모델의 장단점
- 장점
- 협업필터링은 다른 사용자들의 평점이 필요한 반면, 자신의 평점만으로 추천시스템을 만들 수 있음
- Item의 feature를 통해서 추천을 하기 때문에 추천한 이유를 설명하기 용이함
- 사용자가 평점을 매기지 않은 새로운 Item이 들어오는 경우에도 추천 가능
- 단점
- Item의 Feature를 추출해야 하고, 이를 통해 추천하기 때문에 제대로 feature를 추출하지 못하면 정확도가 낮음
- 따라서, Domain Kwowledge가 분석시에 필요할 수도 있음
- 기존의 item과 유사한 item 위주로만 추천하기에 새로운 장르의 item을 추천하기 어려움
- 새로운 사용자에 대해서 충분한 평점이 쌓이기 전까지 추천하기 힘듦