[250616월1096H] 자연어 처리 이론 (1) 역사, 전처리, 벡터화, 임베딩

윤승호·2025년 6월 16일

파이토치를 처음 배우던 날이 떠오른 하루다. 무슨 소리인지 하나도 모르겠다. 머신러닝 때 하던 텍스트 전처리와 비슷한 부분도 약간 있는 것 같은데,,, 당분간 힘든 하루가 될 것 같다. 왜 자연어가 어렵다고 하는지 알겠다.

학습시간 09:00~02:00(당일17H/누적H)


◆ 학습내용

요약표

분류기법/도구설명 요약
빈도 기반BoW, TF-IDF단어 빈도 기반 벡터
정적 임베딩Word2Vec, GloVe, FastText단어 간 의미 학습, 문맥 미반영
문맥 임베딩ELMo, BERT, GPT문맥 포함 동적 벡터
최신 임베딩SBERT, SimCSE문장 간 유사도 중심
전처리Cleansing, Tokenizing, BPE텍스트 정제 및 구조화
벡터화CountVectorizer, TfidfVectorizer정형 입력으로 변환
문장 임베딩SentenceTransformer딥러닝 기반 문장 표현

전처리 순서

''' 데이터 로드 '''
# 자연어 데이터를 저장할 때에는 tsv 형식을 많이 사용
# 실무에서는 자연어를 보통 데이터 프레임 형태로 처리
import pandas as pd
df = pd.read_csv('imdb.tsv', delimiter='\\t')
df


''' 대소문자 통합 '''
df['review'] = df['review'].str.lower()
print(df['review'][0])


''' 토큰화 '''
df['word_tokens'] = df['review'].apply(word_tokenize)
print(df['word_tokens'][0])


''' 정제 '''
stopwords_set = set(stopwords.words('english'))
df['cleaned_tokens'] = df['word_tokens'].apply(lambda x: clean_by_freq(x, 1))
df['cleaned_tokens'] = df['cleaned_tokens'].apply(lambda x: clean_by_len(x, 2))
df['cleaned_tokens'] = df['cleaned_tokens'].apply(lambda x: clean_by_stopwords(x, stopwords_set))
print(df['cleaned_tokens'][0])


''' 어간 추출 '''
df['stemmed_tokens'] = df['cleaned_tokens'].apply(stemming_by_porter)
print(df['stemmed_tokens'][0])







''' 데이터 전처리 관련 함수 '''
from collections import Counter
from nltk.stem import PorterStemmer

# 등장 빈도 기준 정제 함수
def clean_by_freq(tokenized_words, cut_off_count):
    # 파이썬의 Counter 모듈을 통해 단어의 빈도수 카운트하여 단어 집합 생성
    vocab = Counter(tokenized_words)
    
    # 빈도수가 cut_off_count 이하인 단어 set 추출
    uncommon_words = {key for key, value in vocab.items() if value <= cut_off_count}
    
    # uncommon_words에 포함되지 않는 단어 리스트 생성
    cleaned_words = [word for word in tokenized_words if word not in uncommon_words]

    return cleaned_words


# 단어 길이 기준 정제 함수
def clean_by_len(tokenized_words, cut_off_length):
    cleaned_by_freq_len = []
    
    for word in tokenized_words:
        if len(word) > cut_off_length:
            cleaned_by_freq_len.append(word)

    return cleaned_by_freq_len
    
    
# 불용어 제거 함수
def clean_by_stopwords(tokenized_words, stop_words_set):
    cleaned_words = []
    
    for word in tokenized_words:
        if word not in stop_words_set:
            cleaned_words.append(word)
            
    return cleaned_words


# 포터 스테머 어간 추출 함수
def stemming_by_porter(tokenized_words):
    porter_stemmer = PorterStemmer()
    porter_stemmed_words = []

    for word in tokenized_words:
        stem = porter_stemmer.stem(word)
        porter_stemmed_words.append(stem)

    return porter_stemmed_words

1. 통계 빈도 기반 시대

(1) TF-IDF

  • 문서 내 단어의 중요도 계산
  • 단어 빈도 × 역문서 빈도
  • 일반 텍스트 분류나 검색 엔진 기초로 사용
from sklearn.feature_extraction.text import TfidfVectorizer

docs = ["I love NLP", "NLP is fun", "I love machine learning"]
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(docs)
print(X.toarray())
print(vectorizer.get_feature_names_out())

(2) BoW (Bag of Words)

  • 단어 순서 무시, 빈도 기반 벡터 생성
  • 간단하지만 문맥 정보 반영 불가
from sklearn.feature_extraction.text import CountVectorizer

vectorizer = CountVectorizer()
X = vectorizer.fit_transform(docs)
print(X.toarray())
print(vectorizer.get_feature_names_out())

2. 정적 단어 임베딩 시대

