Index
나이브 베이즈(Naive Bayes) 알고리즘이란?
확률 기반 머신러닝 알고리즘의 대표격인 나이브 베이즈 알고리즘은 데이터의 각 특성이 서로 독립할 것이라는 나이브(Naive)
한 가정을 전제로 하고 새로운 입력이 들어왔을때 데이터를 어느 레이블로 분류하는 것이 확률적으로 가장 높은가? 라는 철학으로 동작하는 알고리즘이다.
조건부 확률
,우도
,사전확률
,결합 확률
,독립
등의 생소한 단어들이 등장할텐데 천천히 나이브 베이즈 알고리즘이 어떤건지 자세히 알아보도록 하자.
조건부 확률에서 베이즈 공식까지
조건부 확률
어떤 사건이 일어났다는 가정했을 때 다른 어떤 사건이 일어날 확률을 조건부 확률이라 한다.
예를 들어 내가 버스 정류장까지 5분만에 뛰어갈 수 있다고 할때 버스를 놓치지 않을 확률은 얼마일까? 와 같은 형식이 조건부 확률이다.
두 사건 A , B 가 있다고 할때 각 사건이 일어날 확률은 P(A)
, P(B)
와 같이 표현하고
‘ 사건 A 가 일어났을때 B가 일어날 확률 ‘ 과 같은 조건부 확률 은 P(B|A)
와 같이 표현한다.
또 , ‘ A ,B 가 동시에 일어날 확률 ‘ 과 같은 문제는 결합 확률 이라 하는데 P(A∩B)
혹은 P(A,B)
와 같이 표현한다.
조건부 확률의 계산은 위 표현식들의 조합을 통해 이루어진다.
\[P(B|A) = \frac {P(B \cap A)}{P(A)}\]말로 풀어보자면 ,
A가 일어났다고 가정할때 B가 일어날 확률
= A , B 가 동시에 일어날 확률
÷ A가 일어날 확률
로 계산되는 것이다.
그런데 , 결합 확률이라고 했던 P(A∩B)
는 교환법칙의 성질을 만족하는 연산으로 P(A∩B)
= P(B∩A)
이다.
말로하면 당연하긴 하지만 (내일 비가온다(A) 와 내가 지각한다(B) 가 동시에 일어날 확률과 내일 내가 지각한다(B) 와 비가온다(A) 가 동시에 일어날 확률은 같다.) , 이는 베이즈 공식의 기초가 되는 개념이 된다.
앞의 조건부 확률 계산식으로부터 결합확률 P(B∩A)
는 다음과 같이 다시 쓸 수 있는데 ,
\[P(B \cap A) = P(B|A) \times P(A)\]
P(B∩A)
= P(A∩B)
라고 했으므로 , 다음과 같은 식이 만들어진다.
\[P(B \cap A) = P(B|A) \times P(A) \dots \dots 1\] \[P(A \cap B) = P(A|B) \times P(B) \dots \dots 2\] \[P(B \cap A) = P(A \cap B) \dots \dots 3\] \[P(B|A) \times P(A) = P(A|B) \times \dots \dots 4\] \[\therfore P(B|A) = \frac{P(A|B \times P(B))}{P(A)} \dots \dots 5\]
이때 , 최종적으로 정리된 5번 식이 바로 베이즈 공식 이다.
베이즈 공식은 식 자체로는 두 조건부 확률간의 관계정도를 나타내는 식으로 보일 수 있지만 실제로 이 공식은 우리가 알지 못하는 미래의 확률을 이미 확인된 확률을 통해 추정할 수 있다는 의미를 갖는 중요한 공식이다.
미래 확률을 추정한다는 말을 예시로 풀어보자면 ,
A 사건
: 무릎이 시리다.
B 사건
: 비가온다.
라고 두 사건 A , B 을 설정해보자.
이때 지금 내 무릎이 아프다면 , 곧이어 비가 올 확률은 어떻게 계산할 수 있을까?
확률식으로 표현했을때 P(B|A)
로 표현되는 이러한 미래의 확률이 우리가 궁금한 사후 확률 인 것이다.
이러한 사후 확률은 위에서 확인했던 베이즈 공식에 따라 [ P(A|B)·P(B) ] ÷ P(A)
로 계산할 수 있는데
각 확률을 예시에 맞춰 적용하면 다음과 같다.
P(A|B)
: 비가 왔을때 , 내가 무릎이 시렸던 비율 ( 경험 확률 )
P(B)
: 전체 날짜 중 비가 왔던 비율 ( 경험 확률 )
P(A)
: 전체 날짜 중 내 무릎이 시렸던 비율 ( 경험 확률 )
계속 부가 설명으로 경험 확률이라는 말을 썼는데 , 우리가 예측하는 확률이 아닌 이미 관찰된 데이터를 통해 계산된 확률값임을 구분하기 위해 사용하였다.
또 , 베이즈 이론에서는 위의 각 경험 확률에 대한 용어가 존재하는데 다음과 같다.
P(A|B)
: 우도 , Likelihood
P(B)
: 사전 확률 , Prior
P(A)
: 주변 우도 , Evidence or Marginal likelihood
P(B|A)
: (우리가 실제로 관심 있는 확률) 사후 확률 , Posterior
위 용어로 베이즈 이론을 종합하여 다시 작성하면 , 우리가 실제로 알고 싶은 사후확률 을 계산하는 식은 다음과 같이 나타낼 수 있다.
\(Posterior = \frac{Likelihood \times Prior}{Evidence}\)
나이브 베이즈 알고리즘을 머신러닝에 어떻게 적용하는걸까?
그렇다면 이와 같은 베이즈 이론이 머신러닝에 어떻게 적용되는 것일까?
나이브 베이즈 알고리즘은 확률 기반의 데이터 분류 머신러닝 알고리즘이라 하였는데 ,
앞서 예시를 들며 사용하였던 사건 A , B 를 머신러닝과 관련된 용어로 바꾸면 조금 더 이해가 쉽다.
하나의 독립변수와 하나의 (범주형) 종속변수로 이루어진 데이터에 대해 다음과 같이 사건을 설정해보자.
A 사건
: 어떤 데이터의 독립변수 값이 3이다.
B 사건
: 어떤 데이터의 종속 변수가 7이다. (7번 레이블이다)
이런 상황에서 새로운 입력이 들어왔는데 독립 변수의 값이 3일때 , 7번 레이블로 분류될 확률은 어떻게 될까?
\[probability = P(label=7|input=3) = P(B|A)\]
위와 같은 식으로 표현되며 , 이를 우리가 궁금한 사후 확률 이라고 하는것이다.
그럼 베이즈 공식에서 확인했듯 , 사후 확률은 우도,주변우도,사전 확률을 통해 계산할 수 있는데
\[P(label=7|input=3) = \frac{P(input=3|label=7) \times P(label=7)}{P(input=3)}\]
우도( P(input=3|label=7)
) , 사전확률( P(label=7)
) , 주변우도 ( input=3
) 모두 우리가 이미 학습용으로 가지고 있는 데이터에서 계산할 수 있는 확률값이다.
베이지안 기반 분류 모델에서는 이 같은 사후확률을 모두 계산하여 비교해보고 가장 확률이 높은쪽으로 데이터를 분류하는것이다.
독립변수가 여러개인 경우에는 사후확률을 어떻게 계산할까?
일반적인 상황이라면 독립변수가 2개 이상일때는 식의 복잡도가 꽤 올라간다. 앞서 언급한 예시에서 새로운 사건 C 가 추가된 상황을 상상해보자.
A 사건
: 어떤 데이터의 독립변수1 의 값이 3이다.
B 사건
: 어떤 데이터의 종속 변수가 7이다. (7번 레이블이다)
c 사건
: 어떤 데이터의 독립변수2 의 값이 5이다.
이런 상황에서 사후확률 P( label=7 | input1=3 , input2=5 )
은
P( input1=3 , input2=5 | label=7 ) · P( label=7 )
÷ P(input1=3 , input2=5)
로 계산하게된다.
하나의 사건을 더 추가하여 확인해보면 알겠지만 , 독립변수의 수가 증가할수록 우도와 주변우도의 계산이 복잡하고 많은 연산을 요구하는 확률값으로 예상할 수 있다.
그렇기 때문에 나이브 베이지안 모델에서는 모든 독립사건을 서로 독립적인 사건이라 가정한다.
독립적인 사건이란 , 서로의 발생에 영향이 없는 관계를 의미하며 독립적인 관계인 사건들의 결합확률은 각 사건의 단일발생 확률들의 곱으로 계산할 수 있다.
\[P(A \cap B) = P(A) \times P(B)\]
이러한 가정이 있으면 위의 사후 확률 계산은 상당히 간단해진다.
\[P(B|A,C) = \frac{P(A,C|B) \times P(B)}{P(A,C)} = \frac{P(A|B) \times P(C|B) \times P(B)}{P(A) \times P(B)}\]
여기서 생각해보면 종속변수가 7일 사후확률이 아니라 다른 분류값일 사후확률의 경우에도 분모에 위치한 주변우도의 값은 변하지 않는다. 새로 들어온 독립변수1 , 독립변수2 의 값은 변하지 않기 때문이다. 따라서 식을 등식이 아닌 비례 관계로 나타내면 다음과 같다.
\[P(B|A,C) \propto P(A|B) \times P(C|B) \times P(B)\]
즉 , 각 레이블별로 사후확률을 계산함에 있어 주변 우도는 굳이 계산할 필요 없고 우도와 사전확률의 곱만 서로 비교하면 어느 분류로 처리하는것이 확률적으로 가장 맞을지 알 수 있는 것이다. 또 , 우도와 사전확률의 확률값 또한 매 사후확률 계산시 마다 지속적으로 계산할 필요 없이 초기에 1번씩만 계산해놓으면 더 이상 불필요한 계산을 할 필요가 없어진다.
이에 나이브 베이지안 모델은 학습 데이터로부터 모델을 생성하는 과정에서 우도 표 를 만들어 저장하고 데이터가 새로 들어봐 분류 작업을 처리해야할때 , 각 레이블에 대하여 사후확률을 구하는데 우도 표에서 각 우도를 참조하여 사후확률을 계산한다.
멋있다!
나이브 베이즈 모델의 종류
가우시안 모델
- 독립변수가 연속형 데이터일때 정규 분포를 가정하고 사후 확률을 계산하여 비교한다.
베르누이 모델
- 독립변수가 이진 데이터일때 사용하는 모델로 나이브 가우시안 모델의 대표적 활용 예시인 스팸 메일 분류가 베르누이 모델을 활용한다.
다항 분포 모델
- 독립변수가 이산형 데이터일때 사용하는 모델로 보통 출현 횟수와 관련된 데이터를 다루는 모델이다.
나이브 베이즈 알고리즘의 장단점
이러한 확률기반 베이즈 알고리즘의 장·단점을 간략히 정리해보자면 다음과 같다.
Pros
- 모든 독립변수가 독립적인 관계일 것이라는 나이브한 대전제에도 불구하고 실전에서 꽤 높은 성능을 보이며 문서 분류 문제의 경우 특히나 강한 면모를 보인다.
Cons
- 비교적 많은 경우에 성능이 괜찮을뿐이지 독립의 가정을 하기 어려운 데이터들이나 다른 유형의 분류 문제에서는 적용하기 어렵다.
- 단어 빈도와 같이 이산형 독립변수에 대해서는 이전에 관측되지 않았던 데이터라 우도가 0이 되어버리는 경우가 발생할 위험이 있다. 이에 스무딩 이라는 방법을 활용하여 정확하지 않은 zero-likelihood 문제를 해결할 수 있다.
※ 스무딩(smoothing) : 1과 같은 최소의 데이터를 분자에 적용하여 0이 아닌 작은 우도값이 되도록 하는 기법
R을 활용한 나이브 베이즈 모델링
R을 활용한 나이브 베이지안 기반 스팸 메일 분류기 실습
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 스팸 메일 분류기를 통해 예측하고 결과 혼동행렬을 출력해보기
library(readxl)
library(tm)
library(SnowballC)
library(e1071)
library(gmodels)
sms_train <- read.csv('C:/임시/RData/sms_spam_ansi.txt')
sms_test <- read.csv('C:/임시/RData/햄스팸테스트.txt',header=F)
# 병합 후 전처리 -> 끝나면 다시 분할
split_point <- dim(sms_train)[1]
names(sms_test) <- c('type','text') # 칼럼명 통일 (병합에 필요)
data <- rbind(sms_train,sms_test) # 병합
table(data$type) # 4818 hams 751 spams
# 전처리 -------------------------------------------
sms_corpus <- VCorpus(VectorSource(data$text)) # 코퍼스 생성
sms_corpus_preprocessed <- tm_map(sms_corpus,removeNumbers) # 숫자 제거
sms_corpus_preprocessed <- tm_map(sms_corpus_preprocessed,content_transformer(tolower)) # 소문자 통일
sms_corpus_preprocessed <- tm_map(sms_corpus_preprocessed,removePunctuation) # 특수문자 제거
sms_corpus_preprocessed <- tm_map(sms_corpus_preprocessed,removeWords,stopwords()) # 불용어 제거
sms_corpus_preprocessed <- tm_map(sms_corpus_preprocessed,stemDocument) # 어근 변환
sms_corpus_preprocessed <- tm_map(sms_corpus_preprocessed,stripWhitespace) # 공백 제거
# 문서 단어 행렬 생성 ----------------------------------
sms_dtm <- DocumentTermMatrix(sms_corpus_preprocessed)
sms_dtm #terms :6909 #Non-/sparse entries: 43348/38416166 #Sparsity: 100%
# 희소성 리미팅
sms_dtm <-removeSparseTerms(sms_dtm,0.999)
sms_dtm #terms :1200 #Non-/sparse entries: 34159/6648641 #Sparsity: 99%
# 빈도 수치 범주형 변환
sms_dtm <- apply(sms_dtm, MARGIN = 2, function(x)ifelse(x>0,'Y','N'))
# 학습,예측 데이터 분할
xtrain <- sms_dtm[1:split_point,]
ytrain <- factor(data$type[1:split_point])
xtest <- sms_dtm[(split_point+1):5569,]
ytest <- factor(data$type[(split_point+1):5569])
# 베이시안 분류기 생성&예측
sms_Classifier <- naiveBayes(xtrain,ytrain,laplace = 1)
ypred <- predict(sms_Classifier,xtest)
# 성능 출력
CrossTable(ypred,ytest,
dnn=c('predicted','actual'))
# 정확도 100%
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| actual
predicted | ham | spam | Row Total |
-------------|-----------|-----------|-----------|
ham | 6 | 0 | 6 |
| 1.600 | 2.400 | |
| 1.000 | 0.000 | 0.600 |
| 1.000 | 0.000 | |
| 0.600 | 0.000 | |
-------------|-----------|-----------|-----------|
spam | 0 | 4 | 4 |
| 2.400 | 3.600 | |
| 0.000 | 1.000 | 0.400 |
| 0.000 | 1.000 | |
| 0.000 | 0.400 | |
-------------|-----------|-----------|-----------|
Column Total | 6 | 4 | 10 |
| 0.600 | 0.400 | |
-------------|-----------|-----------|-----------|
sklearn 패키지를 활용한 나이브 베이즈 모델링
참고자료
- 나의 첫 머신러닝/딥러닝 Chapter 4.5