본문 바로가기
Study/머신러닝

[3] 나이브 베이즈 분류를 사용한 텍스트 분류

by 투말치 2020. 7. 25.

목차

    반응형

    텍스트 분류란?

    - 텍스트를 카테고리별로 분류하는 것을 말한다.

    - 텍스트 분류의 예시로는 스팸 분류, 감정 분류, 의도 분류 등이 있다.

     

    텍스트 분류 방법

    - 지도 학습을 통한 텍스트 분류 모델 : 나이브 베이즈 분류, SVM, 신경망, 선형 분류 등

    - 비지도 학습을 통한 텍스트 분류 모델 : K-평균 군집화, 계층적 군집화

     

    나이브 베이즈(Naive Bayse) 분류란?

    - 나이브 베이즈 분류는 베이즈 정리를 기본으로 하는 분류 기법

    - 스팸 필터, 감정 분석, 추천 시스템 등에 활용된다.

    - 학습을 많이 시킬수록 분류 능력이 향상된다.

    - 나이브(naive)라는 단어가 붙는 이유는 데이터셋의 모든 특징들이 동등하고 독립하다고 가정하기 때문이다.

     

     

     

    베이즈 정리

    베이즈 정리

     

    - P(A) : A가 일어날 확률 (사전 확률)

    - P(B) : B가 일어날 확률

    - P(A|B) : B가 일어난 후 A가 일어날 확률 (사후 확률)

    - P(B|A) : A가 일어난 후 B가 일어날 확률

    - 사전 확률 : 현재 가지고 있는 정보를 기초로하여 정한 초기확률 또는 확률 시행 전에 이미 가지고 있는 지식을 통해 부여한 확률

    - 사후 확률 : 사건 발생 후에 어떤 원인으로부터 일어난 것이라고 생각되어지는 확률 또는 추가된 정보로부터 사전정보를 새롭게 수정한 확률

     

     

     

    [실습 1 - 베이지안 필터 구현]

    import math,sys
    from konlpy.tag import Okt
    
    class BayesianFilter:
        def __init__(self): 
            self.words=set() #출현한 단어 기록, set() : 공집합 생성
            self.word_dict={} #카테고리마다의 출현 횟수 기록
            self.category_dict={} #카테고리 출현 횟수 기록
    
        #형태소 분석
        def split(self, text):
            results=[]
            okt=Okt()
    
            #단어의 기본형 사용
            malist=okt.pos(text, norm=True, stem=True)
            for word in malist:
            #어미/조사/구두점 제외
                if not word[1] in ["Josa", "Eomi", "Punctuation"]:
                    results.append(word[0])
                
            return results
    
        #단어와 카테고리의 출현 횟수 세기
        def inc_word(self, word, category):
            #단어를 카테고리에 추가
            if not category in self.word_dict:   #해당 카테고리가 word_dict에 없는 경우
                self.word_dict[category]={}      #카테고리 생성(딕셔너리)
            if not word in self.word_dict[category]: #단어가 해당 카테고리에 없으면 
                self.word_dict[category][word]=0  #해당 카테고리에 단어 추가
            self.word_dict[category][word]+=1 #단어가 나왔으면 횟수 추가
            self.words.add(word)  #출현한 단어를 words 집합에 추가
                    
    
        def inc_category(self, category):
            #카테고리 계산하기
            if not category in self.category_dict: #카테고리가 category_dict에 없는 경우
                self.category_dict[category]=0  #카테고리 생성
            self.category_dict[category]+=1  #횟수 count
    
        #텍스트 학습
        def fit(self, text, category):
            word_list=self.split(text)  #텍스트 형태소 분석
            for word in word_list:
                self.inc_word(word, category) #단어 출현횟수 count
            self.inc_category(category) #카테고리 출현횟수 count
    
        #단어 리스트에 점수 매기기
        def score(self, words, category):
            score=math.log(self.category_prob(category))
            for word in words:
                score=+math.log(self.word_prob(word, category))
            return score   
    
        #예측하기
        def predict(self, text):
            best_category=None
            max_score=-sys.maxsize
            words=self.split(text)     
            score_list=[]
            for category in self.category_dict.keys(): #카테고리 별로 점수 매겨서 score_list에 추가
                score=self.score(words, category)
                score_list.append((category,score))
                if score>max_score:
                    max_score=score
                    best_category=category
            
            return best_category, score_list
        
    
        #카테고리 내부의 단어 출현 횟수 구하기
        def get_word_count(self, word, category):
            if word in self.word_dict[category]:  #단어가 카테고리에 존재하면
                return self.word_dict[category][word] #해당 단어의 출현횟수 return
            else:
                return 0
    
        #카테고리 계산
        def category_prob(self, category):
            sum_categories=sum(self.category_dict.values())  #모든 카테고리 출현 횟수의 합
            category_v=self.category_dict[category] #계산하고 싶은 카테고리의 출현 횟수를 category_v에 저장
            return category_v / sum_categories #해당 카테고리의 출현 확률을 return
    
        #카테고리 내부의 단어 출현 비율 계산
        def word_prob(self, word, category): 
            n=self.get_word_count(word, category)+1 #단어 출현 횟수
            d=sum(self.word_dict[category].values())+len(self.words) #카테고리의 출현 회수 + 출현한 단어들의 수(중복없음)
            return n/d

    - BayesianFilter 클래스를 만들어 베이지안 필터를 구현했다.

    - split() : 형태소 분석 함수

    - inc_word() : 단어가 카테고리에 없으면 추가하고, 단어를 집합에 추가하고, 단어 횟수를 세는 함수

    - inc_category() : 카테고리가 없으면 생성하고 카테고리 출현 횟수 세는 함수

    - fit() : 텍스트를 학습하는 함수

    - score() : 단어 리스트에 점수를 매기는 함수

    - predict() : 카테고리 별 점수를 바탕으로 분류 카테고리를 예측하는 함수

    - get_word_count : 단어의 출현횟수 세는 함수

    - category_prob / word_prob : 카테고리/단어의 출현 확률을 구하는 함수

     

     

     

    [실습 2 - 구현한 베이즈 필터를 사용해 스팸 분류 테스트]

    from bayes import BayesianFilter
    bf=BayesianFilter()
    
    #텍스트 학습
    bf.fit("파격 세일 - 오늘까지만 30% 할인", "광고")
    bf.fit("쿠폰 선물 & 무료 배송", "광고")
    bf.fit("현데계 백화점 세일", "광고")
    bf.fit("봄과 함께 찾아온 따뜻한 신제품 소식", "광고")
    bf.fit("인기 제품 기간 한정 세일", "광고")
    bf.fit("오늘 일정 확인", "중요")
    bf.fit("프로젝트 진행 상황 보고", "중요")
    bf.fit("계약 잘 부탁드립니다", "중요")
    bf.fit("회의 일정이 등록되었습니다.", "중요")
    bf.fit("오늘 일정이 없습니다.", "중요")
    
    
    #예측
    pre, scorelist=bf.predict("재고 정리 할인, 무료 배송")
    print("결과 = ", pre)
    print(scorelist)

     

     

    [실습 2 - 결과화면]

    결과를 보면 해당 텍스트는 광고로 분류되었다. 

    출현한 단어 리스트를 보면 다음과 같다. (bf.words로 볼 수 있음)

    [실습 2 - 학습을 통해 추가된 단어들]

     

     

     

     

     

    참고 자료

     

    실습 : 파이썬을 이용한 머신러닝, 딥러닝 실전 개발 입문_ 쿠지라 히코우즈쿠에 저  

     

    https://zzaebok.github.io/machine_learning/bayesian-statistics-and-machine-learning/

     

    베이지안 통계와 머신 러닝

    Intro학부 인공지능 수업, 컴퓨터 비전 수업의 Generative Model들을 배우면서 prior가 어쩌니, 확률분포에서 샘플링을 하니 마니 하는 이야기를 들은 적이 있다.빈도론자로만 자라온 내게는 와닿지 않�

    zzaebok.github.io

    https://gomguard.tistory.com/6

     

    [머신러닝] 나이브 베이즈 (Naive Bayes)

    지도학습 알고리즘 지도학습 관련 알고리즘들로는 최근접 이웃 (Nearest Neighbor) 나이브 베이즈 (Naive Bayes) 의사결정 트리 (Decision Trees) 분류 규칙 학습자 (Classification Rule Learners) 선형 회귀 (..

    gomguard.tistory.com

     

    반응형