[파이썬] nltk 텍스트 분류의 문제점
- 데이터 부족: 텍스트 분류 작업을 위해 충분한 양의 레이블된 데이터가 필요합니다. 그러나 실제로는 적은 양의 레이블된 데이터가 사용 가능한 경우가 많습니다. 이는 모델이 학습 과정에서 정확도를 향상시키는 데 어려움을 겪을 수 있는 원인입니다.
import nltk
from nltk.corpus import movie_reviews
# 레이블된 데이터 로드
documents = [(list(movie_reviews.words(fileid)), category)
for category in movie_reviews.categories()
for fileid in movie_reviews.fileids(category)]
# 데이터셋 분할
train_set = documents[:1500]
test_set = documents[1500:]
# 피처 추출
all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())
word_features = list(all_words)[:2000]
# 분류 모델 학습
classifier = nltk.NaiveBayesClassifier.train(train_set)
# 정확도 평가
accuracy = nltk.classify.accuracy(classifier, test_set)
print("Accuracy:", accuracy)
- 데이터의 불균형: 레이블링된 데이터셋에서 클래스 간의 불균형이 발생하는 경우가 많습니다. 예를 들어, 악성 이메일 분류 작업에서 정상 이메일보다 스팸 이메일이 훨씬 적은 비율을 차지할 수 있습니다. 이로 인해 모델이 불균형한 클래스에 대해 불필요하게 낮은 정확도를 보일 수 있습니다.
# 피처 추출
all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())
word_features = list(all_words)[:2000]
# 데이터셋 불균형 보정
balanced_train_set = []
pos_reviews = [(list(movie_reviews.words(fileid)), 'positive')
for fileid in movie_reviews.fileids('pos')]
neg_reviews = [(list(movie_reviews.words(fileid)), 'negative')
for fileid in movie_reviews.fileids('neg')]
# 클래스별로 동일한 수의 샘플을 선택
min_size = min(len(pos_reviews), len(neg_reviews))
balanced_train_set.extend(pos_reviews[:min_size])
balanced_train_set.extend(neg_reviews[:min_size])
# 분류 모델 학습
classifier = nltk.NaiveBayesClassifier.train(balanced_train_set)
# 정확도 평가
accuracy = nltk.classify.accuracy(classifier, test_set)
print("Accuracy:", accuracy)
- 과적합: 모델이 훈련 데이터에 과도하게 적합된 경우, 테스트 데이터에서의 정확도가 낮아질 수 있습니다. 이를 방지하기 위해 교차 검증이나 조기 정지와 같은 기술을 사용하여 모델을 더 일반화시킬 수 있습니다.
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.svm import LinearSVC
# 텍스트 전처리
stopwords = set(stopwords.words('english'))
lemmatizer = WordNetLemmatizer()
def preprocess_text(text):
words = nltk.word_tokenize(text)
words = [lemmatizer.lemmatize(word) for word in words if word.isalpha()]
words = [word.lower() for word in words if word.lower() not in stopwords]
return ' '.join(words)
# 전처리된 데이터셋 생성
preprocessed_reviews = [preprocess_text(review) for review, _ in documents]
# TF-IDF 벡터화
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(preprocessed_reviews)
y = [category for _, category in documents]
# 데이터셋 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 모델 학습
classifier = LinearSVC()
classifier.fit(X_train, y_train)
# 정확도 평가
accuracy = classifier.score(X_test, y_test)
print("Accuracy:", accuracy)
- 다양한 텍스트 유형: 텍스트 분류 작업에 있어 다양한 유형의 텍스트가 존재하는데, 이는 모델의 성능에 영향을 미칠 수 있습니다. 예를 들어, 소셜 미디어 글과 뉴스 기사는 서로 다른 특성을 가지고 있습니다. 따라서, 한 유형의 데이터로 학습된 모델은 다른 유형의 데이터에서는 부정확한 결과를 도출할 수 있습니다.
from nltk.tokenize import TweetTokenizer
# 토크나이저 변경
tokenizer = TweetTokenizer()
X = vectorizer.fit_transform(preprocessed_reviews)
# 데이터셋 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 모델 학습
classifier = LinearSVC()
classifier.fit(X_train, y_train)
# 정확도 평가
accuracy = classifier.score(X_test, y_test)
print("Accuracy:", accuracy)
nltk 텍스트 분류의 이러한 문제점들은 데이터 수집과 전처리의 중요성을 강조합니다. 더 많은 레이블된 데이터를 사용하고 데이터셋을 다양하게 구성하여 모델이 다양한 텍스트 유형에 대해 일반화될 수 있도록 노력하는 것이 필요합니다. References:
- Bird, S., Klein, E., & Loper, E. (2009). Natural Language Processing with Python. O’Reilly Media.