[파이썬] nltk 텍스트 분류의 문제점
  1. 데이터 부족: 텍스트 분류 작업을 위해 충분한 양의 레이블된 데이터가 필요합니다. 그러나 실제로는 적은 양의 레이블된 데이터가 사용 가능한 경우가 많습니다. 이는 모델이 학습 과정에서 정확도를 향상시키는 데 어려움을 겪을 수 있는 원인입니다.
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)
  1. 데이터의 불균형: 레이블링된 데이터셋에서 클래스 간의 불균형이 발생하는 경우가 많습니다. 예를 들어, 악성 이메일 분류 작업에서 정상 이메일보다 스팸 이메일이 훨씬 적은 비율을 차지할 수 있습니다. 이로 인해 모델이 불균형한 클래스에 대해 불필요하게 낮은 정확도를 보일 수 있습니다.
# 피처 추출
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)
  1. 과적합: 모델이 훈련 데이터에 과도하게 적합된 경우, 테스트 데이터에서의 정확도가 낮아질 수 있습니다. 이를 방지하기 위해 교차 검증이나 조기 정지와 같은 기술을 사용하여 모델을 더 일반화시킬 수 있습니다.
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)
  1. 다양한 텍스트 유형: 텍스트 분류 작업에 있어 다양한 유형의 텍스트가 존재하는데, 이는 모델의 성능에 영향을 미칠 수 있습니다. 예를 들어, 소셜 미디어 글과 뉴스 기사는 서로 다른 특성을 가지고 있습니다. 따라서, 한 유형의 데이터로 학습된 모델은 다른 유형의 데이터에서는 부정확한 결과를 도출할 수 있습니다.
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: