본문 바로가기
TIL _Today I Learned/2024.09

[DAY 51] TF-IDF, Deep Learning 실습

by gamdong2 2024. 9. 26.
[천재교육] 프로젝트 기반 빅데이터 서비스 개발자 양성 과정 9기
학습일 : 2024.09.26

📕 학습 목록

  • TF-IDF
  • Deep Learning 실습(한국어 사투리 분류 시스템 개발)

 

📗 기억할 내용

1. TF-IDF (Term Frequency-Inverse Document Frequency)

1) TF-IDF의 정의 및 목적

  • TF-IDF : 텍스트 데이터에서 특정 단어의 중요도를 평가하기 위한 통계적 수치
  • 이 방법은 정보 검색 시스템, 문서 분류, 자연어 처리(NLP)에서 자주 사용되며, 주어진 문서에서 얼마나 중요한 단어인지 측정하는 데 유용함
  • TF-IDF는 각 문서에서 자주 등장하는 단어에 가중치를 부여하면서, 전체 문서 집합에서 흔히 등장하는 단어는 중요도를 낮추는 방식으로 계산됨

 

2) TF (Term Frequency)

① 정의

  • TF : 특정 문서에서 단어가 얼마나 자주 등장하는지를 측정
  • 단어가 문서 내에서 자주 등장할수록 그 문서에서 중요한 단어일 가능성이 크기 때문에, 빈도수를 기반으로 중요도를 측정

② 계산 공식

 

3) IDF (Inverse Document Frequency)

① 정의

  • IDF : 특정 단어가 전체 문서 집합에서 얼마나 드물게 등장하는지를 나타냄(DF의 역수)
  • 만약 단어가 여러 문서에서 자주 등장하면 그 단어는 중요도가 낮다고 판단함
  • 흔한 단어(예: "the", "is" 등)는 많은 문서에서 등장하기 때문에 상대적으로 낮은 가중치를 갖게됨

② 계산 공식

 

4) TF-IDF 계산

① 정의

  • TF-IDF : 단어의 TF와 IDF를 곱한 값으로, 특정 문서 내에서 해당 단어의 중요도를 측정하는 데 사용
  • TF는 단어가 특정 문서에서 자주 등장할수록 그 문서에서 중요한 단어임을 나타내고, IDF는 전체 문서 집합에서 자주 등장하는 단어일수록 가중치를 줄이는 역할을 함

② 계산 공식

 

5) TF-IDF의 응용

  • TF-IDF는 정보 검색, 문서 분류, 텍스트 마이닝 등 다양한 자연어 처리 작업에서 사용됨
    • 문서 검색: 사용자가 검색어를 입력하면 TF-IDF 값이 높은 단어를 기반으로 문서를 평가하여, 관련성이 높은 문서를 상위에 보여줌
    • 문서 분류: 문서 내에서 중요한 단어들을 추출하여, 이 단어들의 중요도를 기준으로 문서를 분류함
    • 핵심 단어 추출: 문서에서 중요한 키워드를 추출하는 데 사용됨. TF-IDF 값이 높은 단어들은 문서의 핵심 내용을 나타낼 가능성이 높음

 

2. 프로젝트 작업 내역

1) 프로젝트 제목

한국어 방 분류 시스템 개발

 

2) 프로젝트 목표

  • 사용자가 업로드한 텍스트 파일에서 문장 내 특정 단어와 표현을 분석하여 해당 문장이 어느 지역의 방언에 해당하는지 예측

3) 사용한 데이터 셋

  • 오픈 소스(AI Hub) 한국어 방언 발화 데이터

4) 워크플로우

① 데이터 로드 및 전처리

  • load_data 함수: 방언 데이터 폴더에서 CSV 파일을 불러와 문장과 지역 라벨을 저장
import os
import pandas as pd

def load_data(folder_path):
    data = []
    labels = []
    region_labels = {"강원도": 0, "경상도": 1, "전라도": 2, "제주도": 3, "충청도": 4}

    for file_name in os.listdir(folder_path):
        if file_name.endswith('.csv'):
            region_name = file_name.split('.')[0]
            file_path = os.path.join(folder_path, file_name)
            df = pd.read_csv(file_path)
            
            for idx, row in df.iterrows():
                data.append(row['방언'])
                labels.append(region_labels[region_name])
    return data, labels

 

② 문장 임베딩 (KoBERT 사용)

  • embed_sentences 함수: KoBERT 모델을 사용하여 문장을 임베딩 벡터로 변환. 이를 통해 텍스트에서 의미 있는 표현을 추출
from transformers import AutoTokenizer, AutoModel
import torch

tokenizer = AutoTokenizer.from_pretrained('monologg/kobert', trust_remote_code=True)
model = AutoModel.from_pretrained('monologg/kobert', trust_remote_code=True)

def embed_sentences(sentences):
    embeddings = []
    for sentence in sentences:
        inputs = tokenizer(sentence, return_tensors='pt', padding=True, truncation=True)
        with torch.no_grad():
            outputs = model(**inputs)
        cls_embedding = outputs.last_hidden_state[:, 0, :].squeeze().cpu().numpy()
        embeddings.append(cls_embedding)
    return embeddings

 

③ Transformer 기반 분류 모델 구축

  • TransformerDialectClassifier 클래스: KoBERT를 기반으로 하는 분류 모델을 정의하여 방언 지역을 예측할 수 있도록 설계
import torch
import torch.nn as nn
from transformers import BertModel

class TransformerDialectClassifier(nn.Module):
    def __init__(self, num_classes):
        super(TransformerDialectClassifier, self).__init__()
        self.bert = BertModel.from_pretrained('skt/kobert-base-v1')
        self.fc = nn.Linear(768, num_classes)

    def forward(self, input_ids, attention_mask):
        outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
        cls_output = outputs.last_hidden_state[:, 0, :]
        logits = self.fc(cls_output)
        return logits

 

5) 프로젝트 결과

  • 구현 기능
    • 파일 업로드 및 세션 관리: 사용자가 텍스트 파일을 업로드하고, 파일 내용을 세션에 저장하여 방언 분석이 원활하게 이루어지도록 함
    • 방언 분석 및 지역 예측 기능: KoBERT 모델을 통해 문장을 임베딩한 후, Transformer 기반 분류 모델로 방언 지역을 예측

 6) 트러블 슈팅

  • 문제 상황: 초기 모델에서 특정 단어가 부족한 경우 제주도로 예측되는 문제 발생. 이는 제주도 고유 방언 단어가 모델에 강하게 반영되어 예측이 편향된 것으로 판단됨
    • 해결 방법: 지역별 방언 단어 빈도에 따른 가중치를 적용하여 특정 지역에 치우치지 않도록 조정하고 Fine-Tuning을 통해 모델을 최적화
  • 문제 상황: 불용어 처리 시 일반적으로 불용어로 간주되는 부사, 접속사, 감탄사 등을 제거하려 했으나, 방언에서는 이러한 품사가 지역 특유의 말투를 표현하는 중요한 요소가 되기도 함. 단순히 불용어로 처리할 경우 방언의 특색이 손실될 우려가 있어 어려움이 있었음
    • 해결 방법: 방언 특성에 따라 불용어 중에서도 방언의 말투적 특징을 살리는 단어는 유지하고, 의미 없는 단어만 선별적으로 제거하여 방언의 특징을 최대한 보존

7) 프로젝트를 통해 얻은 역량

  • 형태소 분석 및 텍스트 전처리: Konlpy의 형태소 분석기를 활용하여 텍스트 데이터를 처리하고, 이를 기반으로 방언 지역을 분류하는 데 적용
  • KoBERT를 이용한 임베딩 및 딥러닝 모델 구축: KoBERT 모델을 활용하여 문장을 임베딩하고 Transformer 기반의 분류 모델로 방언 분류

 

📘 코드 실습

  •  TF-IDF 계산
# 1. 문서 데이터 준비
docs = [
    '마트 딸기 진짜 비싸다',  # 첫 번째 문서
    '나는 오늘 아침 사과 먹겠다',  # 두 번째 문서
    '아침 사과 금 사과',  # 세 번째 문서
    '나는 오늘 저녁 딸기 먹겠다'  # 네 번째 문서
]

