머신러닝으로 기사 분류 자동화하기: 종합 가이드
이 글은 PyTorch를 사용해 기사 또는 문서 분류를 자동화하는 기계 학습 활용 방법을 보여줍니다. 이 글은 AI 번역본입니다. 오역이 있을 수 있으니 댓글로 알려 주세요.
Created on September 15|Last edited on September 15
Comment

소개
인터넷처럼 변화가 빠르고 디지털 콘텐츠가 기하급수적으로 생산되는 환경에서는, 기사를 효율적으로 관리하고 분류하는 일이 사용자 경험을 높이고 정보 검색을 최적화하는 데 매우 중요합니다. 자연어 처리와 머신 러닝의 핵심 과제인 문서 분류는 이 분야에서 결정적인 역할을 합니다. 문서 분류는 텍스트 문서의 내용, 구조, 또는 문맥을 바탕으로 미리 정의된 범주나 레이블을 자동으로 부여하는 작업을 의미합니다.
문서 분류는 방대한 정보를 관리하기 쉽고 접근 가능한 범주로 체계화하기 때문에 중요합니다. 이 과정은 효율적인 검색과 조회를 가능하게 하고, 개인화된 콘텐츠 추천을 지원하며, 사용자와 콘텐츠 관리자 모두를 위한 콘텐츠 조직화를 향상시킵니다.
이 글에서는 PyTorch 프레임워크를 활용해 딥 뉴럴 네트워크로 기사 분류를 자동화하는 방법을 살펴봅니다. 먼저 기사 분류 데이터셋을 바탕으로 데이터 전처리를 수행합니다. 이어서 간단한 신경망을 구현해 기사를 분류하도록 학습시킵니다. 또한 학습 파이프라인에 Weights & Biases를 통합해 실험 추적, 모델 비교 등을 손쉽게 수행할 수 있도록 합니다. 글을 마치면 PyTorch를 사용한 기사 분류의 전 과정을 명확히 이해할 수 있을 것입니다.
ML 모델은 문서 분류를 어떻게 수행할까?
문서 분류 분야에서 머신 러닝(ML) 모델은 기사, 뉴스, 연구 논문, 블로그 글에 이르는 디지털 콘텐츠의 분류를 자동화하는 데 중요한 역할을 합니다. 이제 이러한 모델이 문서 분류를 어떻게 수행하는지 자세히 살펴보겠습니다.
문서 분류와 그 역할
문서 분류는 텍스트 문서의 내용, 구조, 또는 문맥을 바탕으로 미리 정의된 범주나 레이블로 분류하는 작업입니다. 이 과정은 디지털 콘텐츠를 체계적으로 정리하고 관리하는 데 필수적이며, 효율적인 정보 검색과 콘텐츠 추천 시스템을 가능하게 합니다. 또한 ML 모델을 활용해 이 분류 과정을 자동화함으로써, 다양한 콘텐츠 유형과 도메인에 걸쳐 확장성과 적응성을 확보할 수 있습니다.
문서 분류는 어떻게 작동할까

문서 분류는 ML과 NLP(자연어 처리) 기술이 결합되어 작동합니다. 이 두 가지가 문서 분류 시스템의 근간을 이룹니다. 이러한 시스템은 일반적으로 다음 단계를 따릅니다:
- 데이터 수집: 첫 번째 단계는 문서 또는 디지털 콘텐츠와 그에 대응하는 범주(레이블)로 구성된 레이블된 데이터셋의 출처를 확보하는 것입니다. 데이터셋이 각 범주에 걸쳐 대표성과 균형을 갖추었는지 확인하세요.
- 데이터 전처리: 이 과정은 여러 단계를 거치며, 각 단계에서 데이터를 정제합니다. 텍스트는 특수 문자, HTML 태그, 문장 부호, 불용어와 같은 노이즈를 제거하여 깨끗하게 만듭니다. 그런 다음 텍스트를 단어 또는 서브워드 단위로 토큰화합니다. 추가로, 어간 추출이나 표제어 추출 같은 기법을 적용해 단어를 정규화할 수 있습니다.
- 특징 추출: 이제 전처리된 텍스트 데이터를 머신러닝 알고리즘이 이해할 수 있는 수치형 특징으로 변환합니다. 자주 사용되는 텍스트 표현 방식으로는 TF-IDF(단어 빈도-역문서 빈도)와 의미 정보를 포착하는 Word2Vec, GloVe, BERT 같은 단어 임베딩이 있습니다.
- 데이터셋 분할: 모델의 성능을 학습하고 평가할 수 있도록 데이터셋을 학습, 검증, 테스트 세트로 나눕니다. 경우에 따라 작업이 단순하면 학습과 테스트만으로 분할하고 검증 세트는 생략하기도 합니다.
- 모델 선택: 문서 분류에 적합한 머신러닝 모델을 선택해야 합니다. 자주 사용되는 모델로는 로지스틱 회귀, 나이브 베이즈, 서포트 벡터 머신(SVM), 신경망이 있습니다.
- 모델 학습 및 테스트: 선택한 모델은 학습 데이터셋으로 학습하고, 별도의 테스트 데이터셋으로 평가합니다. 정확도, 정밀도, 재현율, F1 점수와 같은 평가 지표를 사용해 모델의 효과성을 측정합니다.
텍스트 분류를 위한 지도 학습 vs 비지도 학습

