튜토리얼
14. NLP

14. NLP (자연어 처리)

TF-IDF, Word2Vec, Sentiment Analysis


학습 목표

이 튜토리얼을 완료하면 다음을 할 수 있습니다:

  • 텍스트 전처리 기법을 이해하고 적용할 수 있다
  • 텍스트 벡터화 방법 (BoW, TF-IDF)을 구현할 수 있다
  • 전통 ML 감성분석 (Naive Bayes, SVM, Logistic Regression)을 수행할 수 있다
  • 딥러닝 감성분석 (LSTM, Transformer)의 개념을 이해한다
  • 실전 리뷰 분석 파이프라인을 구축할 수 있다

NLP 기초 개념

텍스트 데이터의 특징

특징설명
비정형 데이터구조가 없음
고차원단어 수만큼 차원
희소성대부분 0 (sparse)
순서 중요단어 순서에 의미

NLP 파이프라인

원본 텍스트 → 전처리 → 토큰화 → 벡터화 → 모델 학습 → 예측

1. 텍스트 전처리

텍스트 전처리는 NLP의 가장 중요한 첫 단계입니다. 원시 텍스트를 모델이 처리할 수 있는 형태로 변환합니다.

기본 전처리 단계

단계설명예시
소문자 변환대소문자 통일"Movie" → "movie"
특수문자 제거구두점 등 제거"great!" → "great"
숫자 처리제거 또는 변환"2024" → ""
불용어 제거의미 없는 단어 제거"the", "is", "a" 등
Stemming어간 추출"running" → "run"
Lemmatization표제어 추출"better" → "good"
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer, WordNetLemmatizer
import re
 
# 기본 전처리 함수
def preprocess_text(text):
    # 소문자 변환
    text = text.lower()
 
    # 특수문자 제거
    text = re.sub(r'[^a-z\s]', '', text)
 
    # 여러 공백을 하나로
    text = re.sub(r'\s+', ' ', text).strip()
 
    return text
 
# Tokenization
tokens = word_tokenize("This is a sample sentence.")
 
# Stop words 제거
stop_words = set(stopwords.words('english'))
filtered = [w for w in tokens if w.lower() not in stop_words]
 
# Stemming
stemmer = PorterStemmer()
stemmed = [stemmer.stem(w) for w in filtered]
 
# Lemmatization
lemmatizer = WordNetLemmatizer()
lemmatized = [lemmatizer.lemmatize(w) for w in filtered]
⚠️

감성분석에서 불용어 제거 시 주의하세요! "not", "no" 같은 부정어는 감성을 반전시키는 중요한 단어입니다. 무분별한 제거는 성능을 저하시킬 수 있습니다.


2. Bag of Words (BoW)

단어의 출현 빈도를 벡터로 표현하는 가장 기본적인 방법입니다.

"I love this movie"  →  [1, 1, 1, 1, 0, 0, ...]
"I hate this movie"  →  [1, 0, 1, 1, 1, 0, ...]

단어: [I, love, this, movie, hate, ...]
from sklearn.feature_extraction.text import CountVectorizer
 
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(documents)
 
print(f'BoW 행렬 shape: {X.shape}')
print(f'어휘 크기: {len(vectorizer.vocabulary_)}')
print(vectorizer.get_feature_names_out())

3. TF-IDF

TF-IDF는 단순 빈도보다 더 의미 있는 단어 중요도를 계산합니다.

수식

TF (Term Frequency): 문서 내 단어 빈도

TF(t,d)=단어 t가 문서 d에 나타난 횟수문서 d의 총 단어 수TF(t, d) = \frac{\text{단어 t가 문서 d에 나타난 횟수}}{\text{문서 d의 총 단어 수}}

IDF (Inverse Document Frequency): 역문서 빈도

IDF(t)=log전체 문서 수단어 t가 포함된 문서 수IDF(t) = \log\frac{\text{전체 문서 수}}{\text{단어 t가 포함된 문서 수}}

TF-IDF = TF x IDF

TF-IDF의 핵심: 흔한 단어(the, is)는 낮은 점수, 특정 문서에만 있는 단어는 높은 점수를 받습니다. 이를 통해 문서를 구별하는 중요한 단어를 찾을 수 있습니다.

from sklearn.feature_extraction.text import TfidfVectorizer
 
tfidf = TfidfVectorizer(max_features=5000)
X = tfidf.fit_transform(documents)
 
# 단어별 중요도 확인
tfidf_means = pd.DataFrame({
    'word': tfidf.get_feature_names_out(),
    'tfidf_mean': np.array(X.mean(axis=0)).flatten()
}).sort_values('tfidf_mean', ascending=False)

4. Word Embedding

단어를 밀집 벡터(Dense Vector)로 표현하여 의미적 유사성을 반영합니다.

BoW/TF-IDF의 한계

  • 고차원, 희소 벡터
  • 단어 간 의미 유사도 반영 불가

Word2Vec의 장점

  • 저차원 밀집 벡터 (100~300차원)
  • 의미적 유사성 반영
  • 유명한 예시: king - man + woman ≈ queen
from gensim.models import Word2Vec
 
# 학습
sentences = [doc.split() for doc in documents]
model = Word2Vec(sentences, vector_size=100, window=5,
                 min_count=2, workers=4)
 
# 유사 단어
model.wv.most_similar('king')
 
# 단어 벡터
vector = model.wv['king']

Pre-trained Embeddings

# GloVe, FastText 등 사전 학습 임베딩 사용
import gensim.downloader as api
 
glove = api.load('glove-wiki-gigaword-100')
vector = glove['computer']

5. 감성분석 모델 (전통 ML)

Naive Bayes

텍스트 분류의 강력한 베이스라인 모델입니다.

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
 
