[머신러닝을 위한 파이썬] Case Study - News Categorization-1

2024. 12. 22. 16:56MOOC

뉴스 분류를 위한 Python 코드 정리

이 코드는 Bag of Words와 Cosine Similarity를 사용하여 뉴스 기사 간 유사도를 계산하고, 이를 바탕으로 뉴스 기사를 분류하는 시스템을 구현한다.


1. 주요 개념

  1. Bag of Words
    • 단어의 출현 빈도를 벡터로 표현하여 문서를 수치화.
  2. Cosine Similarity
    • 두 벡터의 방향(각도)을 기반으로 유사도를 계산.
    • 값이 1에 가까울수록 유사, 0에 가까울수록 무관함.

2. 주요 단계

1) 데이터 불러오기

  • get_file_list(dir_name): 주어진 디렉토리에서 파일 목록을 가져옴.
  • get_conetents(file_list): 파일 내용을 읽어 각 뉴스의 텍스트와 카테고리를 반환.
import os

def get_file_list(dir_name):
    return os.listdir(dir_name)

def get_conetents(file_list):
    y_class = []
    X_text = []
    class_dict = {
        1: "0", 2: "0", 3:"0", 4:"0", 5:"1", 6:"1", 7:"1", 8:"1"
    }

    for file_name in file_list:
        try:
            with open(file_name, "r", encoding="cp949") as f:
                category = int(file_name.split(os.sep)[1].split("_")[0])
                y_class.append(class_dict[category])
                X_text.append(f.read())
        except UnicodeDecodeError as e:
            print(e)
            print(file_name)
    return X_text, y_class

2) 텍스트 전처리

  • get_cleaned_text(text): 텍스트에서 특수문자를 제거하고 소문자로 변환.
  • get_corpus_dict(text): 전체 단어에 고유 인덱스를 부여하여 사전 생성.
import re
from collections import OrderedDict

def get_cleaned_text(text):
	# 소문자 변환과 공백처리
    return re.sub('\W+', '', text.lower())

def get_corpus_dict(text):
	# 단어를 기준으로 나누기
    text = [sentence.split() for sentence in text]
    # 전처리 함수로 텍스트 전처리
    cleaned_words = [get_cleaned_text(word) for words in text for word in words]
	
    #순서가 유지되는 딕셔너리 에 저장
    corpus_dict = OrderedDict()
    for i, v in enumerate(set(cleaned_words)):
        corpus_dict[v] = i
    return corpus_dict

3) 벡터 생성

  • get_count_vector(text, corpus): 각 문서를 Bag of Words 벡터로 변환.
def get_count_vector(text, corpus):
	# 각 문장을 단어로 나뉘어 리스트로 만든다.
    text = [sentence.split() for sentence in text]
    # 각 단어를 corpus 에서 해당하는 번호로 매핑
    word_number_list = [[corpus[get_cleaned_text(word)] for word in words] for words in text]

	# 각 문장은 corpus 길이의 리스트로 표현
    X_vector = [[0 for _ in range(len(corpus))] for _ in range(len(text))]
    
    # word_number_list를 순회하며 각 문장의 단어 빈도를 카운트
    for i, word_numbers in enumerate(word_number_list):
        for word_number in word_numbers:
            X_vector[i][word_number] += 1
    return X_vector

4) 유사도 계산

  • get_cosine_similarity(v1, v2): 두 벡터의 코사인 유사도를 계산.
  • get_similarity_score(X_vector, source): 기준 문서와 나머지 문서 간 유사도 계산.
import math

# 코사인 유사도 함수정의
def get_cosine_similarity(v1, v2):
    sumxx, sumxy, sumyy = 0, 0, 0
    for x, y in zip(v1, v2):
        sumxx += x * x
        sumyy += y * y
        sumxy += x * y
    # 코사인 유사도의 공식
    return sumxy / math.sqrt(sumxx * sumyy)

# 기준 문장과 다른 문장들간 유사도를 계산하는 함수 정의
def get_similarity_score(X_vector, source):
    source_vector = X_vector[source] # 기존의 문장들을 가져옴
    similarity_list = []
    for target_vector in X_vector: # 모든 문장의 벡터를 반복
        similarity_list.append(get_cosine_similarity(source_vector, target_vector)) # 기준문장과 다른 문장간의 코사인 유사도를 계산
    return similarity_list

5) 유사 뉴스 추출

  • get_top_n_similarity_news(similarity_score, n): 상위 n개의 유사 문서를 반환.
def get_top_n_similarity_news(similarity_score, n):
    import operator
    x = {i: v for i, v in enumerate(similarity_score)} # 유사도 점수를 딕셔너리로 변환 
    sorted_x = sorted(x.items(), key=operator.itemgetter(1), reverse=True) #내림차순 정렬
    return sorted_x[1:n+1] # 상위 n개의 유사도 점수와 해당 인덱스 반환

6) 성능 평가

  • get_accuracy(similarity_list, y_class, source_news): 예측 정확도를 계산.
def get_accuracy(similarity_list, y_class, source_news):
    source_class = y_class[source_news]
    return sum([source_class == y_class[i[0]] for i in similarity_list]) / len(similarity_list)

3. 실행

if __name__ == "__main__":
    dir_name = "news_data"
    file_list = get_file_list(dir_name)
    file_list = [os.path.join(dir_name, file_name) for file_name in file_list]

    X_text, y_class = get_conetents(file_list)

    corpus = get_corpus_dict(X_text)
    print("Number of words:", len(corpus))

    X_vector = get_count_vector(X_text, corpus)

    result = []
    for i in range(len(X_vector)):
        similarity_score = get_similarity_score(X_vector, i)
        similarity_news = get_top_n_similarity_news(similarity_score, 10)
        accuracy_score = get_accuracy(similarity_news, y_class, i)
        result.append(accuracy_score)

    print("Average Accuracy:", sum(result) / len(result))

요약

  1. 뉴스 데이터를 벡터로 변환(Bag of Words).
  2. 코사인 유사도를 계산하여 문서 간 유사성 평가.
  3. 상위 유사한 문서를 추출하고 정확도 측정.