이전 포스팅에서 나이브 베이즈를 사용해서 텍스트를 어떻게 분류할 수 있는지 정말 간단한 예제를 통해 살펴보았다.
이번에는 파이썬 머신러닝 라이브러리 scikit-learn에서 실제로 어떻게 구현하고 동작하는지 코드를 알아볼 차례.
scikit-learn에서 Naive Bayes 분류기를 사용하기 전에 일단 자연어(텍스트)로 이루어진 문서들을 1과 0 밖에 모르는 컴퓨터가 이해할 수 있는 형식으로 변환해야 할 거다. feature extraction, 어휘(특성) 추출 과정이라 볼 수 있다.
일단 CounterVectorizer
라는 객체를 만든 후, fit()
메소드를 호출해서 학습 데이터 세트에 등장하는 어휘를 가르쳐놓아야 한다.
예를 들어 아래와 같이 코드를 작성하면
"첫번째", "문서", "테스트", "두번째" 이렇게 총 4개의 어휘를 학습한 CountVectorizer를 만들게 된다.
못 믿겠다면 vectorizer.vocabulary_
를 출력해보면 된다. 이렇게 뜰 거다.
고유한 어휘가 딕셔너리처럼 각각의 인덱스를 가지고 있다.
어휘 사전을 만들었으니 이제 .transform()
메서드를 호출할 수 있다. .transform()
은 문자열 목록을 가져와 미리 학습해놓은 사전을 기반으로 어휘의 빈도를 세주는 거다.
아래와 같이 공백으로 구분되는 문자열로 가져와서 넣어주면
counts에는 각 어휘가 등장한 빈도수가 저장되는 거다. counts.toarray()를 출력해보면 [[1 0 1 2]]와 같은 array를 볼 수 있다. 위에서 학습된 인덱스에 따라 개수를 세주었다. 그리고 "직접"이라는 단어는 애초에 사전에 등록된 단어가 아니기 때문에 고려하지 않는다.
이렇게 텍스트를 컴퓨터가 이해할 수 있는 숫자로 변환시켜놓은 셈이니 이제 나이브 베이즈를 본격적으로 사용해볼 수 있다.
나이브 베이즈 분류기를 학습시킬 때는 당연히 2개의 파라미터가 필요하다. 위에서 여러 문서들을 .transform() 해놓은 문서-단어 행렬과 그 문서들이 어떤 분류에 속하는지 레이블을 준비해서 넣어주면 된다.
이제 새로운 문서가 등장했을 때 어떤 분류로 속할지 예측을 할 수 있다.
단! 텍스트를 바로 넣는다고 되는 게 아니다. 위에서 모델을 학습시키기 위해 학습 데이터를 문서-단어 행렬로 transform 한 것처럼 새로운 텍스트도 transform해서 넣어줘야 한다.
.predict_proba()
는 각 레이블로 분류될 확률을 돌려준다. 베이즈 정리로 해당 문서가 어떤 분류에 속할 확률을 각각 다 계산할 수 있기 때문이다.
나이브 베이즈 분류기를 구현하는 방법은 일단 여기까지다.
주요 내용을 다시 간단히 요약해보자.
베이즈 정리에서 사용되는 확률을 계산하려면 레이블이 지정된 데이터 세트가 필요하다.
데이터 세트에 포함된 문서에서 등장하는 어휘들이 곧 특성(feature)이다. 그리고 베이즈 정리를 적용하기 위해 이 특성(어휘)들은 모두 독립적인 것으로 가정한다.
베이즈 정리를 사용하면 어떤 문서가 있을 때 그것이 특정 레이블에 속할 확률, P(레이블|문서)를 계산할 수 있으며, 이 중 확률이 가장 높은 레이블로 예측을 하게 된다.
뭐 이렇게 간단해보이긴 하지만 사실 텍스트(문서)를 나이브 베이즈로 제대로 분류하려면 그 전에 꽤 복잡한 과정을 거쳐 데이터를 잘 가공하는 게 정말 중요하다. garbage in, garbage out이라는 거..
뭐 일단 간단하고 일반적인 작업으로는 이런 게 있겠다.
문장 부호, 불용어 등을 제거한다.
모든 단어를 소문자로 통일한다. (한국어는 해당사항 없지만)
ngram 모델을 사용한다. 예를 들어 "이 음식은 너무 맛있다"는 문서가 있다면 여기서 feature는 "이", "음식은", "너무", "맛있다"가 될 것이다. 그러나 만약 bigram 모델을 사용하면 "이 음식은", "음식은 너무", "너무 맛있다"가 된다. 나이브 베이즈에서는 애초에 각 어휘들이 독립적이라고 가정하는데 이렇게 bigram 모델을 사용하면 연달아 등장하는 어휘를 고려하는 셈이니 조금 나아지는 편이다.
형태소 단위로 쪼개서 집어 넣는다. 예를 들면 "공부하다", "공부했다", "공부하는" 등의 다양한 어휘가 등장할 때 이것들 각각을 어휘로 보지 않고 "공부하-"라는 대표형으로 묶어서 보는게 효과적이기 때문이다.
특정 품사들만 선택해서 사용한다. 형태소 분석을 하면 각 어휘가 어떤 품사를 지니는지(태깅) 알 수 있기 때문에 이걸 바탕으로 일반명사, 고유명사, 형용사, 동사, 일반부사 위주로 사용하면 결과가 더 좋을 수도 있다. 물론 케바케다. 게다가 형태소를 나누는 기준이나 체계도 딱 정해져 있는 건 아니라..
출처
https://hleecaster.com/ml-naive-bayes-classifier-example/