본문 바로가기
내가 하는 데이터분석/내가 하는 머신러닝

[나이브 베이즈 분류, Naive Bayes Classification] - MultinomialNB with Python

by Pymoon 2023. 2. 17.

데이터가 각 클래스에 속할 특징 확률을 계산하는 조건부 확률 기반의 분류 방법인 나이브베이즈(NaiveBayes)에 대해서 정리해 보자.

 

그중에서 오늘은 MultinomialNB에 대해서 알아볼 것이다.

 

 

이 전의 머신러닝에서는 나이브베이즈(NaiveBayes) 기법 중 GaussianNB에 대해서 알아보며 실습해 보았다.

 

나이브 베이즈 분류(Naive Bayes Classification) - GaussianNB with Python

데이터가 각 클래스에 속할 특징 확률을 계산하는 조건부 확률 기반의 분류 방법인 나이브베이즈(NaiveBayes)에 대해서 정리해 보자. 그중에서 오늘은 GaussianNB에 대해서 알아볼 것이다. 이 전의 머

py-moon.tistory.com

 

 

 

나이브(Naive)는 직역하면 단순하다, 순진하다는 의미를 가진다.

 

 

베이즈(Bayes)는 베이지안 통계를 기반으로 입력특징이 클래스 전체의 확률분포 대비 특정 클래스에 속할 확률을 정리하였다는 점에서 비롯되었다.

 

 

나이브베이즈 분류 기법이 예측한 특징을 상호 독립적이라는 가정하에 확률 계산을 단순화하고 모든 변수가 동등하다는 특징에서 나이브(Naive) 베이즈(Bayes)라는 이름이 결합하게 되었다.

 

 

이제, 나이브베이즈(NaiveBayes) 개념을 이해하기 위해서는 베이즈 정리에 대해 간단히 알아보자.

 


 

