1 텍스트 분류(Text classification) 1

분류기는 사전 분류될 집단이 정해진 경우 어떤 집단에 속할 것인지 판별하여 지정하는 역할 수행한다. 텍스트 분류의 종류는 다음과 같은 것이 있다.

  • 주제(Topic): 텍스트가 무엇에 관한 것인가 분류.
  • 감정(Sentiment): 다양한 감정 상태 중 어떤 감정 상태에 가까운가 분류.
  • 언어(Language): 어느 나라, 어느 민족 텍스트인지 분류.
  • 쟝르(Genre): 텍스트가 어떤 쟝르(시, 소설, 등)에 속하는지 분류.
  • 저자(Author): 텍스트를 보고 누구의 글인지 판별.

2 베이즈 정리를 활용한 텍스트 분류기

전자우편/채팅이 스팸일 확률을 찾고자 하는데 베이즈 정리로 출발해서, 단어가 하나인 경우를 경유하여 단어를 다수 포함한 전자우편/채팅으로 확장해 보자.

2.1 베이즈 정리

특정 단어가 나오면 그 전자우편/채팅이 스팸일 확률을 베이즈 정리를 활용하면 다음과 같다.

\[ P(s|w) = \frac {P(s,w)}{P(w)} = \frac {P(w|s)P(s)}{P(w)} \]

여기서, \(P(w):\) 전자우편이나 채팅에서 특정단어가 출현할 확률(예를 들어, Sell, 팔아요 등), \(P(s)\)는 전자우편이나 채팅이 스팸일 확률

\[P(w) = P(w, s) + P(w, \sim s)\]

2.2 단어 한개를 가정한 베이즈 정리

상기 관계를 이용하여 단어가 주어졌을 때 스팸일 확률을 다음과 같이 정리할 수 있다.

\[ P(s|w) = \frac {P(w|s)P(s)}{P(w)} = \frac {P(w|s)P(s)}{P(w, s) + P(w, \sim s)} = \frac {P(w|s)P(s)}{P(w|s)P(s) + P(w| \sim s)P(\sim s)}\]

즉, 스팸중에서 특정 단어가 출현할 조건부 확률 \(P(w|s)\) 과 스팸이 아닌 것 중에 특정 단어가 출현할 확률 \(P(w|\sim s)\)만 알게 된다면 단어가 주어졌을 때 스팸일 확률을 계산할 수 있게 된다.

2.3 다수 단어를 가정한 베이즈 정리

우선 다수 단어를 \(W\)라고 가정한다. 즉, \(W = w_1 , w_2 , \cdots , w_n\) 라고 다수 단어를 표현한다. 그리고, 각 단어가 서로 독립적이라는 가정을 넣으면 수식은 다음과 같이 단순화된다.

\[\begin{aligned} P(s|W) &= \frac {P(W|s) P(s)}{P(W)} \\ &= P(w_1 , w_2 , \cdots , w_n |s) P(s) \\ &= P(w_1 |s)P(w_2 |s) \cdots P(w_n |s) \end{aligned} \]

3 SMS 단문문자 스팸 분류 2

나이브 베이즈를 활용해서 SMS 단문문자 스팸 분류기 모형을 다음과 같이 개발할 수 있다. 가장 먼저, 데이터는 국내에도 SMS 단문문자 스팸데이터가 있다면 공유되면 좋을텐데 아쉽게도 해외 Tiago A. Almeida, José Maria Gómez Hidalgo 분들이 생성한 SMS Spam Collection v.1 데이터를 활용한다.

3.2 tidytext 데이터 전처리

기본적으로 스팸이냐 아니냐는 sms_raw$type 변수에 저장되어 있다. 즉, 스팸이냐 아니냐는 SMS 단문 메시지에 담긴 문자내용이 핵심인데, 나이브 베이즈 모형에 넣도록 단어를 추출해서 이를 문선단어행렬(DocumentTermMatrix)로 변환시키는데 tidytext 팩키지를 사용해서 데이터를 정제하고, 기계학습 모형 적합을 위한 훈련/시험 데이터로 분할시킨다.

이 전체 과정을 tidytext 작업흐름에 맞춰 코드를 작성한다.

  1. mutate() 함수로 스팸이냐 아니냐를 요인형으로 변환시킨다.
  2. 단문 SMS 텍스트를 소문자로 str_to_lower() 함수로 변환시킨다.
  3. unnest_tokens() 함수로 토큰화한다.
  4. 불용어(stop_words) 사전을 사용해서 불용어를 anti_join() 함수로 제거한다.
  5. 영단어를 위해서 SnowballC 팩키지 wordStem() 함수로 어간을 추출한다.

3.3 tidytext DTM 생성 3

caret 예측모형 생성을 위해서 basetable을 만들어야 한다. 이를 위해서 DTM(Document Term Matrix)를 생성한다. 이를 위해서 cast_dtm() 함수를 사용한다.

<<DocumentTermMatrix (documents: 4739, terms: 7433)>>
Non-/sparse entries: 34909/35190078
Sparsity           : 100%
Maximal term length: 42
Weighting          : term frequency - inverse document frequency (normalized) (tf-idf)

예측모형을 만들 때 DTM 크기가 중요하다. 이를 위해서 removeSparseTerms() 함수를 사용해서 파일 크기를 줄이는 방법을 살펴보자.

<<DocumentTermMatrix (documents: 4739, terms: 94)>>
Non-/sparse entries: 9384/436082
Sparsity           : 98%
Maximal term length: 8
Weighting          : term frequency - inverse document frequency (normalized) (tf-idf)

4 스팸분류 예측모형 4 5

DocumentTermMatrix 객체를 7:3으로 훈련/시험 데이터로 나누고 randomForest 팩키지를 사용해서 “스팸/햄” 을 분류하는 스팸 분류예측모형을 텍스트 Feature만을 대상으로 개발한다.


Call:
 randomForest(x = as.data.frame(as.matrix(sms_train)), y = sms_tbl$type[train_ind]) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 9

        OOB estimate of  error rate: 13.9%
Confusion matrix:
     0  1 class.error
0 2852 28 0.009722222
1  433  4 0.990846682