




question과 context 전처리
#문서들 전처리
doc_list = preprocessing(dataset['context'].tolist()) #기본 전처리
doc_list = mecab_morphs(doc_list) #명사만
doc_list = remove_stop_words(doc_list) # 불용어처리
# 질문들 전처리
q_list = preprocessing(dataset['question'].tolist())
q_list = mecab_morphs(q_list)
q_list, _ = remove_stop_words(doc_list, q_list)
만든 bm25에 적용
# 문서들 fit
bm25 = BM25()
bm25.fit(doc_list) #정제한 문서들
y_hat = [] #bm25 질의에 대한 적합한 문서 예측 리스트
for q_ in q_list:
scores = bm25.search(q_)
y_hat.append(scores.index(max(scores)))
#예측한 문서인덱스를 데이터프레임에 적재
dataset['bm25_y_hat'] = y_hat

tf-idf
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
len(q_list), len(doc_list)
output: (960, 960)
tf-idf는 n-gram을 1~2로 정함
# 사이킷런의 tf-idf default인자에 맞추기위해 재조정
q_list = [','.join(q_).replace(',',' ') for q_ in q_list]
doc_list = [','.join(doc).replace(',',' ') for doc in doc_list]
# q_list와 doc_list 합쳐 fit 한다.
# n-gram은 1~2로 한다.
q_list.extend(doc_list) # 질의와 문서를 학습하기위해 잠시 합쳐놓음
tfidf = TfidfVectorizer(ngram_range=(1,2)).fit(q_list)
len(tfidf.vocabulary_)
output: 82763
tfidf.vocabulary_
output:
{'일본': 58460,
'영유권': 50354,
'주장': 65378,
'당시': 19045,
'김영삼': 14087,
'당대': 18943,
'외교': 51689,
'활동': 81203,
'강력': 4993,
'비꼬': 35741,
'표현': 76462,
'상대': 38528,
'대통령': 20169,
'일본 영유권': 58587,
'영유권 주장': 50355,
'주장 당시': 65418,
'당시 김영삼': 19077,
'김영삼 당대': 14110,
'당대 외교': 18944,
'외교 활동': 51709,
'활동 강력': 81216,
'강력 비꼬': 4997,
'비꼬 표현': 35742,
'표현 상대': 76474,
'상대 대통령': 38547,
...
'상무': 38609,
'광고': 10007,
'통과': 73910,
'시킨': 44683,
...}
tf-idf 벡터를 구한후 question의 matrix와 context의 matrix의 코사인유사도를 구하여 가장 높은 유사도를 y_hat 인덱스로 할당한다.
# q_list와 doc_list 다시 나눈다.
doc_list = q_list[int(len(q_list) / 2):]
q_list = q_list[:int(len(q_list) / 2)]
# 질문 리스트 fit
tfidf_q_list = tfidf.transform(q_list).toarray()
# 문서 리스트 fit
tfidf_doc_list = tfidf.transform(doc_list).toarray()
tfidf_q_list.shape, tfidf_doc_list.shape # -> output: ((960, 82763), (960, 82763))
# 코사인 유사도로 가장 높은 인덱스 추출
sim_matrix = cosine_similarity(tfidf_q_list, tfidf_doc_list)
sim_matrix.shape # -> output: (960, 960)
#idf 질의에 대한 적합한 문서 예측
y_hat = np.zeros((sim_matrix.shape[0]))
for i, q_ in enumerate(sim_matrix):
y_hat[i] = (np.argmax(q_))
#예측한 문서인덱스를 데이터프레임에 적재
dataset['tfidf_y_hat'] = y_hat.astype(int)

print("tf-idf 정확도: ",round(dataset[dataset['y'] == dataset['tfidf_y_hat']].shape[0] /dataset.shape[0], 2))
print("bm25 정확도: ",round(dataset[dataset['y'] == dataset['bm25_y_hat']].shape[0] /dataset.shape[0], 2))
# output:
# tf-idf 정확도: 0.71
# bm25 정확도: 0.7
#TF-IDF 성능 검사
acc = accuracy_score(dataset['tfidf_y_hat'], dataset['y'])
print(acc)
cr = classification_report(dataset['y'], dataset['tfidf_y_hat'])
print(cr)

#BM25 성능 검사
acc = accuracy_score(dataset['bm25_y_hat'], dataset['y'])
print(acc)
cr = classification_report(dataset['y'], dataset['bm25_y_hat'])
print(cr)

https://github.com/lee513/Wiki_Retrieval_BM25/blob/main/TFIDF_BM25.ipynb