Colab으로 하루에 하나씩 딥러닝

텍스트 마이닝_ 1. BOW 기반의 텍스트 마이닝_4)로지스틱 회귀분석 본문

딥러닝_개념

텍스트 마이닝_ 1. BOW 기반의 텍스트 마이닝_4)로지스틱 회귀분석

Elleik 2022. 12. 26. 22:33
728x90

로지스틱 회귀분석

  • 분석하고자 하는 대상들이 두 집단 혹은 그 이상의 집단으로 나누어진 경우, 개별 관측들이 어느 집단에 분류될 수 있는 예측하는 모형
  • 분석 절차
    1. 각 집단에 속하는 확률의 추정치를 예측, 추정치는 이진 분류의 경우 집단에 속하는 확률로 구함
    2. 분류 기준 값을 설정한 후 특정 범수로 분류
  • 일반적인 회귀분석과 차이가 있음
구분 일반적인 회귀분석 로지스틱 회귀분석
종속변수 연속형 변수 이산형 변수
모형 탐색 방법 최소제곱법 최대우도법
모형 검정 F-테스트 x² 테스트


로지스틱 회귀분석을 이용한 문서 분류

2022.12.22 - [딥러닝_프로젝트] - 20 뉴스그룹 데이터 준비 및 특성 추출

20 뉴스그룹 데이터 준비 및 특성 추출

데이터셋 확인 및 분리 (사이킷런 20 뉴스그룹) 해당 데이터는 언론에서 나오는 기사가 아닌 게시판에 올라온 사용자들의 포스트 categories 매개 변수를 이용해 20개의 topic 중에서 원하는 토픽을

elleik.tistory.com

2022.12.23 - [딥러닝_개념] - 텍스트 마이닝_ 1. BOW 기반의 텍스트 마이닝_3) 나이브 베이즈

텍스트 마이닝_ 1. BOW 기반의 텍스트 마이닝_3)나이브 베이즈

나이브 베이즈(cosine similarity) 사전 확률에 기반을 두고 사후 확률을 추론하는 확률적 예측을 하는데, 이때 모든 사건이 독립사건이라는 순진한(naive) 가정을 하고 있음 P(A ¦ B) = (P(A ∩ B)) / (P(B))

elleik.tistory.com

이전 게시물의 영화 리뷰를 기반으로 실습 진행하기 때문에 이전글 확인 후 아래의 실습을 보시는 걸 추천드립니다.
### 이전 코드 불러오기(해당 코드가 있어야 분류가 진행됨)

from sklearn.datasets import fetch_20newsgroups

# 20개 토픽 중 선택하고자 하는 토픽을 리스트로 생성
categories = ['alt.atheism', 'talk.religion.misc','comp.graphics','sci.space']

# 학습 데이터셋을 가져옴
newsgroups_train = fetch_20newsgroups(subset='train',
                                      # 매일 내용에서 hint가 되는 부분을 삭제(순수하게 내용만으로 분류)
                                      remove=("headers","footers","quotes"),
                                      categories=categories)

# 평가 데이터셋을 가져옴
newsgroups_test = fetch_20newsgroups(subset='test',
                                     remove=("headers","footers","quotes"),
                                     categories = categories)

X_train = newsgroups_train.data # 학습 데이터셋 문서
y_train = newsgroups_train.target # 학습 데이터셋 라벨

X_test = newsgroups_test.data # 평가 데이터셋 문서
y_test = newsgroups_test.target # 평가 데이터셋 라벨 

from sklearn.feature_extraction.text import CountVectorizer

cv = CountVectorizer(max_features=2000, min_df=5, max_df=0.5)

X_train_cv = cv.fit_transform(X_train)  # train set 변환

X_test_cv = cv.transform(X_test)  # test set 변환
### 라이브러리 호출 및 분류기 학습

# sklearn이 제공하는 logistic regression을 사용
from sklearn.linear_model import LogisticRegression

# count vector에 대해 regression을 해서 NB와 비교
LR_clf = LogisticRegression() # 분류기 선언

# train data를 이용해 분류기를 학습
LR_clf.fit(X_train_tfidf, y_train)

# train data에 대한 예측 정확도 
print('Train set score: {:.3f}'.format(LR_clf.score(X_train_tfidf, y_train)))

# test data에 대한 예측 정확도
print('Test set score: {:.3f}'.format(LR_clf.score(X_test_tfidf, y_test)))
나이브 베이즈보다 성능이 떨어지는 결과를 보임

성능이 떨어진 이유

  • 나이브 베이즈의 가정이 텍스트 분류의 환경과 잘맞았기 때문
  • 로지스틱 회귀분석에서 학습 데이터와 평가 데이터에 대한 성능의 차이가 크기 때문
  • 로지스틱 회귀분석에서 과적합이 이루어졌기 때문 → 릿지 회귀, 라쏘 회귀로 해결 예정

릿지 회귀를 이용한 과적합 방지

  • 릿지 회귀(ridge regression) 
    • 최적화를 위한 목적함수에 정규화 항목을 넣어서 특성에 대한 계수가 지나치게 커지는 것을 억제함
    • 계수가 지나치게 커지지 않게 계수에 제약음 줌
  • 매개변수 alpha
    • 정규화의 정도를 조절
    • alpha가 커질수록 정규화의 비중이 커져서 계수의 변화를 더 많이 억제
    • alpha의 적정치를 찾는게 중요, 너무 커지면 학습 자체가 안되기 때문
### 라이브러리 호출 및 릿지 분류기 선언과 학습

from sklearn.linear_model import RidgeClassifier

ridge_clf = RidgeClassifier() # 릿지 분류기 선언
ridge_clf.fit(X_train_tfidf, y_train) # 학습

print('Train set score: {:.3f}'.format(ridge_clf.score(X_train_tfidf, y_train)))
print('Test set score: {:.3f}'.format(ridge_clf.score(X_test_tfidf, y_test)))
테스트 셋에 대한 성능이 미세하게 나아짐
### 하이퍼 파라미터를 통해 alpha 값 찾기

import numpy as np
from sklearn.model_selection import train_test_split

X_train_ridge, X_val_ridge, y_train_ridge, y_val_ridge = train_test_split(
    X_train_tfidf, y_train, test_size=0.2, random_state=42)

max_score = 0
max_aplha = 0
for alpha in np.arange(0.1, 10, 0.1):  # alpha를 0.1부터 10까지 0.1씩 증가
  ridge_clf = RidgeClassifier(alpha=alpha)  # 릿지 분류기 선언
  ridge_clf.fit(X_train_ridge, y_train_ridge) # 학습
  # 검정 데이터셋에 대해 정확도를 측정
  score = ridge_clf.score(X_val_ridge, y_val_ridge)
  if score > max_score: # 정확도가 이전의 정확도 최댓값보다 크면 최댓값을 바꿈
    max_score = score
    max_alpha = alpha

print('Max alpha {:3f} at max validaation score {:.3f}'.format(max_alpha, max_score))
최적의 alpha 값은 1.6, 해당 값으로 테스트 진행
### alpha의 최적값을 통해 학습 진행

ridge_clf = RidgeClassifier(alpha=1.6)  # 릿지 분류기 선언 
ridge_clf.fit(X_train_tfidf, y_train) # 학습

print("Train set score: {:.3f}".format(ridge_clf.score(X_train_tfidf, y_train)))
print("Test set score: {:.3f}".format(ridge_clf.score(X_test_tfidf, y_test)))
기존의 로지스틱 회귀분석보다 좋은 성능이지만 나이브 베이즈에는 미치지 못함
### 릿지 회귀를 통한 최종 결과 확인

top10_features(ridge_clf, tfidf,newsgroups_train.target_names)
나이브 베이즈의 결과보다 자세한 결과를 보여줌

라쏘 회귀를 이용한 특성 선택

  • 라쏘 회귀(lasso regression) 
    • 특성의 계수에 대해 정규화를 한다는 점에서 유사하지만 정규화 항에 차이가 있음(릿지는 L2 정규화를 쓰는 반면, 라쏘는 L1 정규화를 사용함)
    • 정규화할 때, 특성의 계수가 0에 가까워지면 이를 완전히 0으로 바꿈
    • 특성의 수를 줄이는 결과를 가져오기 때문에 과적합을 줄이지만 정확도가 항상 향상된다고 보기 어려움
  • 매개변수 C
    • 정규화의 정도를 조절
    • alpha의 역수
    • C의 값이 커지면 정규화가 약해짐
### 라이브러리 호출 및 라쏘 특성 선택과 학습

# Lasso는 동일한 LogisiticRegression을 사용하면서 매개변수로 지정
lasso_clf = LogisticRegression(penalty='l1', solver='liblinear', C=1)

lasso_clf.fit(X_train_tfidf, y_train) # train data로 학습

print('Train set score: {:.3f}'.format(lasso_clf.score(X_train_tfidf, y_train)))
print('Test set score: {:.3f}'.format(lasso_clf.score(X_test_tfidf, y_test)))

# 계수 (coefficient) 중에서 0이 아닌 것들의 개수를 출력
print(
    'Used features count: {}'.format(np.sum(lasso_clf.coef_ != 0)),
    'out of',
    X_train_tfidf.shape[1]
)
정확도는 떨여졌으며 사용된 특성은 확연하게 줄어듦
### 라쏘 특성 선택 후 결과 확인

top10_features(lasso_clf, tfidf, newsgroups_train.target_names)
릿지 회귀분석보다 성능이 향상됨

참고: 박상언, 『파이썬 텍스트 마이닝 완벽 가이드』, 위키북스(2022)
참고: 서지영, 『딥러닝 텐서플로 교과서』, 길벗(2022)