지도 학습: 지도 학습에서는 각 문서가 알려진 범주(레이블)와 연결된 라벨링된 데이터셋으로 모델을 학습합니다. 모델은 학습 과정에서 입력 특성(텍스트 내용)을 대응하는 출력 레이블로 매핑하는 방법을 학습합니다. 지도 학습은 정확한 분류에 효과적이지만, 학습을 위해 라벨링된 데이터가 필요합니다.
비지도 학습: K-평균 클러스터링, 계층적 클러스터링과 같은 군집화 알고리즘을 포함한 비지도 학습 접근 방식은 라벨이 있는 데이터가 필요하지 않습니다. 이들 알고리즘은 미리 정의된 범주 없이도 문서의 특성 유사성을 기준으로 문서를 묶습니다. 비지도 학습은 데이터에서 숨겨진 패턴과 구조를 발견할 수 있지만, 지도 학습 방법에 비해 분류의 세분성이 떨어질 수 있습니다.
뉴스룸의 과제 - 정보 체계화
디지털 미디어 플랫폼과 온라인 출판의 등장으로 정치, 비즈니스, 기술, 엔터테인먼트에 이르기까지 다양한 주제의 뉴스 콘텐츠가 폭발적으로 늘어났습니다. 이러한 기하급수적 증가로 정보 과부하 문제가 심화되면서 사용자가 관련 뉴스 기사를 탐색하고 접근하기가 점점 더 어려워지고 있습니다. 매일 생산되는 뉴스 콘텐츠가 급증함에 따라, 방대한 정보를 효율적으로 체계화하고 분류하는 일이 뉴스룸과 콘텐츠 관리자에게 큰 과제로 떠올랐습니다.
수동 분류 vs 자동 분류
수동 분류와 자동 분류는 각각 장점과 한계가 있습니다. 두 접근 방식을 모두 살펴보겠습니다.
수동 분류:
- 비용: 뉴스 기사 수동 분류에는 인력, 시간, 그리고 자원이 필요합니다. 숙련된 인력을 채용하거나 기존 직원을 기사 분류 업무에 배정하면 비용이 발생합니다.
- 장점: 사람의 판단과 전문성은 특히 복잡하거나 모호한 주제에서 더 미세한 수준의 분류를 가능하게 합니다. 또한 편집 가이드라인과 독자 선호에 맞춰 카테고리를 정교하게 조정할 수 있습니다.
- 제한사항: 수동 분류는 노동 집약적이며 오류가 발생하기 쉽고, 증가하는 뉴스 콘텐츠 규모에 잘 확장되지 않을 수 있습니다. 또한 주관성이 개입되어 분류 결과에 일관성이 떨어질 수 있습니다.
자동 분류:
- 비용: 머신러닝 모델을 활용한 자동 분류를 구현하려면 기술 인프라, 모델 개발, 학습 데이터에 대한 초기 투자가 필요합니다. 그러나 장기적인 운영 비용은 수작업에 비해 크게 낮아질 수 있습니다.
- 장점: 자동 분류는 ML 알고리즘을 활용해 대량의 텍스트 데이터를 빠르고 일관되게 처리합니다. 이를 통해 인간의 오류를 줄이고 확장성을 높이며, 유입되는 뉴스 기사에 대한 실시간 분류를 가능하게 합니다.
- 제한사항: 자동화된 시스템은 미묘하거나 문맥에 의존하는 주제를 정확하게 분류하는 데 어려움을 겪을 수 있습니다. 또한 뉴스 트렌드와 주제가 변화함에 따라 분류 정확도를 유지하려면 정기적인 모니터링과 업데이트가 필요합니다.
자동 분류가 뉴스 탐색, 읽기, 보관을 어떻게 향상시키는가
자동 분류는 사용자가 관련 콘텐츠에 더 오래 머무르게 하고, 특정 정보를 찾는 데 걸리는 시간을 줄이며, 사용자 선호도와 행동에 기반한 맞춤형 콘텐츠 추천을 제공함으로써 전반적인 이용 경험을 개선합니다.
- 뉴스 탐색: 자동 분류는 콘텐츠를 의미 있는 카테고리나 주제로 묶어 사용자들이 관련 뉴스 기사를 더 효율적으로 발견할 수 있도록 합니다. 이를 통해 사용자 선호도에 기반한 맞춤형 뉴스 피드와 목표 지향적 콘텐츠 추천이 가능해져 이용 경험이 향상됩니다.
- 읽기 경험: 자동 분류는 기사를 체계적인 섹션이나 주제 클러스터로 제공하여 사용자가 관련 콘텐츠를 매끄럽게 탐색하고 확장해 볼 수 있도록 함으로써 읽기 경험을 향상시킵니다.
- 보관 및 검색: 자동 분류는 뉴스 콘텐츠를 체계적으로 보관하는 데 도움을 주어, 특정 카테고리, 날짜, 키워드에 따라 과거 기사를 더 쉽게 검색할 수 있게 합니다. 이러한 보관 시스템은 뉴스 조직 내에서 연구, 분석, 그리고 콘텐츠 재활용을 지원합니다.
머신 러닝 기반의 자동 분류 기술을 도입하면, 뉴스룸은 방대한 디지털 뉴스 콘텐츠로 인한 어려움을 극복하고 콘텐츠의 체계화와 접근성을 개선하며, 궁극적으로는 청중의 전반적인 뉴스 소비 경험을 향상시킬 수 있습니다.
Weights & Biases로 나만의 문서 분류기 구축 실무 가이드
뉴스 분류를 위한 머신러닝 모델을 개발·학습·배포하는 실무적인 측면을 살펴보겠습니다. 이 안내서에서는 모델이 기사나 문서를 입력으로 받아 해당 문서가 속한 카테고리를 예측할 수 있도록 합니다.
데이터셋 선택
기사 분류를 위해 우리는 사용할 예정입니다 뉴스 기사 데이터셋으로, 2,584개의 고유한 뉴스 기사가 포함되어 있습니다. 각 뉴스 기사에는 다음과 같은 카테고리가 할당되어 있습니다. 비즈니스 또는 스포츠.
이 데이터셋은 수집되었습니다 https://www.thenews.com.pk 웹사이트입니다. 비즈니스와 스포츠 관련 뉴스 기사가 2015년부터 현재까지 수록되어 있습니다. 각 기사에는 제목, 본문, 그리고 게재 날짜가 포함되어 있습니다. 또한 본문에는 해당 발언 또는 기사가 발표된 장소 정보도 담겨 있습니다.
1단계: 필요한 라이브러리 가져오기
나중에 코드에서 사용할 pandas, torch, sklearn 같은 필수 라이브러리를 가져오겠습니다.
import osimport pandas as pdimport numpy as npimport randomimport torchimport torch.nn as nnimport torch.optim as optimfrom sklearn.feature_extraction.text import CountVectorizerfrom sklearn.preprocessing import LabelEncoderfrom sklearn.model_selection import train_test_splitimport reimport stringimport nltkfrom nltk.corpus import stopwordsfrom sklearn.metrics import accuracy_score, confusion_matrix, classification_reportimport wandb
2단계: Weights & Biases 초기화
이제 article_classifier라는 새 프로젝트에 대해 Weights & Biases를 초기화하고 구성 데이터를 추가하겠습니다. 이 단계는 프로젝트 환경을 설정하기 때문에 중요합니다.
config = {"seed": 42,"lr": 0.001,"epochs": 5}wandb.init(project='article_classifier', config=config)

