[세션] 자연어 처리

yeji·2025년 1월 13일
1

Python

목록 보기
35/36

텍스트 데이터

  • 전형적인 비정형 데이터 중 하나
  • 전처리를 통해 분석 가능한 형태로 변형해야 함
  • 자연어 처리(Natural Language Processing)를 통해 정형화된 정보를 추출하고 이를 분석에 활용해야 함

임베딩 방법

  • 임베딩 : 자연어를 기계가 이해할 수 있도록 숫자 형태인 벡터로 바꾸는 과정
  • One Hot Encoding
    • 하나의 단어가 하나의 차원(컬럼)이 되는 것
    • 문서에 해당 단어가 있으면 1, 없으면 0
  • Term Frequency(Term Frequency - Inverse Document Frequency)
    • 하나의 단어가 하나의 차원(컬럼)이 되는 것
    • One Hot Encoding과는 달리 단어가 등장한 횟수를 값으로 가지는 벡터를 만듦
    • scikit-learn의 CountVecotrizer 활용
  • TF-IDF (Term Frequency - Inverse Document Frequency)
    • 하나의 단어가 하나의 차원이 됨
    • TF만 따지면 조사나 관사 등 의미없는 단어가 자주 등장할 가능성이 큼
    • 공통된 문서에서 자주 등장하는 단어는 페널티를 줘서 중요도를 낮추는 방법
      • tf(w): 단어 w의 Term Frequency / df(w): 단어 w의 Document Frequency / N: 총 문서의 개수
    • scikit-learn의 TfidfVectorizer 활용
  • Word Embedding
    • 빈도 기반으로 단어를 벡터화하면 단어와 단어 사이의 관계, 문맥 등을 반영하기 어려움
    • 연관성 있는 단어를 가까운 곳에, 연관성이 떨어지는 단어를 먼 곳에 위치하게 벡터화를 하면 단어 사이 연관성을 파악하기 수월해짐
    • 특정 문장에서 단어의 ‘주변 단어’를 활용하는 Word2Vec 알고리즘 등을 활용하여, 단어를 주어진 차원(하이퍼 파라미터)에 벡터화
      • Skip-gram: 특정 단어가 주어졌을 때 주변 단어를 예측하는 모델(더 많이 씀)
      • C-Bow: 주변 단어가 주어졌을 때 빈 칸의 단어를 예측하는 모델
    • gensim의 word2vec 모델을 사용하여 구현 가능
  • LLM을 활용한 임베딩과 Vector DB
    • ChatGPT와 같은 LLM(Large Language Model)은 수많은 텍스트 데이터를 학습하여 만들어진 결과물
    • 이미 학습된 LLM의 API 호출을 통해 텍스트를 벡터로 변환 가능
    • Vector DB는 벡터 형태 데이터를 효율적으로 다룰 수 있는 DB이며 벡터 형태의 검색 가능

데이터 전처리

  • 문장 정리(Sentence Segmentation)
    • 더 작은 문장 단위로 쪼개는 것
    • 마침표처럼 확실한 구분자를 이용해 구분하는 방식이 있음
    • 분석 대상 언어마다, 글의 속성에 따라 적용할 수 있는 룰이 다름
  • 불필요한 문자 제거(Text Cleaning)
    • 불필요한 텍스트가 포함되어 있는 경우 사전 제거 (ex.ㅋㅋㅋ, 특수문자)
    • 정규 표현식(Regex)를 활용해 간편하게 특정 문자열 제거 가능
  • 토큰화(Tokenization)
    • 문장을 의미있는 단위로 쪼개는 작업으로 전처리의 핵심
    • 영어같은 경우는 띄어쓰기 단위로만 쪼개도 각 토큰이 어느 정도 의미를 가지고 있음
    • 한글의 경우 띄어쓰기에 민감하지 않아 띄어쓰기가 잘 이루어지지 않는 경우도 많을 뿐더러, 띄어쓰기 단위인 ‘어절’로 쪼개도 의미 단위로 쪼개지지 않음
      • 형태소 분석기를 이용해 나뉘어진 토큰은 품사 태그(Part-of-speech, POS) 정보를 포함하고 있어 이를 분석에 활용할 수 있음
    • 영문의 경우 표제어 추출(Lemmatization), 어간 추출(Stemming) 기법 활용
      • 표제어 추출: 기본 사전어 단어로 변환 (ex.am, are , is → be)
      • 어간 추출 : 단어 생성 규칙에 따라 어간만 남기는 방법(ex.numerical → numeric)
  • 불용어 제거(Stopword)

