๐Ÿ›ธ ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ(NLP) ๊ธฐ์ดˆ: ํ…์ŠคํŠธ ์ „์ฒ˜๋ฆฌยทTF-IDFยท๊ฐ์„ฑ ๋ถ„์„

okorionยท2025๋…„ 10์›” 29์ผ

1๏ธโƒฃ ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ(NLP)๋ž€?

์ž์—ฐ์–ด ์ฒ˜๋ฆฌ(Natural Language Processing) ๋Š” ์ธ๊ฐ„ ์–ธ์–ด๋ฅผ ์ปดํ“จํ„ฐ๊ฐ€ ์ดํ•ดํ•˜๊ณ  ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๊ธฐ์ˆ ์ด๋‹ค.
ํ…์ŠคํŠธ๋‚˜ ์Œ์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜ํ•™์ ์œผ๋กœ ๋ณ€ํ™˜ํ•ด ์˜๋ฏธ๋ฅผ ์ถ”์ถœํ•œ๋‹ค.

๋‹จ๊ณ„๋ชฉ์ ์˜ˆ์‹œ
ํ…์ŠคํŠธ ์ „์ฒ˜๋ฆฌ๋ถˆํ•„์š”ํ•œ ๋‹จ์–ด ์ œ๊ฑฐ, ์ •๊ทœํ™”โ€œIโ€™m happy!!!โ€ โ†’ โ€œi happyโ€
๋ฒกํ„ฐํ™”๋ฌธ์žฅ์„ ์ˆซ์ž๋กœ ํ‘œํ˜„Bag-of-Words, TF-IDF
ํ•™์Šต๊ฐ์„ฑ๋ถ„์„ยทํ† ํ”ฝ๋ถ„๋ฅ˜ ๋“ฑ๊ธ์ •/๋ถ€์ • ๋ถ„๋ฅ˜๊ธฐ
์‘์šฉ์ฑ—๋ด‡, ๋ฒˆ์—ญ, ์š”์•ฝ ๋“ฑChatGPT, DeepL, BERT

2๏ธโƒฃ NLP ์ ‘๊ทผ ๋ฐฉ์‹

์œ ํ˜•์„ค๋ช…๋Œ€ํ‘œ ๊ธฐ๋ฒ•
ํด๋ž˜์‹ ๋ชจ๋ธ๊ทœ์น™ยทํ†ต๊ณ„ ๊ธฐ๋ฐ˜BoW, TF-IDF, Naive Bayes
๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์˜๋ฏธยท๋ฌธ๋งฅ ๊ธฐ๋ฐ˜RNN, LSTM, Transformer

3๏ธโƒฃ Bag-of-Words (BoW) ๋ชจ๋ธ

๐Ÿ’ก ๊ฐœ๋…

๋ฌธ์„œ๋ฅผ ๋‹จ์–ด์˜ โ€œ๊ฐ€๋ฐฉ(bag)โ€์œผ๋กœ ๋ณด๊ณ ,
๋‹จ์–ด์˜ ์ถœํ˜„ ํšŸ์ˆ˜๋ฅผ ๋ฒกํ„ฐ ํ˜•ํƒœ๋กœ ํ‘œํ˜„ํ•œ๋‹ค.

์˜ˆ์‹œ:
๋ฌธ์žฅ1: โ€œI love NLPโ€
๋ฌธ์žฅ2: โ€œI love Pythonโ€

โ†’ ๋‹จ์–ด ์ง‘ํ•ฉ(Vocabulary): [I, love, NLP, Python]
โ†’ BoW ๋ฒกํ„ฐ

  • ๋ฌธ์žฅ1 โ†’ [1, 1, 1, 0]
  • ๋ฌธ์žฅ2 โ†’ [1, 1, 0, 1]

๋‹จ์ˆœํ•˜์ง€๋งŒ, ๋‹จ์–ด ์ˆœ์„œ๋‚˜ ์˜๋ฏธ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š”๋‹ค.


4๏ธโƒฃ ํ…์ŠคํŠธ ์ „์ฒ˜๋ฆฌ ๋‹จ๊ณ„

โš™๏ธ ์ฃผ์š” ๋‹จ๊ณ„ (Python ๊ธฐ์ค€)

import re
import nltk
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer

corpus = []
for i in range(0, 1000):
    review = re.sub('[^a-zA-Z]', ' ', dataset['Review'][i])
    review = review.lower()
    review = review.split()
    ps = PorterStemmer()
    review = [ps.stem(word) for word in review if not word in set(stopwords.words('english'))]
    review = ' '.join(review)
    corpus.append(review)