3단계: 환경 시드 고정
딥러닝에서 환경에 시드를 고정하면 난수 생성이 일관되게 유지되어, 디버깅과 테스트, 하이퍼파라미터 튜닝, 연구 및 프로덕션 환경에서의 결과 검증에 필요한 재현성을 보장합니다.
random.seed(config["seed"])os.environ["PYTHONHASHSEED"] = str(config["seed"])np.random.seed(config["seed"])torch.manual_seed(config["seed"])torch.cuda.manual_seed(config["seed"])torch.backends.cudnn.deterministic = True
4단계: 불용어 다운로드
데이터셋 정제를 위해 나중에 사용할 수 있도록 NLTK 라이브러리를 사용해 영어 불용어 전체를 다운로드합니다.
nltk.download('stopwords')
5단계: 데이터 로딩 및 전처리
먼저 pandas를 사용해 CSV 파일에서 데이터를 읽습니다. 그런 다음 clean_text라는 함수를 정의해 텍스트 데이터를 다음과 같이 전처리합니다.
- 텍스트를 소문자로 변환하기.
- 구두점 제거하기
- 불용어 제거하기
- 공백 제거하기
이 과정은 기사에서 불필요한 요소를 걸러내면서 핵심 맥락 정보를 보존합니다.
정제 후에는 정제된 텍스트 데이터를 CSV 파일의 'Cleaned_Article' 열에 저장하고, 추가 분석을 위해 정제된 기사와 해당 범주를 함께 불러옵니다.
# Load dataset from CSVdata = pd.read_csv('Articles.csv', encoding='ISO-8859-1')
# Preprocessingdef clean_text(text):text = text.lower() # Convert text to lowercasetext = re.sub(r'\d+', '', text) # Remove digitstext = text.translate(str.maketrans('', '', string.punctuation)) # Remove punctuationtext = ' '.join([word for word in text.split() if word not in stopwords.words('english')]) # Remove stop wordstext = text.strip() # Remove leading and trailing whitespacesreturn text
data['Cleaned_Article'] = data['Article'].apply(clean_text)X = data['Cleaned_Article']y = data['NewsType']
다음은 뉴스 기사를 정제하기 전과 후의 예시입니다.
정제 이전:

