Bag of Words는 문서에서 등장하는 단어들을 벡터로 변환하는 방식으로, 각 단어의 출현 빈도를 기록하여 문서를 수치적으로 표현한다.
How are you?
에 대한 대답을 벡터로 표현해보자.awesome thank you → [1, 1, 1, 0, 0, 0, 0]
awesome | thank | you | great | not | bad | good |
---|---|---|---|---|---|---|
1 | 1 | 1 | 0 | 0 | 0 | 0 |
great thank you → [0, 1, 1, 1, 0, 0, 0]
awesome | thank | you | great | not | bad | good |
---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 0 | 0 | 0 |
not bad not good → [0, 0, 0, 0, 2, 1, 1]
awesome | thank | you | great | not | bad | good |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 2 | 1 | 1 |
awesome thank you
x great thank you
:great thank you
x not bad not good
:the | man | girl | like | love |
---|---|---|---|---|
2 | 1 | 1 | 1 | 0 |
the | man | girl | like | love |
---|---|---|---|---|
2 | 1 | 1 | 0 | 1 |
the | man | girl | like | love |
---|---|---|---|---|
5 | 0 | 0 | 0 | 0 |
the man like the girl
x the man love the girl
= 6the man like the girl
x the the the the the
= 10단어의 출현 순서를 무시하는 Bag of Words(BoW)의 한계를 극복
machine learning is fun and is not boring
Bag of Words
machine | fun | is | learning | and | not | boring |
---|---|---|---|---|---|---|
1 | 1 | 2 | 1 | 1 | 1 | 1 |
not
의 위치 정보가 무시되면 전혀 다른 문장의 유사도가 높게 나올 수 있음machine learning is fun and is not boring
machine learning is boring and is not fun
Bag of bigram
machine learning | learning is | is fun | fun and | and is | is not | not boring |
---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 |
다음에 올 단어 예측
how are you | are you doing | how are they |
---|---|---|
2 | 1 | 1 |
how are
다음에 올 단어는? → you
Spell checker 기능
qu | ua | al | li | it | ty | at | te | er | ui |
---|---|---|---|---|---|---|---|---|---|
3 | 2 | 1 | 1 | 2 | 1 | 1 | 1 | 1 | 1 |
qwal
이라고 오타가 났을 때 → qual
이라고 spell checkBM25는 TF-IDF의 한계를 개선한 정보 검색 모델로, TF-IDF와 비슷하게 단어 빈도와 문서 빈도를 기반으로 하지만, 좀 더 정교한 수식을 사용해 문서와 질의 간의 유사도를 평가한다. 특히, 단어 빈도에 대한 포화 효과와 문서 길이에 대한 보정을 통해 현실적인 검색 결과를 제공한다.
BM25 수식
특징
TF-IDF와 비교하여 BM25는 일반적인 단어가 주는 정보의 양을 더 낮게 평가하여, 검색어가 드문 문서일수록 해당 문서를 더욱 강조한다.
from datasets import load_dataset
dataset = load_dataset("squad_kor_v1")
corpus = list(set([example['context'] for example in dataset['train']]))
len(corpus) # 9606
tokenizer_func = lambda x: x.split(' ') # 띄어쓰기 기준으로 token 나눔
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(tokenizer=tokenizer_func, ngram_range=(1,2)) # unigram, bigram 활용
TfidfVectorizer
: 텍스트 데이터를 TF-IDF 방식으로 벡터화하는 도구로, 단어들의 중요도를 계산한다.tokenizer
: 텍스트를 어떻게 토큰으로 분리할지 정의 (여기서는 띄어쓰기 기준)ngram_range=(1,2)
: unigram과 bigram을 사용하여 벡터화 수행. 즉, 한 단어 및 두 단어가 조합된 형태의 n-gram을 생성한다.vectorizer.fit(corpus) # corpus에 대해 TF-IDF 계산에 필요한 정보(TF, IDF) 학습(fit)
sp_matrix = vectorizer.transform(corpus) # 학습된 vectorizer를 사용하여 corpus를 TF-IDF 벡터로 변환(transform)
sp_matrix.shape # (9606, 1272768)
sp_matrix
: TF-IDF 값을 포함하는 희소 행렬로, 각 문서를 벡터로 변환한 결과. 각 값은 문서 내 단어의 중요도를 나타낸다.import random
import numpy as np
random.seed(1)
sample_idx = random.choice(range(len(dataset['train'])))
query = dataset['train'][sample_idx]['question']
ground_truth = dataset['train'][sample_idx]['context'] # 실제 context가 GT가 된다.
query_vec = vectorizer.transform([query])
query_vec.shape # (1, 1272768)
result = query_vec * sp_matrix.T # query_vector와 context들의 vector와 dot product 수행
result.shape # (1, 9606)
sorted_result = np.argsort(-result.data) # similarity가 높은 순으로 인덱스 정렬
doc_scores = result.data[sorted_result] # 정렬된 similarity score
doc_ids = result.indices[sorted_result] # 정렬된 indicies
k = 3
doc_scores[:k], doc_ids[:k]
> (array([0.18985967, 0.03625019, 0.03371167]),
> array([2232, 3742, 5540], dtype=int32))
print("[Search query]\n", query, "\n")
print("[Ground truth passage]")
print(ground_truth, "\n")
for i in range(k):
print("Top-%d passage with score %.4f" % (i + 1, doc_scores[i]))
doc_id = doc_ids[i]
print(corpus[doc_id], "\n")
[Search query]
호메로스 찬가를 신통기에 비해 간결한 서사로 간주한 사람은 누구인가?
[Ground truth passage]
고전 시대 신화에서는 티탄들의 패배 이후, 신들의 새로운 판테온이 세워졌다고 설명한다. 주요한 그리스 신들 중에서 올림피안은 올림포스 산 정상에서 제우스의 통치 아래 살아가는 신들을 말한다. 이들의 인원이 열두 명으로 제한된 것은 비교적 최근에 도입된 개념으로 보인다. 올림피안 이외에도 그리스인들은 염소 신 판, 강의 정령 님프, 샘에 사는 나이아드, 나무의 정령 드라이어드, 바다에 사는 네레이드, 강의 신, 사티로스를 비롯한 그 지역의 다양한 신들을 숭배하였다. 여기에는 에리니에스(또는 푸리아이)처럼 혈연 관계에게 범죄를 저지른 죄인을 뒤쫓는 저승의 암흑 세력도 있었다. 시인들은 그리스 판테온의 영광을 기리고자 호메로스 찬가를 지었다.(33편의 노래). 그레고리 나지는 호메로스 찬가를 "각 노래마다 신에 대한 기원을 노래하는(《신통기》에 비해) 간결한 서가"로 간주하였다.
Top-1 passage with score 0.1899
고전 시대 신화에서는 티탄들의 패배 이후, 신들의 새로운 판테온이 세워졌다고 설명한다. 주요한 그리스 신들 중에서 올림피안은 올림포스 산 정상에서 제우스의 통치 아래 살아가는 신들을 말한다. 이들의 인원이 열두 명으로 제한된 것은 비교적 최근에 도입된 개념으로 보인다. 올림피안 이외에도 그리스인들은 염소 신 판, 강의 정령 님프, 샘에 사는 나이아드, 나무의 정령 드라이어드, 바다에 사는 네레이드, 강의 신, 사티로스를 비롯한 그 지역의 다양한 신들을 숭배하였다. 여기에는 에리니에스(또는 푸리아이)처럼 혈연 관계에게 범죄를 저지른 죄인을 뒤쫓는 저승의 암흑 세력도 있었다. 시인들은 그리스 판테온의 영광을 기리고자 호메로스 찬가를 지었다.(33편의 노래). 그레고리 나지는 호메로스 찬가를 "각 노래마다 신에 대한 기원을 노래하는(《신통기》에 비해) 간결한 서가"로 간주하였다.
Top-2 passage with score 0.0363
두 사람은 낙담하고, 밴 하우튼의 집을 떠난다. 리더비히는 대신 사과하며 두 사람과 같이 여행을 한다. 세 사람은 안네 프랑크의 집을 방문한다. 집에 계단이 많기 때문에 헤이즐은 힘들게 올라간다. 안네 프랑크의 집 꼭대기에서 헤이즐은 사랑을 느끼고 어거스터스와 로맨틱한 키스를 한다. 두 사람은 호텔로 돌아와 처음으로 밤을 같이 보낸다. 다음날, 어거스터스는 헤이즐에게 자신의 암이 재발했다고 말한다. 인디애나폴리스에 돌아와서 어거스터스의 상태가 더욱 악화되어 갔다. 어거스터스는 중환자실로 보내지며 죽음이 가까운 것을 깨달았다. 어거스터스는 자신의 생전 장례식에 눈 먼 친구 아이작과 헤이즐을 불러 두 사람은 사전에 적은 추도사를 낭독한다. 헤이즐은 밴 하우튼의 소설을 인용하며, 어거스터스와 함께하는 짧은 시간은 무엇과도 바꿀 수 없는 것이라고 말한다.
Top-3 passage with score 0.0337
고대 그리스에서 신화는 일상의 중심이었다. 그리스인들은 신화를 그들의 역사의 일부로 보았다. 그들은 자연 현상과 문화적 변화, 인습적인 증오와 친교를 설명하는데 신화를 사용하였다. 한 지도자가 신화적 영웅, 또는 신의 후손이라는 증거로 사용할 수 있는 자부심의 원천이기도 했다. 《일리아스》와 《오디세이아》에서 설명하는 트로이아 전쟁의 진실에 대해서 의문을 갖는 사람은 거의 없었다. 군사 역사가, 칼럼니스트, 정치 수필가이자 전 고전학 교수인 빅터 데이비스 핸슨과 고전학 부교수 존 히스에 따르면, 그리스인들에게 호메로스 서사시의 심오한 지식은 그들의 문화 변용의 기저로 간주되었다. 호메로스는 "그리스의 학문"(Ἑλλάδος παίδευσις)이었고, 그의 시는 한 권의 "책"이었다.
Sparse Embedding은 검색어와 문서 간의 매칭이 어떻게 이루어지는지 직관적으로 해석할 수 있고, 비교적 빠르고 자원 효율적이기 때문에 대규모의 데이터셋을 다루거나 실시간 검색이 필요한 상황에서 유리하다는 장점이 있다. 하지만 질문에 사용된 용어 기반으로만 문서를 검색하기 때문에 검색어가 포함된 문서만 찾을 수 있으며, 문맥이나 의미를 반영하지 못하는 한계가 존재한다. 이러한 한계를 극복하기 위해, 다음 글에서 설명할 Dense Embedding을 활용할 수 있다. 이는 질문과 문서의 의미적 유사성을 기반으로 검색하므로, 더 정교하고 정확한 검색 결과를 제공한다.