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): 문서 내 단어 빈도
IDF (Inverse Document Frequency): 역문서 빈도
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
면접 질문 맛보기
- TF-IDF의 의미와 계산 방법은?
- Word2Vec의 CBOW와 Skip-gram 차이는?
- 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 튜토리얼을 모두 완료했습니다. 더 깊은 학습을 원한다면:
- Premium Practice - 연습문제
- Premium Solutions - 솔루션
- Premium Interviews (opens in a new tab) - 면접 대비