사례

  • 감성 분석
    • 긍정과 부정, 그리고 중립으로 분류하는 분류 문제로 주로 리뷰나 댓글에 적용
    • 단어마다 긍정, 부정, 중립 점수를 부여하는 감성 언어 사전을 구축하여 문장을 scoring하고 분류하는 방법
    • 문장(리뷰)을 벡터화한 뒤 문장의 label을 활용하여 분류 모델을 학습하는 방법
  • 텍스트 자동 분류
    • 카테고리가 명시된 텍스트(문서)에 대해 카테고리를 자동으로 분류하는 분류 모델 생성
    • 대량의 텍스트 데이터를 분류하여 살펴볼 때 유용
    • 라벨링된 문서를 대상으로 분류 모델을 학습하여 자동 분류 모델 생성 가능
  • 텍스트 데이터 클러스터링
    • 텍스트 데이터를 벡터화하고 난 이후 클러스터링 과정은 정형 데이터 분석과 동일함
    • 다만 정형화된 텍스트 데이터는 다른 데이터 대비 차원이 굉장히 큼
    • 유클리디언 거리보다는 코사인 거리를 활용하면 좋은 성능을 기대할 수 있음

코드

# 패키지 설치
!pip install kss konlpy customized_konlpy

# 라이브러리
import re
import pandas as pd
import kss
from konlpy.tag import Okt, Kkma, Komoran
from ckonlpy.tag import Twitter
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer

#warning 메시지 무시
import warnings
warnings.filterwarnings('ignore')

# 실습에 사용할 뉴스 데이터셋 받아오기 (허깅페이스)
splits = {'train': 'train.csv', 'validation': 'validation.csv', 'test': 'test.csv'}
df_news = pd.read_csv("hf://datasets/daekeun-ml/naver-news-summarization-ko/" + splits["train"])

# 리스트로 변경
news_documents = df_news['document'].to_list()

# 확인
news_documents[10]

# kss 패키지를 활용한 문장 분리
kss.split_sentences(news_documents[10])

# Regex를 활용해 영문, 한글, 숫자, 공백, '.'만 남도록 변경
re.sub(r'[^\w\s\.,]', '', news_documents[10])

# 데이터 클리닝 함수
def text_cleaning(text):
    #이메일 주소 제거
    text = re.sub(r'[a-zA-Z0-9._%+-]*@*[a-zA-Z0-9-]+\.(?:com|co\.kr|net)', '', text)

    #날짜 형식 제거 (YYYY.MM.DD)
    text = re.sub(r'\d{4}\.\d{2}\.\d{2}', '', text)

    #대괄호와 내용 제거
    text = re.sub(r'\[.*?\]', '', text)

    #중괄호와 내용 제거
    text = re.sub(r'\{.*?\}', '', text)

    #소괄호와 내용 제거
    text = re.sub(r'\(.*?\)', '', text)

    #특수문자 제거
    # 예: #, $, &, *, ^, @, !, ? 등
    text = re.sub(r'[^\w\s\.,]', '', text)

    #여러 개의 공백을 하나로 변경
    text = re.sub(r'\s+', ' ', text)

    #앞뒤 공백 제거
    text = text.strip()

    return text

# 함수 적용
news_documents_cleaned = [text_cleaning(doc) for doc in news_documents]

# OpenKoreanText 토크나이저 사용 실습
okt = Okt()
sample_doc = news_documents_cleaned[9]
print(sample_doc)

# morphs - 형태소 분석
print(okt.morphs(sample_doc))

#pos - 형태소 분석 결과를 POS 태그와 함께 출력
print(okt.pos(sample_doc))

#pos - 형태소 분석 결과 중에서 명사(Noun)만 출력
print(okt.nouns(sample_doc))

#Customized Konlpy를 이용해 고유명사를 추가하여 형태소 분석 진행 예시
twitter = Twitter() #OpenKoreanText 형태소 분석기의 원형
print(twitter.morphs(sample_doc))

# 변경
twitter.add_dictionary('허준이', 'Noun')
twitter.add_dictionary('고등과학원', 'Noun')
twitter.add_dictionary('수학부', 'Noun')
twitter.add_dictionary('석학교수', 'Noun')
twitter.add_dictionary('과학기술정보통신부', 'Noun')
print(twitter.morphs(sample_doc))

# POS를 활용하여 의미 있는 단어만 선별하는 작업
pos_set = ['Noun', 'Verb', 'Alpha']

def selected_tokenizer(sent, pos = pos_set) :
    t = Okt()
    return [x[0] for x in t.pos(sent) if len(x[0]) > 1 and x[1] in pos]
    
sample_tokens = [selected_tokenizer(x) for x in news_documents_cleaned[:10]]
print(sample_tokens[0])

# stopword 적용
stopwords = ['했습니다', '위해', '하기로', '합니다', '하면서', 'YTN']
sample_cleaned_token = [x for x in sample_tokens[0] if x not in stopwords]
print(sample_cleaned_token)
profile
👋🏻

0개의 댓글