우노
[자연어처리] Naive Bayes란? 본문
스팸 필터
- 스팸 메일은 어떻게 분류 할 수 있을까?
Naive Bayes
- 통계적 분류기
- 각 분류별 확률 값을 계산
- 분류 해주는 게 아니라 확률 값을 계산해준다.
- 베이즈 정리에 따라 확률 계산
- 확률 계산의 단서(메일에 포함된 단어)들이 서로 조건부독립임을 가정
- 확률 계산이 단순해진다.
Naive Bayes 스팸 필터
새로운 메일이 왔다. 스팸인지 알아보려면?
- 해당 메일의 내용을 보지 않았을 때
- 예) 기존 스팸 메일과 일반 메일의 비율 만 보고 단순하게 일반 메일 80%, 스팸 메일 20%와 같이 예측 할 수 있다.
- 해당 메일의 내용을 봤을 때
- 메일에 포함된 단어들이 스팸 메일에 자주 나오는 단어인지, 일반 메일에 자주 나오는 단어인지를 살펴보고 스팸 여부를 판단 할 수 있다.
- 해당 메일의 내용을 보지 않았을 때
위와 같은 결과를 위해선 먼저, 스팸 메일과 일반 메일들을 수집한 뒤 다음을 계산해야 한다.
- P( S ) : 스팸 메일과 일반 메일의 비율을 계산
- P( wi | S = True ) : 각 단어가 스팸 메일에서 얼마나 자주 등장하는지 계산
- P( wi | S = False ) : 각 단어가 일반 메일에서 얼마나 자주 등장하는지 계산
새로운 메일(M)이 왔다. 스팸인지 알아보려면?
스팸메일일 확률
- P ( S = T ) * 해당 메일에 존재하는 단어들이 스팸메일에서 존재할 확률
일반메일일 확률
- P ( S = F ) * 해당 메일에 존재하는 단어들이 일반메일에서 존재할 확률
사전확률 (Prior probability)
- P( S ) : 가지고 있는 스팸 메일과 일반 메일의 단순한 비율을 계산
- P( S = T ) = 0.4
- P( S = F ) = 0.6
가능도 (Likelihood)
P( wi | S = True ) : 각 단어가 스팸 메일에서 얼마나 자주 등장하는지 계산
- 스팸 메일만 모아서 각 단어가 몇번이나 등장하는지 계산한다.
- 예
- P( 롤 | S = T ) = 1/15
- P( 시공 | S = T ) = 5/15
- P( 조아 | S = T ) = 3/15
- P( 옵치 | S = T ) = 0/15
- P( 폭풍 | S = T ) = 4/15
- P( 접속 | S = T ) = 2/15
P( wi | S = False ) : 각 단어가 일반 메일에서 얼마나 자주 등장하는지 계산
- 일반 메일만 모아서 각 단어가 몇번이나 등장하는지 계산한다.
- 예
- P( 롤 | S = F ) = 4/18
- P( 시공 | S = F ) = 1/18
- P( 조아 | S = F ) = 2/18
- P( 옵치 | S = F ) = 6/18
- P( 폭풍 | S = F ) = 1/18
- P( 접속 | S = F ) = 4/18
스팸 분류하기
새로운 메일이 왔다. 스팸인지 알아보려면?
- 메일 내용 : 시공 조아 폭풍 조아
해당 단어들이 등장했을 때, 이 메일이 스팸메일일 확률
- P( S = T | 시공, 조아, 폭풍, 조아)
베이즈 정리에 의해
P( 시공, 조아, 폭풍, 조아 | S = T ) P( S = T ) / P(시공, 조아, 폭풍, 조아)
참고) 베이즈 정리
두 확률 변수의 사전확률과 사후확률 사이의 관계를 나타내는 정리
나이브 베이즈의 조건부독립 가정에 의해 이 메일이 스팸메일일 확률
- P( 시공 | S=T ) P( 조아 | S=T) P( 폭풍 | S=T ) P( 조아 | S=T ) P( S=T ) / P(시공, 조아, 폭풍, 조아)
이 메일이 일반메일일 확률
- P( 시공 | S=F ) P( 조아 | S=F ) P( 폭풍 | S=F ) P( 조아 | S=F ) P( S=F ) / P(시공, 조아, 폭풍, 조아)
스팸메일 확률과 일반메일 확률을 비교 할 때, 동일만 분모를 사용하므로 제거해서 비교해도 된다.
스팸 분류하기
새로운 메일이 왔다. 스팸인지 알아보려면?
메일 내용 : 시공 조아 폭풍 조아
스팸메일 가능성: P(S=T) P(시공|S=T) P(조아|S=T) P(폭풍|S=T) P(조아|S=T)
- 스팸메일 가능성: 0.4 × (5/15) × (3/15) × (4/15) × (3/15) = 0.00142222
일반메일 가능성: P(S=F) P(시공|S=F) P(조아|S=F) P(폭풍|S=F) P(조아|S=F)
- 일반메일 가능성: 0.6 × (1/18) × (2/18) × (1/18) × (2/18) = 0.00002286
스팸메일일 확률이 더 크므로, 해당 메일은 스팸메일이다.
또 다른 메일이 왔다. 스팸인지 알아보려면?
메일 내용 : 시공 시공 시공 ㄱㄱ
- ㄱㄱ는 그 동안 스팸 메일에서 한 번도 등장하지 않았다.
스팸메일 가능성 : P(S=T) P(시공|S=T) P(시공|S=T) P(시공|S=T) P(ㄱㄱ|S=T)
- 스팸메일 가능성 : 0.4 × (5/15) × (5/15) × (5/15) × (0/15) = 0
일반메일 가능성 : P(S=F) P(시공|S=F) P(시공|S=F) P(시공|S=F) P(ㄱㄱ|S=F)
- 일반메일 가능성 : 0.6 × (1/18) × (1/18) × (1/18) × (6/18) = 0.00003429
ㄱㄱ는 그 동안 스팸 메일에서 한 번도 등장하지 않아 확률값이 0이므로
해당 메일은 일반 메일로 판단된다.
이 때, 사용하는 방법이 라플라스 스무딩이다.
라플라스 스무딩 (Smoothing)
기존 스팸메일이나 일반메일에서 한 번도 등장하지 않은 단어가 나올 경우 계산 결과가 이상해진다.
스무딩 : 모든 단어가 일반 / 스팸메일에 한 번씩은 등장했다고 가정 (한 번씩 → α 번씩)
스무딩 후 다시 메일을 분류해보면
메일 내용 : 시공 시공 시공 ㄱㄱ
스팸메일 가능성 : P(S=T) P(시공|S=T) P(시공|S=T) P(시공|S=T) P(ㄱㄱ|S=T)
- 스팸메일 가능성: 0.4 × (6/21) × (6/21) × (6/21) × (1/21) = 0.0004442
일반메일 가능성 : P(S=F) P(시공|S=F) P(시공|S=F) P(시공|S=F) P(ㄱㄱ|S=F)
- 일반메일 가능성: 0.6 × (2/24) × (2/24) × (2/24) × (7/24) = 0.0001012
결과값에 따라, 해당 메일은 스팸메일로 판단된다.
언더플로우
메일에 존재하는 단어가 많을 경우 가능성이 0으로 수렴한다.
- 0~1 사이의 확률값을 계속 곱하다보면 결과값이 0으로 수렴하기 때문이다.
- 너무 0에 가까워지면 컴퓨터 연산의 특성상 정확도가 떨어진다. → 언더플로우
Log를 활용하여 개선 가능하다.
- 우리는 결국 확률을 대소비교 하고 싶은 것이다.
- Log는 단조증가함수이기 때문에, A < B 라면 log(A) < log(B) 와 동일하다.
- Log를 사용하게 되면 곱셈 이였던 수식은 로그간 덧셈으로 바뀐다.
- Log(ABC) = Log(A) + Log(B) + Log(C)
로그를 사용하여 다시 계산해보면?
메일 내용 : 롤 접속 ㄱㄱ
스팸: log(P(S=T)) + log(P(롤|S=T)) + log(P(접속|S=T)) + log(P(ㄱㄱ|S=T))
- (-0.92) + (-2.35) + (-1.95) + (-3.04) = -8.26
일반: log(P(S=F)) + log(P(롤|S=F)) + log(P(접속|S=F)) + log(P(ㄱㄱ|S=F))
- (-0.51) + (-1.57) + (-1.57) + (-1.23) = -4.88
결과값에 따라, 헤당 메일은 일반 메일로 판단된다.