๋‹จ๊ณ„์„ค๋ช…
์ •๊ทœ์‹ ์ œ๊ฑฐํŠน์ˆ˜๋ฌธ์ž, ์ˆซ์ž ์ œ๊ฑฐ
์†Œ๋ฌธ์ž ๋ณ€ํ™˜๋Œ€์†Œ๋ฌธ์ž ์ผ๊ด€์„ฑ
ํ† ํฐํ™”(Tokenization)๋‹จ์–ด ๋‹จ์œ„ ๋ถ„๋ฆฌ
๋ถˆ์šฉ์–ด ์ œ๊ฑฐ(Stopwords)์˜๋ฏธ ์—†๋Š” ๋‹จ์–ด ์ œ๊ฑฐ (โ€œtheโ€, โ€œisโ€)
์–ด๊ฐ„ ์ถ”์ถœ(Stemming)๋‹จ์–ด์˜ ๊ธฐ๋ณธํ˜•์œผ๋กœ ์ถ•์†Œ (โ€œlovedโ€โ†’โ€œloveโ€)

5๏ธโƒฃ ํ…์ŠคํŠธ ๋ฒกํ„ฐํ™” (TF-IDF)

BoW๊ฐ€ ๋‹จ์–ด์˜ โ€œ์กด์žฌโ€๋งŒ ๋ณธ๋‹ค๋ฉด,
TF-IDF(Term Frequency-Inverse Document Frequency) ๋Š”
๋‹จ์–ด์˜ ์ค‘์š”๋„๋ฅผ ๋ฐ˜์˜ํ•œ๋‹ค.

TFIDF(t,d)=TF(t,d)ร—logโกNDF(t)TFIDF(t,d) = TF(t,d) \times \log \frac{N}{DF(t)}
  • TF: ๋ฌธ์„œ ๋‚ด ๋‹จ์–ด ๋“ฑ์žฅ ๋นˆ๋„
  • DF: ๋‹จ์–ด๊ฐ€ ํฌํ•จ๋œ ๋ฌธ์„œ ์ˆ˜
  • N: ์ „์ฒด ๋ฌธ์„œ ์ˆ˜

๊ฒฐ๊ณผ์ ์œผ๋กœ,

  • ํ”ํ•œ ๋‹จ์–ด(โ€œtheโ€)๋Š” ๊ฐ€์ค‘์น˜ โ†“
  • ๋“œ๋ฌธ ๋‹จ์–ด(โ€œamazingโ€)๋Š” ๊ฐ€์ค‘์น˜ โ†‘

๐Ÿงช Python ์‹ค์Šต

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(max_features=1500)
X = tfidf.fit_transform(corpus).toarray()
y = dataset.iloc[:, 1].values  # ๊ธ์ •(1)/๋ถ€์ •(0)

โ†’ X๋Š” 1000ร—1500 ์ฐจ์›์˜ ๋ฒกํ„ฐ,
๊ฐ ๋‹จ์–ด์˜ ์ค‘์š”๋„(weight)๊ฐ€ ๋ฐ˜์˜๋œ ์ˆ˜์น˜ ํ–‰๋ ฌ.


6๏ธโƒฃ ๊ฐ์„ฑ ๋ถ„์„ (Sentiment Analysis)

๐Ÿ’ก ๊ฐœ๋…

๋ฆฌ๋ทฐ๋‚˜ ๋Œ“๊ธ€์˜ ๊ธ์ •ยท๋ถ€์ • ๊ฐ์ •์„ ๋ถ„๋ฅ˜ํ•œ๋‹ค.
์ง€๋„ ํ•™์Šต ๋ถ„๋ฅ˜ ๋ชจ๋ธ(Logistic, Naive Bayes, SVM ๋“ฑ)์„ ์‚ฌ์šฉ.


๐Ÿงช Python ์‹ค์Šต

from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import confusion_matrix, accuracy_score

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
classifier = GaussianNB()
classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)

cm = confusion_matrix(y_test, y_pred)
print("Accuracy:", accuracy_score(y_test, y_pred))

๐Ÿ’ก TF-IDF + Naive Bayes = ๊ฐ„๋‹จํ•˜์ง€๋งŒ ๊ฐ•๋ ฅํ•œ ํ…์ŠคํŠธ ๋ถ„๋ฅ˜ ์กฐํ•ฉ.
๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ(โ€œ์ข‹์•„์š”โ€, โ€œ๋ณ„๋กœ์˜ˆ์š”โ€)๋ฅผ ํ•™์Šตํ•ด ์‹ค์‹œ๊ฐ„ ๊ฐ์ • ํŒ๋ณ„ ๊ฐ€๋Šฅ.


๐Ÿงช R ์‹ค์Šต

library(tm)
library(SnowballC)
library(e1071)

corpus = VCorpus(VectorSource(dataset$Review))
corpus = tm_map(corpus, content_transformer(tolower))
corpus = tm_map(corpus, removePunctuation)
corpus = tm_map(corpus, removeNumbers)
corpus = tm_map(corpus, removeWords, stopwords())
corpus = tm_map(corpus, stemDocument)