베이즈 정리(Bayes' Theorem)는 두 확률 변수의 사전확률과 사후확률 사이의 관계를 나타내는 정리이다.

 

사건 A, B가 있을 때, 사건 B가 일어난 것을 전제로 한 사건 A의 조건부 확률을 구하는 것이다.

 

scikit-learn에서 구현된 나이브베이즈 분류기는 BernoulliNB, MultinomialNB, GaussianNB가 있다.

 

 

 

이 중 오늘 실습해 볼 분류기는 MultinomialNB이다.

 

MultinomialNB은 이산형 데이터를 분류할 때 적용할 수 있다.

 

데이터의 출현 횟수에 따라 값을 달리 한 데이터에도 사용할 수 있다.

 


 

IMDB영화 리뷰 데이터를 MultinomialNB의 분류분석을 통해 영화에 대한 긍정/부정적 평가를 분류해 보자.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from keras.datasets import imdb
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings(action='ignore')
 
(X_train, y_train), (X_test, y_test) = imdb.load_data()
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
 
 
(25000,) (25000,) (25000,) (25000,)
cs

 

> MultinomialNB을 활용한 분류 분석을 위해 필요한 라이브러리와 데이터셋을 불러와준다.

 

> 본 실습에서 쓰일 데이터는 정제가 되어있지 않기 때문에 오픈소스코드를 활용해서 정제해 준다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
word_to_index = imdb.get_word_index()
index_to_word = {}
 
for key, value in word_to_index.items():
    index_to_word[value + 3= key
 
for index, token in enumerate(('<pad>''<sos>''<unk>')):
    index_to_word[index] = token
    
train_reviews = []
for X in X_train:
    tmp = ' '.join([index_to_word[index] for index in X])
    train_reviews.append(tmp)
    
test_reviews = []
for X in X_test:
    tmp = ' '.join([index_to_word[index] for index in X])
    test_reviews.append(tmp)
    
train = pd.concat([pd.DataFrame(train_reviews), pd.DataFrame(y_train)], axis = 1)
train.columns = ['reviews''label']
train['reviews'= train['reviews'].str[6:]
 
test = pd.concat([pd.DataFrame(test_reviews), pd.DataFrame(y_test)], axis = 1)
test.columns = ['reviews''label']
test['reviews'= test['reviews'].str[6:]
 
print(train.head(), '\n')
print(test.head())
 
 
                                             reviews  label
0  this film was just brilliant casting location ...      1
1  big hair big boobs bad music and a giant safet...      0
2  this has to be one of the worst films of the 1...      0
3  the scots excel at storytelling the traditiona...      1
4  worst mistake of my life br br i picked this m...      0 
 
                                             reviews  label
0  please give this one a miss br br kristy swans...      0
1  this film requires a lot of patience because i...      1
2  many animation buffs consider wladyslaw starew...      1
3  i generally love this type of movie however th...      0
4  like some other people wrote i'm a die hard ma...      1
cs

 

> 위 코드를 통해서 분석에 사용할 수 있게끔 리뷰 데이터를 두 변수로 나누어 주고, 문장도 어느 정도 전처리가 이루어진 것을 확인할 수 있다.

 

 

 

 

1
2
3
4
5
6
7
x_train, x_test = train['reviews'].values, test['reviews'].values
y_train, y_test = train['label'].values, test['label'].values
 
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)
 
 
(25000,) (25000,) (25000,) (25000,)
cs

 

> 분석에 사용하기 위해 독립변수와 종속변수를 정의하고 데이터셋을 분할해 준다.

 

 

 

 

1
2
3
4
5
6
7
8
from sklearn.feature_extraction.text import CountVectorizer
 
cv = CountVectorizer(binary = False)
x_traincv = cv.fit_transform(x_train)
x_traincv.shape
 
 
(2500074703)
cs

 

> MultinomialNB은 이산형 데이터만을 입력데이터로 취급하는 기법이라서 데이터가 0과 1이 되도록 전처리를 진행해줘야 한다.

 

> 따라서 CountVectorizer에서 binary를 False로 두어 단어가 한 번 이상 등장하면 개수를 세어주도록 한다.

 

> 그러고 난 후, 전처리를 시킨 train데이터의 shape을 확인해 보니 (25000, 74703)으로 확인이 되었다.

 

> 단어가 74,703개라는 뜻이다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
print(cv.inverse_transform(x_traincv)[0])
 
 
['this' 'film' 'was' 'just' 'brilliant' 'casting' 'location' 'scenery'
 'story' 'direction' 'everyone' 'really' 'suited' 'the' 'part' 'they'
 'played' 'and' 'you' 'could' 'imagine' 'being' 'there' 'robert' 'redford'
 'is' 'an' 'amazing' 'actor' 'now' 'same' 'director' 'norman' 'father'
 'came' 'from' 'scottish' 'island' 'as' 'myself' 'so' 'loved' 'fact'
 'real' 'connection' 'with' 'witty' 'remarks' 'throughout' 'were' 'great'
 'it' 'much' 'that' 'bought' 'soon' 'released' 'for' 'retail' 'would'
 'recommend' 'to' 'watch' 'fly' 'fishing' 'cried' 'at' 'end' 'sad' 'know'
 'what' 'say' 'if' 'cry' 'must' 'have' 'been' 'good' 'definitely' 'also'
 'congratulations' 'two' 'little' 'boy' 'of' 'paul' 'children' 'are'
 'often' 'left' 'out' 'praising' 'list' 'think' 'because' 'stars' 'play'
 'them' 'all' 'grown' 'up' 'such' 'big' 'profile' 'whole' 'but' 'these'
 'should' 'be' 'praised' 'done' 'don' 'lovely' 'true' 'someone' 'life'
 'after' 'shared' 'us']
cs

 

> 첫 번째 데이터를 예시로 변환된 데이터를 디코딩하여 어떤 단어들이 있는지 확인해 본다.

 

 

 

 

1
2
3
4
from sklearn.naive_bayes import MultinomialNB
 
mnb = MultinomialNB()
mnb.fit(x_traincv, y_train)
cs

 

> 사용할 분류기인 MultinomialNB을 불러와 객체를 생성하고 학습을 진행한다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
from sklearn.metrics import accuracy_score
 
x_testcv = cv.transform(x_test)
pred = mnb.predict(x_testcv)
 
acc = accuracy_score(y_test, pred)
print('Accuracy Score : {:.2f}'.format(acc))
 
 
Accuracy Score : 0.81
cs

 

> 예측된 값을 pred변수에 저장해 주고, y_test값과 비교하여 정확도를 산출해 준다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
from sklearn.metrics import classification_report
 
print(classification_report(y_test, pred))
 
 
              precision    recall  f1-score   support
 
           0       0.78      0.88      0.83     12500
           1       0.86      0.75      0.80     12500
 
    accuracy                           0.81     25000
   macro avg       0.82      0.81      0.81     25000
weighted avg       0.82      0.81      0.81     25000
cs

 

> 정확도 이외에 성능평가지표를 불러와 다른 기준으로 바라본 성능에 대해서도 확인해 본다.

 

 


 

OUTTRO.

 

 

나이브베이즈 분류는 간단하고 빠르며 노이즈와 결측치에 강하다는 특징과 예측을 위한 추정확률을 쉽게 얻을 수 있다는 장점을 가지고 있다.

 

하지만, 나이브베이즈의 개념상 모든 특징이 동등하게 중요하며 독립이라고 가정하기 때문에, 가정이 잘못된 경우들이 생기고, 가정된 확률이 예측된 클래스보다 신뢰성이 떨어진다는 단점이 존재한다.

 

 

 

그럼에도 나이브베이즈 분류는 언제 사용하는데 적절한가?

 

  • 과거의 빈도를 보여주는 데이터가 많지 않거나 자주 일어나지 않는 사건이어서 빈도주의적 추론의 사용이 적절하지 않을 때 나이브베이즈 분류를 사용한다.

 

  • 베이지안 접근은 계속해서 값을 수정하면서 좀 더 현실적인 추정치를 찾아나가는 기법이기 때문에 추정의 목적이 과거나 현재보단 미래 예측일 때 나이브베이즈 분류를 사용한다.