- DB 설계하기
- DB 구축하기
1.1. 데이터 수집하기
1.1.1. arXive dataset(YJ)
1.1.2. pub-med dataset(YH)
1.1.3. kaggle dataset(YJ)
1.1.4. Covid19 dataset(HJ)
1.2. 데이터 정제하기
1.2.1. arXive dataset(YJ)
1.2.2. pub-med dataset(YH)
1.2.3. kaggle dataset(YJ)
1.2.4. Covid19 dataset(HJ)
1.3. 데이터 문장 단위로 나누기(YJ)
1.3.1. 데이터 의미 단위로 나누기(YJ)
1.4. 문장 단위로 나뉜 데이터 테이블로 저장(YJ)- 사용자로부터 쿼리 입력받기
2.1. 웹/카카오톡 인터페이스 설계 및 구현(SH, YH, HJ, YJ)
2.2. 사용자의 쿼리에서 키워드 추출하기(YJ)- DB 검색하기
3.1. 키워드 유사어 5개 포함 데이터 검색하기(YJ)
3.2. 임베딩 결과 유사도 검색하기(YH, HJ)- 사용자에게 검색 결과 웹/카카오톡으로 보여주기(SH, YH, HJ, YJ)
오늘 포스팅의 주제가 1.2.1. arXive dataset 데이터 정제와 1.3.1. 데이터 의미 단위로 나누기 두 가지이다.
arXive dataset 중에 valid 데이터셋만을 사용했다.
이 데이터를 전처리한 전후 비교 사진이다.
Before
After
바뀐 점은 다음과 같다.
<S>,[,],')import pandas as pd
import re
df = pd.read_csv('/content/drive/MyDrive/koala_common/data3val.csv')
# 데이터프레임의 모든 텍스트에서 '[]<>' 문자 제거
df.replace(to_replace=r'[\'\[\],]', value='', regex=True, inplace=True)
# 첫 번째 열 제거
df.drop('Unnamed: 0', axis=1, inplace=True)
# 중복 id 제거
df = df.drop_duplicates(subset='article_id')
# 'abstract_text' 열의 모든 행에서 맨 앞 2글자 제거
df['abstract_text'] = df['abstract_text'].apply(lambda x: x[2:])
# 결과 출력
print(df.head(3))
이전 포스팅에서 논문 full text를 문장 단위로 잘라 article id와 함께 sentences 테이블에 저장했다. 이는 논문 레퍼런스를 검색할 때 논문 전체 내용뿐아니라 일부만를 활용하는 경우도 꽤 많기 때문이다.

이렇게 저장했을 때 명확한 한계가 있다. 문장만 보아서는 정보가 제한되기 때문이다. 이 문장의 경우 '~~는 그 예시이다.'라고 말하고 있는데, 앞 내용과 연결되는 것을 유추할 수 있다. 이럴 경우 앞문장과 현 문장을 이어서 저장하는 것이 더욱 효율적이고, 많은 정보를 보존할 수 있다.
이 작업을 하기 위해 의미 유사도 분석을 활용했다. SBERT를 활용해 전체 문서를 임베딩한 뒤 앞뒤 문장과 코사인 유사도를 계산하였다. 이렇게 하면 현 문장이 앞문장과 연관이 되어있고, 그 앞문장과도 연관이 되어있고... 했을 때 다 하나의 덩어리로 묶어줄 수 있게 된다.
물론 '연관이 있다'라고 볼 수 있는 기준이 무엇인가? 하는 문제가 남아있다. 좀 더 실용적으로 표현하면 '임계치를 어떻게 설정해야 하는가?'의 문제이다. 단순무식하게 0.5로 설정해 줄 수도 있을 것이다. 가장 적은 비용으로 해결하는 방법이다. 만일 'Top N 정확도' 평가지표에 따라 성능이 괜찮게 나온다면 그대로 결론지으면 된다. 여전히 성능 개선이 없으면 다음으로 해야할 일은 수작업 라벨링이다.
수작업 라벨링부터는 골치가 아파진다. 일정한 품질로 라벨링을 해야하고, 라벨링을 할 사람도 선정해야 하며 가이드라인도 제공해야 한다. 기간 안에 되려면 데이터 라벨링 대행이 필요할 것 같다. 💸
from sentence_transformers import SentenceTransformer, util
import pandas as pd
from tqdm.auto import tqdm
tqdm.pandas()
# SBERT 모델 로드
model = SentenceTransformer('all-MiniLM-L6-v2')
# 문장 임베딩 및 유사도 계산 함수
def process_row(row):
document = row['article_text']
sentences = document.strip().split('.')
article_id = row['article_id']
# 모든 문장을 한 번에 임베딩
embeddings = model.encode(sentences, convert_to_tensor=True)
row_data = []
for i in range(len(embeddings) - 1):
# 인접한 문장 쌍의 유사도 계산
similarity = util.pytorch_cos_sim(embeddings[i], embeddings[i+1]).item()
row_data.append((article_id, (i+1, i+2), similarity))
return row_data
# apply()를 사용하여 각 행 처리
data = df.progress_apply(process_row, axis=1)
# 결과 플래트닝
flattened_data = [item for sublist in data for item in sublist]
# 새로운 데이터프레임 생성
df_similarity = pd.DataFrame(flattened_data, columns=['article_id', '문장 쌍', '코사인 유사도'])
# Threshold 설정 및 필터링
threshold = 0.5
high_similarity_pairs = df_similarity[df_similarity['코사인 유사도'] > threshold]
# 결과 출력 및 저장
print("유사도가 높은 문장 쌍:")
print(high_similarity_pairs)
high_similarity_pairs.to_csv('./high_similarity_pairs.csv')
다음 포스팅 예고
임계치 0.5로 했을 때 성능 향상 여부에 대해 다룰 예정이다.