# Pipeline으로 전처리와 모델을 결합
nb_pipeline = Pipeline([
    ('tfidf', TfidfVectorizer(ngram_range=(1, 2))),
    ('clf', MultinomialNB())
])
 
nb_pipeline.fit(X_train, y_train)
y_pred = nb_pipeline.predict(X_test)

Logistic Regression

from sklearn.linear_model import LogisticRegression
 
lr_pipeline = Pipeline([
    ('tfidf', TfidfVectorizer(ngram_range=(1, 2))),
    ('clf', LogisticRegression(max_iter=1000))
])
 
lr_pipeline.fit(X_train, y_train)
y_pred = lr_pipeline.predict(X_test)

SVM

from sklearn.svm import LinearSVC
 
svm_pipeline = Pipeline([
    ('tfidf', TfidfVectorizer(ngram_range=(1, 2))),
    ('clf', LinearSVC())
])
 
svm_pipeline.fit(X_train, y_train)
y_pred = svm_pipeline.predict(X_test)

N-gram을 활용하면 연속된 단어 패턴을 캡처할 수 있습니다. ngram_range=(1, 2)는 단일 단어(unigram)와 두 단어 연속(bigram)을 모두 사용합니다. 예: "not good"이라는 bigram은 부정적 의미를 잘 캡처합니다.


6. 딥러닝 NLP

LSTM for Sentiment

순서 정보를 학습하는 순환 신경망입니다.

"This movie is not good" vs "This movie is good"
→ 단어 순서에 따라 의미가 달라짐
→ LSTM은 순서 정보를 학습
from tensorflow.keras import models, layers
 
model = models.Sequential([
    layers.Embedding(vocab_size, 128, input_length=max_len),
    layers.LSTM(64, return_sequences=True),
    layers.LSTM(32),
    layers.Dense(64, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(1, activation='sigmoid')
])
 
model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

7. Transformer & BERT

현대 NLP의 핵심 기술입니다.

Attention Mechanism

  • 입력 시퀀스의 모든 위치 간 관계 학습
  • 병렬 처리 가능

BERT (Bidirectional Encoder Representations from Transformers)

  • 사전학습된 대규모 언어 모델
  • Fine-tuning으로 다양한 NLP 태스크 해결
from transformers import BertTokenizer, TFBertForSequenceClassification
 
# Tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
inputs = tokenizer(texts, padding=True, truncation=True,
                   return_tensors='tf', max_length=128)
 
# Model
model = TFBertForSequenceClassification.from_pretrained(
    'bert-base-uncased', num_labels=2)
 
# Fine-tuning
model.compile(optimizer='adam', loss=model.compute_loss,
              metrics=['accuracy'])
model.fit(inputs, labels, epochs=3, batch_size=16)

Hugging Face Pipeline 활용

from transformers import pipeline
 
sentiment_pipeline = pipeline('sentiment-analysis')
result = sentiment_pipeline('I love this movie!')
# [{'label': 'POSITIVE', 'score': 0.9998}]

코드 요약 (감성 분석 파이프라인)

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score
 
# 데이터
reviews = ["This movie is great!", "Terrible waste of time", ...]
labels = [1, 0, ...]
 
# Pipeline
pipeline = Pipeline([
    ('tfidf', TfidfVectorizer(max_features=5000, ngram_range=(1, 2))),
    ('classifier', LogisticRegression(max_iter=1000))
])
 
# Cross-validation
scores = cross_val_score(pipeline, reviews, labels, cv=5)
print(f"Accuracy: {scores.mean():.4f}{scores.std():.4f})")
 
# 학습 & 예측
pipeline.fit(reviews, labels)
predictions = pipeline.predict(["Amazing film!", "Boring movie"])

텍스트 표현 비교

방법장점단점
BoW단순, 빠름희소, 순서 무시
TF-IDF중요 단어 강조순서 무시
Word2Vec의미 캡처문맥 무시
BERT문맥 이해느림, 리소스

선택 가이드

상황권장 방법
빠른 프로토타입TF-IDF + LogReg
의미 유사도Word2Vec
최고 성능BERT
시퀀스 모델링LSTM

실전 팁

텍스트 전처리 상황별 가이드

상황전처리 방법
감성분석불용어 제거 주의 (not 중요!)
문서 분류TF-IDF + N-gram
유사도 측정Word Embedding
대규모 데이터BERT Fine-tuning

성능 향상 팁

1. 데이터 양 확보: 최소 1000개 이상 권장, 데이터 증강(역번역 등) 활용

2. 전처리 실험: N-gram 범위 조정, 불용어 리스트 커스터마이징, 어간/표제어 추출 비교

3. 모델 앙상블: 여러 모델 결합 (Stacking, Voting)

4. 딥러닝 활용: 사전학습 모델 (BERT), Transfer Learning


면접 질문 맛보기

  1. TF-IDF의 의미와 계산 방법은?
  2. Word2Vec의 CBOW와 Skip-gram 차이는?
  3. BERT가 기존 모델과 다른 점은?

더 많은 면접 질문은 Premium Interviews (opens in a new tab)에서 확인하세요.


실습 노트북

노트북에서는 다음 추가 내용을 다룹니다:

  • 영화 리뷰 샘플 데이터를 활용한 실습
  • BoW와 TF-IDF 행렬 시각화 (히트맵)
  • 모델별 성능 비교 (5-Fold Cross Validation)
  • 특성 중요도 분석 (긍정/부정 단어 Top 15)
  • N-gram(Bigram) 분석
  • WordCloud 시각화
  • 새로운 리뷰 실시간 예측 함수
  • Word Embedding 개념 시각화 (2D 투영)

이전: 13. CNN


학습 완료!

14개의 ML 튜토리얼을 모두 완료했습니다. 더 깊은 학습을 원한다면: