본문 바로가기
Computer/ML·DL·NLP

[이수안컴퓨터연구소] 문서 분류 Document Classification

by injeolmialmond 2021. 8. 7.

https://www.youtube.com/watch?v=xegxbgsnYko&list=PL7ZVZgsnLwEEoHQAElEPg7l7T6nt25I3N&index=4 

https://colab.research.google.com/drive/1NlSZKwocO_9Z6Tbw7X4v9YsISHAZfJlK?usp=sharing 

 

_4 문서 분류(Document Classification).ipynb

Colaboratory notebook

colab.research.google.com

데이터 준비

  • 문서 분류에 필요한 데이터는 scikit-learn이 제공하는 20개의 주제를 가지는 뉴스그룹 데이터를 사용
  • 텍스트는 CounterVectorizer를 거쳐 DTM 행렬로 변환
  • DTM 은 문서에 등장하는 단어들을 빈도 수 별로 표현한 행렬
from gensim import models
from numpy.core.defchararray import mod
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split

news = fetch_20newsgroups()
x = news.data
y = news.target

cv = CountVectorizer()
x = cv.fit_transform(x)

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
print(x_train.shape, y_train.shape, x_test.shape, y_test.shape)
# (7919, 130107) (7919,) (3395, 130107) (3395,)

print(x_train[0])
#   (0, 56979)  1
#   (0, 50527)  3
#   (0, 111322) 1
#   (0, 114731) 1
#   (0, 90379)  1
#   (0, 76032)  1
#   (0, 114455) 4
#   (0, 68766)  1
#   (0, 115475) 3
#   (0, 32311)  1
#   (0, 66608)  2
#   (0, 27436)  1
#   (0, 86001)  1
#   (0, 128402) 2
#   (0, 114428) 1
#   (0, 35983)  1
#   (0, 56283)  1
#   (0, 124147) 1
#   (0, 124332) 1
#   (0, 33527)  1
#   (0, 61546)  1
#   (0, 83706)  1
#   (0, 25399)  1
#   (0, 92923)  1
#   (0, 120941) 1
#   :   :
#   (0, 29974)  1
#   (0, 94251)  1
#   (0, 86430)  1
#   (0, 37755)  1
#   (0, 76878)  1
#   (0, 51777)  1
#   (0, 90595)  2
#   (0, 83585)  2
#   (0, 92985)  1
#   (0, 37461)  1
#   (0, 99248)  1
#   (0, 108791) 1
#   (0, 58564)  2
#   (0, 117191) 1
#   (0, 100678) 1
#   (0, 27587)  1
#   (0, 43064)  2
#   (0, 110344) 1
#   (0, 92106)  1
#   (0, 39677)  1
#   (0, 52669)  1
#   (0, 48258)  1
#   (0, 80241)  1
#   (0, 35485)  1
#   (0, 119498) 2

먼저 shape 메소드는 해당 행렬의 형태를 알기 위해 쓴 것임.

x_train의 첫번째 문서에 대한 학습데이터를 출력했더니, 첫번째 줄부터 해석하면: 56979 인덱스를 가진 단어가 1번 출현. 50527번 단어가 2번 출현.

scikit-learn을 이용한 문서 분류

from sklearn.metrics import accuracy_score

Logistic Regression

  • Logistic Regression은 특성상 다중 분류에는 적합하지 않음.
  • '로지스틱 회귀'로 이름에는 '회귀'가 들어가기는 하지만, 가능한 클래스가 2개인, 이진 분류를 위한 모델임.
  • 로지스틱 회귀 모델은 선형 회귀 모델 (두 변인 사이 경향성이 선으로 나타난다)에 시그모이드 함수를 적용
  • 로지스틱 회귀의 학습 목표는 목적 함수를 최소화하는 파라미터를 찾는 것.
from sklearn.linear_model import LogisticRegression
LR = LogisticRegression()
LR.fit(x_train, y_train) # 모델에 학습시키기
pred = LR.predict(x_test) # 예측
acc = accuracy_score(pred, y_test) # 비교
print(acc) # 0.8674521354933726

 

Support Vector Machine

- 회귀, 분류, 이상치 탐지 등에 사용되는 지도학습 방법.

- 클래스 사이의 경계에 위치한 데이터 포인트를 서포트 벡터(support vector) 라고 함.

- 각 서포트 벡터가 클래스 사이의 결정 경계를 구분하는 데 얼마나 중요한지를 학습

- 각 서포트 벡터 사이의 마진이 가장 큰 방향으로 학습 (클래스 사이를 구분하는 선이 있다면, 그 선에 있어서 생기는 서포트 벡터들이 있을 것임. 많은 선들 중에서, 서포트 벡터 사이의 거리가 클 수록, 그 선이 클래스 사이를 명확하게 나누어 준다는 것을 이해할 수 있음!)

