본문 바로가기
풀스택 개발 학습 과정/머신러닝, 딥러닝

[텍스트 마이닝] 텍스트 분석 -2 [실습] 20 뉴스 그룹 분류

by 육츠 2024. 8. 1.
Contents 접기

텍스트 데이터 확인

from sklearn.datasets import fetch_20newsgroups
import numpy as np

news_data = fetch_20newsgroups(subset='all', random_state= 100) # subset='all' 훈련데이터와 평가데이터 모두
print(np.unique(news_data.target))
# 20개의 카테고리에 해당하는
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19]
print(type(news_data))
print(np.array(news_data.data).shape)
<class 'sklearn.utils._bunch.Bunch'>
(18846,)

 

import pandas as pd
print('target 클래스')
print(dict(zip(np.unique(news_data.target_names), np.bincount(news_data.target)))) # bincount 카운트값의 개수
target 클래스
{'alt.atheism': 799, 'comp.graphics': 973, 'comp.os.ms-windows.misc': 985, 'comp.sys.ibm.pc.hardware': 982, 'comp.sys.mac.hardware': 963, 'comp.windows.x': 988, 'misc.forsale': 975, 'rec.autos': 990, 'rec.motorcycles': 996, 'rec.sport.baseball': 994, 'rec.sport.hockey': 999, 'sci.crypt': 991, 'sci.electronics': 984, 'sci.med': 990, 'sci.space': 987, 'soc.religion.christian': 997, 'talk.politics.guns': 910, 'talk.politics.mideast': 940, 'talk.politics.misc': 775, 'talk.religion.misc': 628}

 

print(news_data.data[0])
From: ggr@koonda.acci.com.au (Greg Rose)
Subject: Authentication and one-time-pads (was: Re: Advanced one time pad)
Summary: presents one-time-pad based MAC
Organization: Australian Computing and Communications Institute
Lines: 93

(중략)

 

뉴스 그룹 데이터에서 'headers', 'footers', 'quotes'를 제외한 내용을 모두 가져오기

news_data = fetch_20newsgroups(subset= 'all', remove =('headers','footers','quotes'), random_state=100)
print(news_data.data[0])  # 본문만 나옴
Firstly, an aside:

I agree that the weakness exists, but I have a lot of trouble
believing that it represents a difficulty in real life. Given:

1. the purpose of the one-time pad is to give unbreakable security,
and the expense of key distribution etc., imply that the clients
really do want that level of security

 

학습데이터/평가데이터 분리

test_news = fetch_20newsgroups(subset='test', remove =('headers','footers','quotes'), random_state=100)
# 본문의 내용만 가져오지만, 학습데이터 내용만
x_test = test_news.data
y_test = test_news.target

print(f'학습데이터 크기 : {len(x_train)}, 평가데이터 크기 : { len(x_test)}')
학습데이터 크기 : 11314, 평가데이터 크기 : 7532

 

피처 벡터화 반환과 머신러닝 모델 학습, 예측, 평가

 

CounterVectorizer 이용

from sklearn.feature_extraction.text import CountVectorizer
from nltk.corpus import stopwords

cnt_vect = CountVectorizer(stop_words= stopwords.words('english'))
cnt_vect.fit(x_train) # vocabulary 를 만드는 과정

# 평가데이터에 대해서도 피처 벡터화를 해야함
# 평가데이터에도 학습데이터의 vocabulary 를 이용해야하기 때문

x_train_cnt_vect = cnt_vect.transform(x_train) 

# 학습데이터로 학습된 것으로 피처 벡터화 
x_test_cnt_vect = cnt_vect.transform(x_test)

print(f'학습데이터 텍스트 cntvect_shape: {x_train_cnt_vect.shape}')
학습데이터 텍스트 cntvect_shape: (11314, 101487)

 

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score # 정확도

lr = LogisticRegression(solver='liblinear')
lr.fit(x_train_cnt_vect, y_train) # y_train: 정답은 0~ 19  까지의 숫자로 되어있음

y_hat = lr.predict(x_test_cnt_vect)
print(f'정확도: {accuracy_score(y_test,y_hat):.3f}')

# 분류해 내는데 63 % 정도의 정확도를 가짐
정확도: 0.635

 

TfidfVectorizer 이용 -1

from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.corpus import stopwords

tfidf_vect = TfidfVectorizer(stop_words= stopwords.words('english'))
tfidf_vect.fit(x_train) # vocabulary 를 만드는 과정

# 평가데이터에 대해서도 피처 벡터화를 해야함
# 평가데이터에도 학습데이터의 vocabulary 를 이용해야하기 때문

x_train_tfidf_vect = tfidf_vect.transform(x_train) 

# 학습데이터로 학습된 것으로 피처 벡터화 
x_test_tfidf_vect = tfidf_vect.transform(x_test)

print(f'학습데이터 텍스트 tfidf_vect_shape: {x_train_tfidf_vect.shape}') # shape 이 달라지진 않음
학습데이터 텍스트 tfidf_vect_shape: (11314, 101487)

 

lr = LogisticRegression(solver='liblinear')
lr.fit(x_train_tfidf_vect, y_train) # y_train: 정답은 0~ 19  까지의 숫자로 되어있음

y_hat = lr.predict(x_test_tfidf_vect)
print(f'정확도: {accuracy_score(y_test,y_hat):.3f}')

# 69% 정도의 정확도
정확도: 0.688

 

fidfVectorizer 이용 - 2

n-gram(1,2) 적용 :: 사전의 목록을 더 확장 (예시: a ab b bc c)

tfidf_vect = TfidfVectorizer(stop_words= stopwords.words('english'), ngram_range=(1,2), max_df= 300)
# max_df: 전체 문서에 걸쳐서 너무 높은 빈도수를 가지는 단어 피처를 제외
# 너무 높은 빈도수를 가지는 단어는 불용어와 같이 단어로서 의미가 없는 반복적인 단어일 확률이 높다
# max_df: 전체 문서에 걸쳐서 300개 이하로 나오는 단어 한에서 피처로 추출
# min_df (최소 빈도수)

tfidf_vect.fit(x_train) # vocabulary 를 만드는 과정

# 평가데이터에 대해서도 피처 벡터화를 해야함
# 평가데이터에도 학습데이터의 vocabulary 를 이용해야하기 때문

x_train_tfidf_vect = tfidf_vect.transform(x_train) 

# 학습데이터로 학습된 것으로 피처 벡터화 
x_test_tfidf_vect = tfidf_vect.transform(x_test)

print(f'학습데이터 텍스트 tfidf_vect_shape: {x_train_tfidf_vect.shape}') # shape 이 달라지진 않음
학습데이터 텍스트 tfidf_vect_shape: (11314, 990299)

벡터화한 학습데이터의 열의 크기가 커짐.

 

lr = LogisticRegression(solver='liblinear')
lr.fit(x_train_tfidf_vect, y_train) # y_train: 정답은 0~ 19  까지의 숫자로 되어있음

y_hat = lr.predict(x_test_tfidf_vect)
print(f'정확도: {accuracy_score(y_test,y_hat):.3f}')
정확도: 0.692