텍스트 분류 실습 - 20 뉴스그룹 분류
- 사이킷런이 내부에 갖고 있는 예제 데이터인 20 뉴스그룹 데이터셋을 이용해 텍스트 분류를 적용해보자 → fetch_20newsgroups()
- 텍스트를 피처 벡터화로 변환하면 희소 행렬 형태가 된다. 이런 희소 행렬에 분류를 효과적으로 잘 처리할 수 있는 알고리즘은 로지스틱 회귀, 선형 서포트 벡터 머신, 나이브 베이즈 등이다.
텍스트 정규화
In [1]:
from sklearn.datasets import fetch_20newsgroups
news_data = fetch_20newsgroups(subset='all', random_state=156)
In [2]:
print(news_data.keys())
dict_keys(['data', 'filenames', 'target_names', 'target', 'DESCR'])
In [3]:
import pandas as pd
print('target 클래스의 값과 분포도 \n', pd.Series(news_data.target).value_counts().sort_index())
print('target 클래스의 이름들 \n', news_data.target_names)
target 클래스의 값과 분포도
0 799
1 973
2 985
3 982
4 963
5 988
6 975
7 990
8 996
9 994
10 999
11 991
12 984
13 990
14 987
15 997
16 910
17 940
18 775
19 628
dtype: int64
target 클래스의 이름들
['alt.atheism', 'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware', 'comp.sys.mac.hardware', 'comp.windows.x', 'misc.forsale', 'rec.autos', 'rec.motorcycles', 'rec.sport.baseball', 'rec.sport.hockey', 'sci.crypt', 'sci.electronics', 'sci.med', 'sci.space', 'soc.religion.christian', 'talk.politics.guns', 'talk.politics.mideast', 'talk.politics.misc', 'talk.religion.misc']
개별 데이터가 텍스트로 어떻게 구성돼있는지 하나만 확인해보자
In [4]:
print(news_data.data[0])
From: egreen@east.sun.com (Ed Green - Pixel Cruncher)
Subject: Re: Observation re: helmets
Organization: Sun Microsystems, RTP, NC
Lines: 21
Distribution: world
Reply-To: egreen@east.sun.com
NNTP-Posting-Host: laser.east.sun.com
In article 211353@mavenry.altcit.eskimo.com, maven@mavenry.altcit.eskimo.com (Norman Hamer) writes:
>
> The question for the day is re: passenger helmets, if you don't know for
>certain who's gonna ride with you (like say you meet them at a .... church
>meeting, yeah, that's the ticket)... What are some guidelines? Should I just
>pick up another shoei in my size to have a backup helmet (XL), or should I
>maybe get an inexpensive one of a smaller size to accomodate my likely
>passenger?
If your primary concern is protecting the passenger in the event of a
crash, have him or her fitted for a helmet that is their size. If your
primary concern is complying with stupid helmet laws, carry a real big
spare (you can put a big or small head in a big helmet, but not in a
small one).
---
Ed Green, former Ninjaite |I was drinking last night with a biker,
Ed.Green@East.Sun.COM |and I showed him a picture of you. I said,
DoD #0111 (919)460-8302 |"Go on, get to know her, you'll like her!"
(The Grateful Dead) --> |It seemed like the least I could do...
기사 내용, 뉴스그룹 제목, 작성자, 소속, 이메일 등의 다양한 정보를 갖고 있다.
이 중 내용을 제외하고 제목 등의 정보는 제거하자 → 제목, 소속, 이메일 등의 header와 footer 정보는 뉴스그룹 분류의 target 클래스값과 유사한 데이터를 갖고 있는 경우가 많기 때문에
- remove 파라미터를 이용하면 뉴스그룹 기사의 header, footer를 제거할 수 있다.
- subset 파라미터로 학습 데이터셋, 테스트 데이터셋을 분리하여 내려받을 수 있다.
In [17]:
from sklearn.datasets import fetch_20newsgroups
# subset='train'으로 학습용(Train) 데이터만 추출, remove=('headers', 'footers', 'quotes')로 내용만 추출
train_news= fetch_20newsgroups(subset='train', remove=('headers', 'footers', 'quotes'), random_state=156)
X_train = train_news.data
y_train = train_news.target
print(type(X_train))
# subset='test'으로 테스트(Test) 데이터만 추출, remove=('headers', 'footers', 'quotes')로 내용만 추출
test_news= fetch_20newsgroups(subset='test',remove=('headers', 'footers','quotes'),random_state=156)
X_test = test_news.data
y_test = test_news.target
print('학습 데이터 크기 {0} , 테스트 데이터 크기 {1}'.format(len(train_news.data) , len(test_news.data)))
<class 'list'>
학습 데이터 크기 11314 , 테스트 데이터 크기 7532
피처 벡터화 변환과 머신러닝 모델 학습/예측/평가
- CountVectorizer를 이용해 학습 데이터의 텍스트를 피처 벡터화하기
- 테스트 데이터에는 반드시 학습 데이터를 이용해 fit()이 수행된 CountVectorizer 객체를 이용해 cnt_vect.transform()해야 한다. → fit_transform() 적용 X
In [18]:
from sklearn.feature_extraction.text import CountVectorizer
# Count Vectorization으로 feature extraction 변환 수행.
cnt_vect = CountVectorizer()
cnt_vect.fit(X_train , y_train)
X_train_cnt_vect = cnt_vect.transform(X_train)
# 학습 데이터로 fit( )된 CountVectorizer를 이용하여 테스트 데이터를 feature extraction 변환 수행.
X_test_cnt_vect = cnt_vect.transform(X_test)
print('학습 데이터 Text의 CountVectorizer Shape:',X_train_cnt_vect.shape)
학습 데이터 Text의 CountVectorizer Shape: (11314, 101631)
11,314개의 문서에서 101,631개의 피처가 만들어졌다.
이제 로지스틱 회귀를 적용해보자
In [19]:
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# LogisticRegression을 이용하여 학습/예측/평가 수행.
lr_clf = LogisticRegression()
lr_clf.fit(X_train_cnt_vect , y_train)
pred = lr_clf.predict(X_test_cnt_vect)
print('CountVectorized Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test,pred)))
CountVectorized Logistic Regression 의 예측 정확도는 0.606
- 이번에는 TF-IDF 기반 벡터화로 변경하여 예측을 수행해보자
In [20]:
from sklearn.feature_extraction.text import TfidfVectorizer
# TF-IDF Vectorization 적용하여 학습 데이터셋과 테스트 데이터 셋 변환.
tfidf_vect = TfidfVectorizer()
tfidf_vect.fit(X_train)
X_train_tfidf_vect = tfidf_vect.transform(X_train)
X_test_tfidf_vect = tfidf_vect.transform(X_test)
# LogisticRegression을 이용하여 학습/예측/평가 수행.
lr_clf = LogisticRegression()
lr_clf.fit(X_train_tfidf_vect , y_train)
pred = lr_clf.predict(X_test_tfidf_vect)
print('TF-IDF Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test ,pred)))
TF-IDF Logistic Regression 의 예측 정확도는 0.674
단순 카운트 기반보다 TF-IDF 기반 벡터화가 더 높은 예측 정확도를 제공한다.
일반적으로 문서 내에 텍스트가 많고 문서가 많으면 TF-IDF 벡터화가 더 좋은 성능을 가진다.
- 텍스트 분석에서 머신러닝 모델의 성능을 향상시키는 중요한 2가지 방법은 최적의 ML 알고리즘을 선택하는 것과 최장의 피처 전처리를 수행하는 것이다.
- 앞의 TF-IDF 벡터화에서는 기본 파라미터만 적용했지만 스톱 워드를 기존 'None'에서 'englisg'로 변경하고, ngram_range는 기존 (1,1)에서 (1,2)로, max_df=300으로 변경한 뒤 다시 예측을 해보자
In [21]:
tfidf_vect = TfidfVectorizer(stop_words='english',
ngram_range=(1,2), max_df=300)
tfidf_vect.fit(X_train)
X_train_tfidf_vect = tfidf_vect.transform(X_train)
X_test_tfidf_vect = tfidf_vect.transform(X_test)
lr_clf = LogisticRegression(solver='liblinear')
lr_clf.fit(X_train_tfidf_vect , y_train)
pred = lr_clf.predict(X_test_tfidf_vect)
print('TF-IDF Vectorized Logistic Regression 의 예측 정확도는 {0:.3f}'.format(
accuracy_score(y_test,pred)))
TF-IDF Vectorized Logistic Regression 의 예측 정확도는 0.690
- 이번엔 GridSearchCV를 이용해 로지스틱 회귀의 하이퍼 파라미터 최적화를 수행해보자
- 로지스틱 회귀의 C 파라미터만 변경하면서 최적의 C값을 찾고 이 값으로 학습된 모델에서 테스트 데이터로 예측해보자
In [22]:
from sklearn.model_selection import GridSearchCV
params = {'C':[0.01, 0.1, 1, 5, 10]}
grid_cv_lr = GridSearchCV(lr_clf, param_grid=params, cv=3, scoring='accuracy', verbose=1)
grid_cv_lr.fit(X_train_tfidf_vect, y_train)
print('Logistic Regression best C parameter:', grid_cv_lr.best_params_)
pred = grid_cv_lr.predict(X_test_tfidf_vect)
print('TF-IDF Vectorized Logistic Regression 의 예측 정확도는 {0:.3f}'.format(
accuracy_score(y_test, pred)))
Fitting 3 folds for each of 5 candidates, totalling 15 fits
Logistic Regression best C parameter: {'C': 10}
TF-IDF Vectorized Logistic Regression 의 예측 정확도는 0.704
C가 10일 때 가장 좋은 예측 성능을 나타냈고 이를 테스트 데이터에 적용한 결과 0.704로 성능이 약간 향상됐다.
사이킷런 파이프라인(Pipeline) 사용 및 GridSearchCV와의 결합
- 사이킷런의 pipeline 클래스를 이용하면 피처 벡터화와 ML 알고리즘 학습 및 예측을 한 번에 진행할 수 있다.
- 일반적으로 머신러닝에서 Pipeline이란 데이터의 가공, 변환같은 전처리와 알고리즘 적용을 한꺼번에 스트림 기반으로 처리한다는 의미이다.
- Pipeline을 이용하면 데이터의 전처리와 머신러닝 학습 과정을 통일된 API 기반에서 처리할 수 있어 더 직관적인 ML 모델 코드를 생성할 수 있다. 또, 대용량 데이터의 피처 벡터화 결과를 별도 데이터로 저장하지 않고 스트림 기반에서 바로 알고리즘의 데이터로 입력할 수 있기 때문에 수행 시간을 절약할 수 있다.
TfidfVectorizer와 LogisticRegression 두 객체를 파이프라인으로 연결하는 pipeline 객체 생성
→ 별도의 fit(), transform()와 fit(), predict()가 필요없음
In [23]:
from sklearn.pipeline import Pipeline
pipeline = Pipeline([('tfidf_vect', TfidfVectorizer(stop_words='english', ngram_range=(1,2), max_df=300)),
('lr_clf', LogisticRegression(solver='liblinear', C=10))])
In [24]:
pipeline.fit(X_train, y_train)
pred = pipeline.predict(X_test)
print('Pipeline을 통한 Logistic Regression의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test, pred)))
Pipeline을 통한 Logistic Regression의 예측 정확도는 0.704
- GridSearchCV의 생성 파라미터로 pipeline을 입력하여 pipeline 기반에서도 하이퍼 파라미터 튜닝을 그리드 서치 방식으로 진행할 수 있다.
- 이렇게 하면 피처 벡터화를 위한 파라미터와 ML 알고리즘의 하이퍼 파라미터를 한번에 GridSearchCV를 이용해 최적화할 수 있다.
다음은 GridSearchCV에 Pipeline을 입력하면서 TfidfVectorizer의 파라미터와 LogisticRegression의 하이퍼 파라미터를 함께 최적화하는 예제이다.
In [ ]:
from sklearn.pipeline import Pipeline
pipeline = Pipeline([
('tfidf_vect', TfidfVectorizer(stop_words='english')),
('lr_clf', LogisticRegression())
])
# Pipeline에 기술된 각각의 객체 변수에 언더바(_)2개를 연달아 붙여 GridSearchCV에 사용될
# 파라미터/하이퍼 파라미터 이름과 값을 설정. .
params = { 'tfidf_vect__ngram_range': [(1,1), (1,2), (1,3)],
'tfidf_vect__max_df': [100, 300, 700],
'lr_clf__C': [1,5,10]
}
# GridSearchCV의 생성자에 Estimator가 아닌 Pipeline 객체 입력
grid_cv_pipe = GridSearchCV(pipeline, param_grid=params, cv=3 , scoring='accuracy',verbose=1)
grid_cv_pipe.fit(X_train , y_train)
print(grid_cv_pipe.best_params_ , grid_cv_pipe.best_score_)
pred = grid_cv_pipe.predict(X_test)
print('Pipeline을 통한 Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test ,pred)))
'Data Science > 파이썬 머신러닝 완벽 가이드' 카테고리의 다른 글
[sklearn] (50) Bag of Words - BOW (0) | 2023.08.01 |
---|---|
[sklearn] (49) 텍스트 사전 분비 작업(텍스트 전처리) - 텍스트 정규화 (0) | 2023.07.31 |
[sklearn] (48) 자연어처리(NLP, Natural Language Processing)와 텍스트 분석(Text Analytics) (0) | 2023.07.28 |
[sklearn] (47) 군집화 실습 - 고객 세그먼테이션(Customer Segmentation) (0) | 2023.07.28 |
[sklearn] (46) DBSCAN(밀도 기반 클러스터링), make_circles (0) | 2023.07.26 |