서포트 벡터 머신 (naver.com)

 

서포트 벡터 머신

서포트 벡터 머신(support vector machine, SVM)은 주어진 샘플 그룹에 대해 그룹 분류(classification) 규칙을 찾아내는 기법 중 하나이다. 패턴 인식(pattern recognition) 분야에서 제안된 알고리즘으로 1995년 러

terms.naver.com

- 서포트 벡터 사이의 거리서포트 벡터의 중요도를 기반으로 예측을 수행

from sklearn import svm

SVM = svm.SVC(kernel="linear")
SVM.fit(x_train, y_train)
pred = SVM.predict(x_test)
acc = accuracy_score(pred, y_test)
print(acc) # 0.8147275405007364

 

Naive Bayes 분류기

- 베이즈 정리를 적용한 확률적 분류 알고리즘

- 모든 특성들이 독립임을 가정 (=naive 가정)

- 입력 특성에 따라 3개의 분류기 존재:

1. 가우시안 나이브 베이즈 분류기

2. 베르누이 나이브 베이즈 분류기

3. 다항 나이브 베이즈 분류기 (V)

 

DTM을 이용한 Naive Bayes

from sklearn.naive_bayes import MultinomialNB

NB = MultinomialNB()
NB.fit(x_train, y_train)
pred = NB.predict(x_test)
acc = accuracy_score(pred, y_test)
print(acc) # 0.8103092783505155

tf-idf를 이용한 정확도 향상

텍스트 데이터를 숫자로 바꾼 뒤에 학습을 시키는 것임. 그런데 여기서 tf-idf를 활용한다. 해당 문서에서의 단어의 중요도를 고려한 학습 데이터를 만드는 것임.

사이킷런을 활용한 머신러닝(9) - 나이브 베.. : 네이버블로그 (naver.com)

 

사이킷런을 활용한 머신러닝(9) - 나이브 베이즈 분류(Naive bayes classification)

안녕하세요, 동네코더입니다. 이번에는 사이킷런을 활용한 머신러닝 9번째 포스팅으로, 집필중인 책의 원고...

blog.naver.com

from sklearn.feature_extraction.text import TfidfTransformer

tfidf = TfidfTransformer()
x_train_tf = tfidf.fit_transform(x_train)
x_test_tf = tfidf.fit_transform(x_test)

NB.fit(x_train_tf, y_train)
pred = NB.predict(x_test_tf)
acc = accuracy_score(pred, y_test)
print(acc) # 0.8197349042709867

방금 전보다 정확도가 높아진 것을 볼 수 있음 

 

Decision Tree

- 분류와 회귀에 사용되는 지도 학습 방법

- 데이터 특성으로부터 추론된 결정 규칙을 통해 값을 예측

- if-then-else 결정 규칙을 통해 데이터 학습

-트리의 깊이가 깊을수록 복잡한 모델

from sklearn.tree import DecisionTreeClassifier

DT = DecisionTreeClassifier()
DT.fit(x_train, y_train)
pred = DT.predict(x_test)
acc = accuracy_score(pred, y_test)
print(acc) # 0.6365243004418262

인덱스만 가지고 규칙을 찾기는 어렵기 때문에 정확도가 낮을 것임

 

 

 

XGBoost

- 트리 기반의 앙상블 기법

- 분류에 있어서 다른 알고리즘보다 좋은 예측 성능을 보여줌

- XGBoost는 GBM 기반이지만, GBM의 단점인 느린 수행 시간과 과적합 규제 부재등의 문제를 해결

- 병렬 CPU 환경에서 빠르게 학습 가능

pip install xgboost

from xgboost import XGBClassifier

xgb = XGBClassifier(n_estimators = 30, learning_rate = 0.05, max_depth = 3)
xgb.fit(x_train, y_train)
pred = xgb.predict(x_test)
acc = accuracy_score(pred, y_test)
print(acc) # 0.7157584683357879

교차 검증

  • 일반 검증은 학습 데이터가 테스트 데이터로 사용되지 않음
  • 교차 검증은 데이터를 n개의 집합으로 나누어 정확도를 계산해 학습 데이터로 사용된 데이터도 테스트 데이터로 사용
  • 교차 검증을 사용하면 일반 검증보다 모델의 일반화가 잘 되어 있는지 평가 가능
  • 앞서 구성한 나이브 베이즈 모델을 교차 검증