# 2. 문서에 등장하는 단어들의 집합(vocab)을 생성하고 정렬
vocab = list(set([word for doc in docs for word in doc.split()]))  # 각 문서에서 단어를 분리하여 집합(set)으로 만듦
vocab.sort()  # 단어를 알파벳 순으로 정렬

# 3. DTM(Document-Term Matrix) 생성
N = len(docs)  # 문서의 개수 저장
dtm = []  # DTM을 저장할 빈 리스트

# 문서에서 단어의 등장 빈도를 계산하여 DTM에 추가
for doc in docs:  # 각 문서에 대해 반복
    row = []
    for word in vocab:  # 각 단어에 대해 반복
        row.append(doc.split().count(word))  # 해당 문서에서 해당 단어의 빈도를 계산하여 리스트에 추가
    dtm.append(row)  # 각 문서에 대해 계산된 단어 빈도를 DTM 리스트에 추가

# DTM을 DataFrame으로 변환하여 출력
import pandas as pd  # pandas를 사용하여 DataFrame 생성
dtm_df = pd.DataFrame(dtm, columns=vocab)  # DTM을 DataFrame으로 변환
print("Document-Term Matrix (DTM):")  # DTM 출력
print(dtm_df)

# 4. TF(Term Frequency) 계산
def tf(term, doc):
    """문서에서의 단어 빈도(TF)를 계산하는 함수"""
    return doc.split().count(term) / len(doc.split())  # 문서에서 단어의 등장 횟수를 전체 단어 수로 나눔

tf_result = []  # TF 결과를 저장할 리스트
for doc in docs:  # 각 문서에 대해 반복
    row = []
    for word in vocab:  # 각 단어에 대해 반복
        row.append(tf(word, doc))  # TF 계산 후 리스트에 추가
    tf_result.append(row)  # 각 문서에 대한 TF 결과를 리스트에 추가

tf_df = pd.DataFrame(tf_result, columns=vocab)  # TF 결과를 DataFrame으로 변환
print("\nTF (Term Frequency):")  # TF 출력
print(tf_df)

# 5. IDF(Inverse Document Frequency) 계산
import math  # 수학 계산을 위한 math 모듈 사용

def idf(term, docs):
    """역 문서 빈도(IDF)를 계산하는 함수"""
    df = sum([1 for doc in docs if term in doc.split()])  # 해당 단어가 등장한 문서의 수 계산
    return math.log(len(docs) / (df + 1))  # IDF 계산 (로그 함수 사용)

idf_result = []  # IDF 결과를 저장할 리스트
for word in vocab:  # 각 단어에 대해 반복
    idf_result.append(idf(word, docs))  # 각 단어에 대해 IDF를 계산하고 리스트에 추가

idf_df = pd.DataFrame(idf_result, index=vocab, columns=['IDF'])  # IDF 결과를 DataFrame으로 변환
print("\nIDF (Inverse Document Frequency):")  # IDF 출력
print(idf_df)

# 6. TF-IDF 계산
def tf_idf(term, doc, docs):
    """TF와 IDF를 곱하여 TF-IDF 값을 계산하는 함수"""
    return tf(term, doc) * idf(term, docs)  # TF와 IDF의 곱을 계산

tf_idf_result = []  # TF-IDF 결과를 저장할 리스트
for doc in docs:  # 각 문서에 대해 반복
    row = []
    for word in vocab:  # 각 단어에 대해 반복
        row.append(tf_idf(word, doc, docs))  # TF-IDF 계산 후 리스트에 추가
    tf_idf_result.append(row)  # 각 문서에 대한 TF-IDF 결과를 리스트에 추가

tf_idf_df = pd.DataFrame(tf_idf_result, columns=vocab)  # TF-IDF 결과를 DataFrame으로 변환
print("\nTF-IDF:")  # TF-IDF 출력
print(tf_idf_df)

 

- 출력된 DTM

 
- TF-IDF 계산 결과
{'마트': 2, '딸기': 1, '진짜': 9, '비싸다': 4, '나는': 0, '오늘': 7, '아침': 6, '사과': 5, '먹겠다': 3, '저녁': 8}

 

 

📙 내일 일정

  • 텍스트 분류 모델 학습