dtm = DocumentTermMatrix(corpus)
dtm = removeSparseTerms(dtm, 0.99)
dataset_sparse = as.data.frame(as.matrix(dtm))
dataset_sparse$Liked = dataset$Liked

classifier = naiveBayes(Liked ~ ., data = dataset_sparse)
pred = predict(classifier, dataset_sparse)

7๏ธโƒฃ BoW vs TF-IDF ๋น„๊ต

ํ•ญ๋ชฉBag-of-WordsTF-IDF
ํŠน์ง•๋‹จ์ˆœ ์ถœํ˜„ ํšŸ์ˆ˜์ถœํ˜„ + ์ค‘์š”๋„ ๋ฐ˜์˜
๊ณ„์‚ฐ๋Ÿ‰์ž‘์Œํผ
์ค‘๋ณต ๋‹จ์–ด ์˜ํ–ฅํผ์ž‘์Œ
์ถ”์ฒœ ์‚ฌ์šฉ๊ธฐ๋ณธ baseline๊ณ ๊ธ‰ ํ‘œํ˜„, ๊ฐ์„ฑ ๋ถ„์„์— ์ ํ•ฉ

8๏ธโƒฃ ๊ฐ์„ฑ ๋ถ„์„ ๊ฒฐ๊ณผ ํ‰๊ฐ€

์ง€ํ‘œ์˜๋ฏธ
์ •ํ™•๋„(Accuracy)์ „์ฒด ์ค‘ ๋งž๊ฒŒ ์˜ˆ์ธกํ•œ ๋น„์œจ
์ •๋ฐ€๋„(Precision)๊ธ์ •์ด๋ผ ์˜ˆ์ธกํ•œ ๊ฒƒ ์ค‘ ์‹ค์ œ ๊ธ์ •
์žฌํ˜„์œจ(Recall)์‹ค์ œ ๊ธ์ • ์ค‘ ๋งž๊ฒŒ ์˜ˆ์ธกํ•œ ๋น„์œจ
F1 Score์ •๋ฐ€๋„ยท์žฌํ˜„์œจ์˜ ์กฐํ™” ํ‰๊ท 
from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))

9๏ธโƒฃ ํ™•์žฅ: ๋”ฅ๋Ÿฌ๋‹ ๊ธฐ๋ฐ˜ NLP๋กœ ๋‚˜์•„๊ฐ€๊ธฐ

๋‹จ๊ณ„๋Œ€ํ‘œ ๊ธฐ๋ฒ•์„ค๋ช…
๋‹จ์–ด ์ž„๋ฒ ๋”ฉWord2Vec, GloVe๋‹จ์–ด ์˜๋ฏธ ๋ฒกํ„ฐํ™”
๋ฌธ๋งฅ ๋ชจ๋ธBERT, GPT๋ฌธ์žฅ ์ˆ˜์ค€ ์˜๋ฏธ
๊ฐ์„ฑ ๋ถ„์„ ๊ณ ๋„ํ™”LSTM, Transformer๋ฌธ๋งฅ ์˜์กด ๊ฐ์ • ํŒŒ์•…

๐Ÿ”Ÿ ๊ฒฐ๋ก 

์ž์—ฐ์–ด ์ฒ˜๋ฆฌ๋Š” ํ…์ŠคํŠธ๋ฅผ ์ˆ˜์น˜ํ™”ํ•˜์—ฌ
๊ฐ์ •ยท์˜๋„ยท์˜๋ฏธ๋ฅผ ๋ฐ์ดํ„ฐ๋กœ ํ•ด์„ํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค.

  • ์ „์ฒ˜๋ฆฌ๋กœ ์žก์Œ์„ ์ œ๊ฑฐํ•˜๊ณ 
  • TF-IDF๋กœ ๋‹จ์–ด ์ค‘์š”๋„๋ฅผ ๋ฐ˜์˜ํ•˜๋ฉฐ
  • ๊ฐ์„ฑ๋ถ„์„ ๋ชจ๋ธ๋กœ ์–ธ์–ด์˜ ๊ฐ์ •์„ ์˜ˆ์ธกํ•œ๋‹ค.

๐Ÿ“˜ ํ•ต์‹ฌ ์š”์•ฝ

๋‹จ๊ณ„ํ•ต์‹ฌ ๊ธฐ์ˆ ๋ชฉ์ 
ํ…์ŠคํŠธ ์ •์ œTokenization, Stopword ์ œ๊ฑฐ๋…ธ์ด์ฆˆ ์ตœ์†Œํ™”
๋ฒกํ„ฐํ™”BoW, TF-IDF์ˆ˜์น˜ ๋ณ€ํ™˜
๋ชจ๋ธ๋งNaive Bayes, SVM๊ฐ์ •ยท์ฃผ์ œ ๋ถ„๋ฅ˜
profile
Tech Blog

0๊ฐœ์˜ ๋Œ“๊ธ€