from sklearn.model_selection import cross_val_score
scores = cross_val_score(NB, x, y, cv=5)
print(scores, scores.mean()) # [0.83870968 0.83826779 0.82368537 0.83031374 0.83642794] 0.833480903927519

83% 정도의 정확도를 보여준다!

  • 교차 검증을 통해 일반 검증보다 좀 더 일반화된 모델 생성 가능
  • 교차 검증은 일반 검증에 비해 n번 검증을 해 비용이 더 많이 소요

 

정밀도와 재현률

  • 정밀도(precision)는 양성 클래스(정답)으로 예측한 샘플이 양성 클래스일 확률을 의미
  • 모델이 얼마나 양성 클래스를 잘 예측하는지를 나타냄
  • 재현률(recall)은 양성 클래스인 샘플에서 모델이 양성 클래스로 예측한 샘플 비율을 의미하며, 모델이 얼마나 실제 상황을 재현하는지를 나타냄
  • 정밀도와 재현율의 가중조화평균인 F1-score라는 지표는 정확도에 비해 더 효과적인 모델 분석 지표로 알려져 있음
  • 직접 계산할 수도 있으나, scikit-learn은 이를 편리하게 계산해주는 함수를 제공

 

  • 다중 클래스 분류 문제에서 정밀도와 재현률을 계산할 때는 클래스간의 지표를 어떻게 합칠지 지정 필요
  • None - 클래스간 지표를 합치지 말고 그대로 출력
  • micro - 정밀도와 재현률이 같음, 이로 인해 f1-score도 정밀도, 재현률과 동일
  • macro - 클래스간 지표를 단순 평균한 값
  • weighted - 클래스간 지표를 가중 평균한 값
from sklearn.metrics import precision_score, recall_score, f1_score

precision = precision_score(pred, y_test, average='micro')
recall = recall_score(pred, y_test, average='micro')
f1 = f1_score(pred, y_test, average='micro')

print(precision, recall, f1)
# 0.7157584683357879 0.7157584683357879 0.715758468335788 : micro는 세 개 동일하게 나옴

precision = precision_score(pred, y_test, average='macro')
recall = recall_score(pred, y_test, average='macro')
f1 = f1_score(pred, y_test, average='macro')

print(precision, recall, f1)
# 0.7106642627191686 0.7421743409644816 0.72025466998744 : macro는 세 개 각각 나옴

 

그리드 검색을 이용한 파라미터 최적화

  • 그리드 검색을 사용하면 분류기에 사용하는 파라미터 최적화 가능
  • 그리드 검색을 통해 앞서 구성한 나이브 베이즈 모델의 'alpha' 파라미터를 최적화시키는 예제

* 질문! alpha는 무엇인가? 나이브 베이즈 분류기에서는 각 단어에 대한 확률의 분모, 분자에 전부 숫자를 더해서 분자가 0이 되는 것을 방지하는 라플라스 스무딩을 사용하는데,  alpha=1.0은 라플라스 스무딩이 적용되었음을 의미한다고 합니다. 분모분자에 더하는 숫자가 알파임을 추론할 수 있을 것 같습니다.

5) 나이브 베이즈 분류기(Naive Bayes Classifier) - 딥 러닝을 이용한 자연어 처리 입문 (wikidocs.net)

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net

  • estimator: 사용 모델 객체
  • param_grid: 사용 객체:지정 파라미터 리스트로 구성된 딕셔너리
  • scoring: 최적화하고자 하는 성능 지표
  • cv: 교차 검증 분할 개수
from sklearn.model_selection import GridSearchCV
GS = GridSearchCV(estimator=NB, param_grid={'alpha': [0.001, 0.01, 0.1, 1.]}, scoring='accuracy', cv=10)
GS.fit(x,y)

print(GS.best_score_) # 0.8897820965842167
print(GS.best_params_) # {'alpha': 0.001}

성능이 88%까지 상승했다!

from sklearn.model_selection import GridSearchCV
GS = GridSearchCV(estimator=NB, param_grid={'alpha': [0.001, 0.002, 0.003, 0.004, 0.005]}, scoring='accuracy', cv=10)
GS.fit(x,y)

print(GS.best_score_) # 0.8897820965842167
print(GS.best_params_) # {'alpha': 0.001}

파라미터 값을 다르게 넣어봤는데도 최적은 0.001이다. 더 작게 해보자.

from sklearn.model_selection import GridSearchCV
GS = GridSearchCV(estimator=NB, param_grid={'alpha': [0.001, 0.0008, 0.0006]}, scoring='accuracy', cv=10)
GS.fit(x,y)

print(GS.best_score_) # 0.8897820965842167
print(GS.best_params_) # {'alpha': 0.001}

그래도 최적은 0.001이다.

댓글