Text Analyis Basic using Scikit-Learn and KoNLPy (python 텍스트 분석 03)

2 minute read

이 분석은 개인적인 local 사정상, Docker 환경에서 실습했음을 알린다.

Docker 환경을 만든 이유는 local OS : Window 10 Home edition 이기 때문이다.

  • docker toolbox 로 진행했는데, 꽤나 힘들었다. KoNLPy 순서로 진행한다.

이 외에도, KoNLPy (형태소 분석기 = 한국어 전용 어간분석기) 를 사용할 수 있고, 실제로도 이를 많이 사용한다.
그러나, 현재 실습 환경이 Window 인 관계로, 생략한다. 이는 추후 Collab 에서 활용하도록 한다
“KoNLPy의 Mecab() 클래스는 윈도우에서 지원되지 않습니다.” (http://konlpy.org/ko/latest/install/)

## 라이브러리 로드

import pandas as pd
import numpy as np
import re
import matplotlib.pyplot as plt

%matplotlib inline
# 시각화 결과가 선명하게 표시되도록
%config InlineBackend.figure_format = 'retina'

시각화를 위한 한글폰트 설정

# Window 한글폰트 설정
# plt.rc("font", family="Malgun Gothic")
# Mac 한글폰트 설정
plt.rc("font", family="AppleGothic")
plt.rc('axes', unicode_minus=False)

이미 github 에 txt 파일로 정제된것을 활용했다.

df_train = pd.read_csv('/home/cypision/Alchemy/dataset/naver_movie_sample/ratings_train.txt',delimiter='\t',keep_default_na=False)
df_train.head(2)
id document label
0 9976970 아 더빙.. 진짜 짜증나네요 목소리 0
1 3819312 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 1

lable 이 0 이면 부정적인 리뷰. 1이면 긍정적인 리뷰다
numpy 배열로 바꿔보면

text_train = df_train.document.values
y_train = df_train.label.values
print(text_train.shape,y_train.shape)
(150000,) (150000,)
print(type(text_train),text_train.ndim)
<class 'numpy.ndarray'> 1
## text data 불러와서 가공하기
df_test = pd.read_csv('/home/cypision/Alchemy/dataset/naver_movie_sample/ratings_test.txt',delimiter='\t',keep_default_na=False)
text_test = df_test['document'].values
y_test = df_test.label.values

데이터 탐색하기

len(text_train), np.bincount(y_train)
(150000, array([75173, 74827]))
len(text_test), np.bincount(y_test)
(50000, array([24827, 25173]))

KoNLPy 를 tokenizer 로 활용하기

KoNLPy 는 앞선 post 에서 언급했던, 형태소 분석기이고 기본적으로 5개 정도가 있다.
여기서는 2개 정도만 실습해보기로 한다.

Okt 이른바 Twitter 형태소 분석기 활용

from konlpy.tag import Okt ## Twitter --> Okt 로 버전업하면서 명칭이 바뀌었다.
twitter_tag = Okt()
def twitter_tokenizer(text):
    return twitter_tag.morphs(text)
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import GridSearchCV
twit_param_grid = {'tfidfvectorizer__min_df':[3,5,7],
                  'tfidfvectorizer__ngram_range':[(1,1),(1,2),(1,3)],
                  'logisticregression__C':[0.1,1,10]}
## 여기가 핵심이다.
## 기본 TfidfVectorizer() 는 정규식을 활용하자만, 여기서는 KoNLPy 에 해당하는 어간(형태소) tokenizer 를 사용한다.
t_pipe = make_pipeline(TfidfVectorizer(tokenizer=twitter_tokenizer),LogisticRegression())
t_grid = GridSearchCV(t_pipe,twit_param_grid)
t_grid.fit(text_train[0:1000],y_train[0:1000])
print(t_grid.best_score_)
print(t_grid.best_params_)
0.718
{'logisticregression__C': 1, 'tfidfvectorizer__min_df': 3, 'tfidfvectorizer__ngram_range': (1, 3)}

이제 최적의 조합을 찾았으니, text set를 변환시키고 (KoNLPy tokenzier 를 사용하고) 실제 test 결과를 구해본다

t_grid.best_estimator_
Pipeline(memory=None,
         steps=[('tfidfvectorizer',
                 TfidfVectorizer(analyzer='word', binary=False,
                                 decode_error='strict',
                                 dtype=<class 'numpy.float64'>,
                                 encoding='utf-8', input='content',
                                 lowercase=True, max_df=1.0, max_features=None,
                                 min_df=3, ngram_range=(1, 3), norm='l2',
                                 preprocessor=None, smooth_idf=True,
                                 stop_words=None, strip_accents=None,
                                 sublinear_tf=False,
                                 token...
                                 tokenizer=<function twitter_tokenizer at 0x7f0b5545f268>,
                                 use_idf=True, vocabulary=None)),
                ('logisticregression',
                 LogisticRegression(C=1, class_weight=None, dual=False,
                                    fit_intercept=True, intercept_scaling=1,
                                    l1_ratio=None, max_iter=100,
                                    multi_class='auto', n_jobs=None,
                                    penalty='l2', random_state=None,
                                    solver='lbfgs', tol=0.0001, verbose=0,
                                    warm_start=False))],
         verbose=False)
x_test_konlypy = t_grid.best_estimator_.named_steps['tfidfvectorizer'].transform(text_test)
score = t_grid.best_estimator_.named_steps['logisticregression'].score(x_test_konlypy,y_test)
print(score)
0.70698

딱히 비교할 건 없지만, 꽤나 잘 맞는다

Mecab 형태소 분석기 활용

from konlpy.tag import Mecab
mecab = Mecab()
def mecab_tokenizer(text):
    return mecab.morphs(text)
mecab_param_grid = {'tfidfvectorizer__min_df':[3,5,7],
                  'tfidfvectorizer__ngram_range':[(1,1),(1,2),(1,3)],
                  'logisticregression__C':[0.1,1,10]}
## 여기가 핵심이다.
## 기본 TfidfVectorizer() 는 정규식을 활용하자만, 여기서는 KoNLPy 에 해당하는 어간(형태소) tokenizer 를 사용한다.
m_pipe = make_pipeline(TfidfVectorizer(tokenizer=mecab_tokenizer),LogisticRegression())
m_grid = GridSearchCV(m_pipe,mecab_param_grid)
m_grid.fit(text_train[0:1000],y_train[0:1000])
GridSearchCV(cv=None, error_score=nan,
             estimator=Pipeline(memory=None,
                                steps=[('tfidfvectorizer',
                                        TfidfVectorizer(analyzer='word',
                                                        binary=False,
                                                        decode_error='strict',
                                                        dtype=<class 'numpy.float64'>,
                                                        encoding='utf-8',
                                                        input='content',
                                                        lowercase=True,
                                                        max_df=1.0,
                                                        max_features=None,
                                                        min_df=1,
                                                        ngram_range=(1, 1),
                                                        norm='l2',
                                                        preprocessor=None,
                                                        smooth_idf=True,
                                                        stop_words=N...
                                                           n_jobs=None,
                                                           penalty='l2',
                                                           random_state=None,
                                                           solver='lbfgs',
                                                           tol=0.0001,
                                                           verbose=0,
                                                           warm_start=False))],
                                verbose=False),
             iid='deprecated', n_jobs=None,
             param_grid={'logisticregression__C': [0.1, 1, 10],
                         'tfidfvectorizer__min_df': [3, 5, 7],
                         'tfidfvectorizer__ngram_range': [(1, 1), (1, 2),
                                                          (1, 3)]},
             pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
             scoring=None, verbose=0)
print(m_grid.best_score_)
print(m_grid.best_params_)
0.7529999999999999
{'logisticregression__C': 1, 'tfidfvectorizer__min_df': 3, 'tfidfvectorizer__ngram_range': (1, 2)}
m_grid.best_estimator_
Pipeline(memory=None,
         steps=[('tfidfvectorizer',
                 TfidfVectorizer(analyzer='word', binary=False,
                                 decode_error='strict',
                                 dtype=<class 'numpy.float64'>,
                                 encoding='utf-8', input='content',
                                 lowercase=True, max_df=1.0, max_features=None,
                                 min_df=3, ngram_range=(1, 2), norm='l2',
                                 preprocessor=None, smooth_idf=True,
                                 stop_words=None, strip_accents=None,
                                 sublinear_tf=False,
                                 token...
                                 tokenizer=<function mecab_tokenizer at 0x7f0b2f7a3378>,
                                 use_idf=True, vocabulary=None)),
                ('logisticregression',
                 LogisticRegression(C=1, class_weight=None, dual=False,
                                    fit_intercept=True, intercept_scaling=1,
                                    l1_ratio=None, max_iter=100,
                                    multi_class='auto', n_jobs=None,
                                    penalty='l2', random_state=None,
                                    solver='lbfgs', tol=0.0001, verbose=0,
                                    warm_start=False))],
         verbose=False)
x_test_konlypy = m_grid.best_estimator_.named_steps['tfidfvectorizer'].transform(text_test)
score = m_grid.best_estimator_.named_steps['logisticregression'].score(x_test_konlypy,y_test)
print(score)
0.74632

그렇다…이렇다 할 특별한 부분은 없지만…결과는 훨씬 좋은 듯. ㅋㅋ

Comments