정제 이후:

6단계: 레이블 인코딩과 벡터화
이제 텍스트 데이터를 전처리했으므로, 모델 학습을 위해 레이블 인코딩과 벡터화를 수행해 특성과 레이블을 준비하겠습니다.
# Label Encodinglabel_encoder = LabelEncoder()y = label_encoder.fit_transform(y)class_labels = label_encoder.classes_
# Vectorizationvectorizer = CountVectorizer()X = vectorizer.fit_transform(X)
# Convert sparse matrix to dense tensorX = torch.tensor(X.toarray(), dtype=torch.float32)y = torch.tensor(y, dtype=torch.long)
7단계: 데이터셋 분할
다음으로 데이터셋을 균등하게 두 부분으로 나눠 학습용과 테스트용 세트로 구성하고, 이를 각각 모델 학습과 평가에 활용합니다.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)print(f"Training samples: {len(X_train)} - Testing samples: {len(X_test)}")
8단계: 모델 아키텍처 정의
이제 PyTorch를 사용해 기사 분류를 위한 다층 퍼셉트론(MLP) 아키텍처를 정의하겠습니다.
class NewsClassifier(nn.Module):def __init__(self, input_dim, output_dim):super(NewsClassifier, self).__init__()self.fc = nn.Sequential(nn.Linear(input_dim, input_dim//8),nn.ReLU(),nn.Linear(input_dim//8, output_dim))def forward(self, x):x = self.fc(x)return x
input_dim = X_train.shape[1]output_dim = len(y_train.unique())model = NewsClassifier(input_dim, output_dim)criterion = nn.CrossEntropyLoss()optimizer = optim.Adam(model.parameters(), lr=0.001)
9단계: 초기 결과 로깅
테스트 데이터셋에서 샘플 10개를 추출해 학습되지 않은 모델로 예측을 수행하겠습니다. 그리고 그 결과를 Weights & Biases에 로깅하겠습니다.
# Logging articles to the tablepred_table = wandb.Table(columns=["Name", "Sample 1", "Sample 2", "Sample 3", "Sample 4", "Sample 5", "Sample 6", "Sample 7", "Sample 8", "Sample 9", "Sample 10"])
이제 데이터셋을 분할하고 기사를 Weights & Biases 테이블에 로깅합니다.
# Split_, test_x, _, test_y = train_test_split(data['Cleaned_Article'].values, data['NewsType'].values, test_size=0.5, random_state=42)pred_table.add_data("Articles", test_x[0], test_x[1], test_x[2], test_x[3], test_x[4], test_x[5], test_x[6], test_x[7], test_x[8], test_x[9])
이제 학습되지 않은 모델로 예측을 수행하고, 그 결과를 Weights & Biases 테이블에 로깅합니다.
# Initial resultsinitial_samples = X_test[:10] # Get 10 initial samplesinitial_predictions = torch.argmax(torch.softmax(model(initial_samples), dim=1), dim=1)initial_predictions_labels = [class_labels[i] for i in initial_predictions.tolist()]print("Initial Predictions: \t", initial_predictions_labels)
pred_table.add_data("Initial Predictions", initial_predictions_labels[0],initial_predictions_labels[1], initial_predictions_labels[2], initial_predictions_labels[3],initial_predictions_labels[4], initial_predictions_labels[5], initial_predictions_labels[6],initial_predictions_labels[7], initial_predictions_labels[8], initial_predictions_labels[9])
10단계: 학습 및 예측 로깅
이제 학습 데이터셋으로 모델을 5에포크만 학습하겠습니다. 각 에포크마다 앞서 언급한 테스트 샘플로 예측을 수행하고, 그 결과를 Weights & Biases 테이블에 추가합니다.
# Training loopfor epoch in range(config["epochs"]):model.train()optimizer.zero_grad()outputs = model(X_train)loss = criterion(outputs, y_train)print(f"Epoch: {epoch+1:2d} - Loss: {loss:1.4f}")wandb.log({"Epoch":epoch+1, "Loss":loss})loss.backward()optimizer.step()
# Logging final resultsfinal_predictions = torch.argmax(torch.softmax(model(initial_samples), dim=1), dim=1)final_predictions_labels = [class_labels[i] for i in final_predictions.tolist()]pred_table.add_data(f"Epoch {epoch+1}", final_predictions_labels[0], final_predictions_labels[1], final_predictions_labels[2], final_predictions_labels[3], final_predictions_labels[4], final_predictions_labels[5], final_predictions_labels[6], final_predictions_labels[7], final_predictions_labels[8], final_predictions_labels[9])
print("Final Predictions: \t", final_predictions_labels)

이 표는 초기 모델의 예측 결과와 각 에포크별 예측을 함께 보여 주어, 성능이 어떻게 개선되는지 나타냅니다.
여기서는 Weights & Biases의 곡선 그래프가 에포크마다의 학습 손실을 보여 줍니다. 에포크가 진행될수록 학습 손실이 감소하며, 이는 학습 중 예측값과 실제 범주 간의 차이가 줄어들고 있음을 의미합니다.

Weights & Biases의 곡선 그래프는 에포크마다의 학습 손실을 보여 줍니다
11단계: 테스트 및 평가
모델 학습이 완료되면 테스트 데이터셋으로 성능을 평가합니다.
model.eval()with torch.no_grad():test_outputs = model(X_test)predicted = torch.argmax(torch.softmax(test_outputs, dim=1), dim=1)accuracy = accuracy_score(y_test, predicted)confusion_mat = confusion_matrix(y_test, predicted)classification_rep = classification_report(y_test, predicted)
# Logging evaluation metrics to W&Bwandb.log({"Accuracy": accuracy})wandb.log({"Confusion Matrix": confusion_mat.tolist()})wandb.log({"Classification Report": classification_rep})
print("Evaluation ->")print("Accuracy: ", accuracy)print("Confusion Matrix:\n", confusion_mat)print("Classification Report:\n", classification_rep)

Weights & Biases의 그래프는 테스트 데이터셋의 정확도를 보여 줍니다.

Weights & Biases에 로깅된 분류 보고서.
12단계: 모델 저장
이제 나중에 문서/기사 분류에 다시 사용할 수 있도록 모델을 저장하겠습니다. 추가로, wandb 클래스의 finish 함수를 호출해 실행을 완료 상태로 표시하고 모든 데이터를 업로드하도록 하겠습니다.
torch.save(model.state_dict(), 'article_categorization_model.pth')wandb.finish()
출력

그림은 터미널 출력 결과를 보여 줍니다.

Weights & Biases에 전체 로그 데이터가 기록된 모습을 보여 주는 그림.
결과 게시 - 모델 평가와 구현
기사 분류기 모델의 성능을 평가하기 위해 다음을 사용했습니다:
- 정확도
- 혼동 행렬
- 분류 보고서
모델은 테스트 데이터셋에서 정확도 99.47%를 달성했습니다. 분류 보고서는 정밀도, 재현율, F1 점수 등 세부 지표를 제시하며, 모든 평가 지표에서 모델이 매우 우수한 성능을 보였음을 보여 줍니다.
이 혼동 행렬은 데이터셋에서 이진 분류 모델의 성능을 나타냅니다. 행렬의 각 칸은 특정 범주에 속하는 사례의 개수를 의미하며, 참양성(TP), 거짓양성(FP), 참음성(TN), 거짓음성(FN)으로 구분됩니다.
여기에서는 혼동 행렬을 시각적으로 확인할 수 있습니다.

제공된 혼동 행렬을 기반으로 한 분석은 다음과 같습니다:
- 참양성(TP): 648
- 거짓양성(FP): 1
- 거짓음성(FN): 6
- 참음성(TN): 691
혼동 행렬을 보면 모델이 두 클래스 모두에서 높은 정확도와 정밀도로 매우 우수하게 동작했음을 알 수 있습니다. 거짓양성과 거짓음성 비율이 낮다는 것은 잘못된 예측이 매우 적었다는 의미로, 정확성이 최우선인 문서 분류 같은 작업에서 특히 중요합니다.
가이드 전반에서 마주하는 과제
간단한 기사 분류기를 구축하는 과정에서는 큰 어려움이 없습니다. 다만 몇 가지 사소한 과제가 발생하며, 다음과 같습니다:
- 데이터셋: 충분히 적절한 데이터셋을 찾는 일은 작은 과제입니다. 때로는 알맞은 유형을 찾지 못해 직접 데이터셋에 주석을 달아야 할 수도 있습니다.
- 클래스 불균형 데이터셋에서 클래스 분포가 불균형하면, 다수 클래스에서는 성능이 좋지만 소수 클래스에서는 성능이 떨어지는 편향된 모델이 될 수 있습니다. 이 문제를 완화하기 위해 클래스 가중치와 같은 기법이 필요할 수 있습니다.
- 텍스트 전처리: 데이터 정제에서 필수 단계이지만, 현재 데이터셋에서는 텍스트 전처리가 성능에 큰 영향을 주지 않습니다. 따라서 전처리 적용 여부에 따른 성능을 비교하는 편이 더 좋습니다. 또한 텍스트 전처리는 문서를 정리하는 데 시간이 걸리므로, 시간이 많이 드는 과정이기도 합니다.
결론
자동 기사 분류는 자연어 처리와 머신 러닝 분야에서 매우 흥미로운 주제입니다. 효율적인 검색과 검색 결과 제공, 개인화된 콘텐츠 추천, 체계적인 콘텐츠 관리 등 폭넓은 활용처가 있습니다. 간단한 다층 퍼셉트론(MLP)을 사용하면 문서/기사 분류기를 구축해 99%의 정확도를 달성할 수 있습니다. 앞으로 더 많은 데이터를 수집하고, 알고리즘을 정교화하며, 모델을 확장해 나가면 다양한 디지털 플랫폼과 애플리케이션 전반에서 효율적인 정보 관리, 개인화된 콘텐츠 제공, 향상된 사용자 경험이라는 새로운 가능성을 열 수 있습니다.
Add a comment