(1) Word2Vec

  • 단어의 의미를 벡터로 학습
  • 주변 단어 기반으로 중심 단어의 의미 추론
  • CBOW vs Skip-gram 구조 존재
from gensim.models import Word2Vec

sentences = [["I", "love", "NLP"], ["NLP", "is", "fun"]]
model = Word2Vec(sentences, vector_size=50, window=2, min_count=1, sg=1)
print(model.wv["NLP"])  # 'NLP' 단어 벡터 출력

(2) GloVe

  • 단어 동시 등장 행렬 기반 통계 임베딩
  • 공식 라이브러리는 C 기반, glove-python 또는 사전 학습 벡터 활용
# GloVe는 gensim downloader를 통해 불러오는 방식 추천
import gensim.downloader as api

glove_vectors = api.load("glove-wiki-gigaword-50")
print(glove_vectors["king"])  # 'king'의 벡터 출력

(3) FastText

  • 단어를 n-gram 단위로 분해
  • 신조어나 오탈자에 강함
from gensim.models import FastText

model = FastText(sentences, vector_size=50, window=2, min_count=1)
print(model.wv["NLP"])

3. 문맥적 임베딩 시대

(1) ELMo

  • BiLSTM 기반 문맥 학습
  • 토크나이저 수준에서 문맥 따라 벡터 변화
  • TensorFlow 기반, 사용 복잡
# AllenNLP 설치 필요
pip install allennlp

(2) Transformer & Attention

  • Self-Attention으로 문맥 학습
  • 병렬 처리 가능, RNN 대체 구조
  • LLM의 근간 아키텍처
# 핵심 구조만 요약
from transformers import AutoTokenizer, AutoModel

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModel.from_pretrained("bert-base-uncased")

inputs = tokenizer("Hello NLP", return_tensors="pt")
outputs = model(**inputs)
print(outputs.last_hidden_state.shape)

(3) BERT

  • 양방향 Transformer 인코더
  • Masked LM으로 사전학습 → 파인튜닝
from transformers import BertTokenizer, BertModel

tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
model = BertModel.from_pretrained("bert-base-uncased")

inputs = tokenizer("Natural language processing", return_tensors="pt")
outputs = model(**inputs)
print(outputs.last_hidden_state)

(4) GPT

  • Transformer Decoder 기반
  • 다음 단어 예측 방식, 생성형 모델
from transformers import GPT2Tokenizer, GPT2Model

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2Model.from_pretrained("gpt2")

inputs = tokenizer("I love natural", return_tensors="pt")
outputs = model(**inputs)
print(outputs.last_hidden_state)

4. 최신 문장 임베딩 시대

(1) Sentence-BERT

  • Siamese 구조
  • 문장 쌍 입력 → 유사도 학습
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('all-MiniLM-L6-v2')
embeddings = model.encode(["This is a sentence", "That is another one"])

(2) SimCSE

  • 동일 문장에 dropout 두 번 적용하여 contrastive 학습
  • 비지도임에도 우수한 성능
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('princeton-nlp/sup-simcse-bert-base-uncased')
embeddings = model.encode(["This is a test", "This is a test too"])

5. 텍스트 전처리

(1) 토큰화

text = "I love natural language processing."
tokens = text.split()
print(tokens)

(2) 텍스트 클렌징

import re
text = "NLP is fun!! @@@"
clean_text = re.sub(r'[^a-zA-Z\s]', '', text)
print(clean_text)

(3) 형태소 분석 (Mecab, Kiwi 예시)

from kiwipiepy import Kiwi

kiwi = Kiwi()
result = kiwi.tokenize("자연어 처리는 어렵지만 재미있다.")
print([(token.form, token.tag) for token in result])

(4) 바이트페어 인코딩

import sentencepiece as spm

spm.SentencePieceTrainer.train(input='train.txt', model_prefix='bpe', vocab_size=500)
sp = spm.SentencePieceProcessor(model_file='bpe.model')
print(sp.encode('자연어처리는 어렵지만 재미있다.', out_type=str))

6. 텍스트 벡터화

(1) CountVectorizer (BoW)

from sklearn.feature_extraction.text import CountVectorizer
corpus = ["I love NLP", "NLP is amazing"]
vec = CountVectorizer()
X = vec.fit_transform(corpus)
print(X.toarray())

(2) TfidfVectorizer

from sklearn.feature_extraction.text import TfidfVectorizer
vec = TfidfVectorizer()
X = vec.fit_transform(corpus)
print(X.toarray())

7. 텍스트 임베딩

(1) Word2Vec (단어)

from gensim.models import Word2Vec
sentences = [["I", "love", "coding"], ["deep", "learning", "rocks"]]
model = Word2Vec(sentences, vector_size=100, sg=1)

(2) SentenceTransformer (문장)

from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
sentence_vec = model.encode("딥러닝은 흥미롭다.")

profile
나는 AI 엔지니어가 된다.

0개의 댓글