[Python] 머신러닝 완벽가이드 - 08. 텍스트 분석[한글 텍스트 처리]

Updated:

파이썬 머신러닝 완벽가이드 교재를 토대로 공부한 내용입니다.

실습과정에서 필요에 따라 내용의 누락 및 추가, 수정사항이 있습니다.


기본 세팅

import numpy as np
import pandas as pd

import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns

import warnings
%matplotlib inline
%config InlineBackend.figure_format = 'retina'

mpl.rc('font', family='NanumGothic') # 폰트 설정
mpl.rc('axes', unicode_minus=False) # 유니코드에서 음수 부호 설정

# 차트 스타일 설정
sns.set(font="NanumGothic", rc={"axes.unicode_minus":False}, style='darkgrid')
plt.rc("figure", figsize=(10,8))

warnings.filterwarnings("ignore")

7. 한글 텍스트 처리

7.1 네이버 영화 평점 데이터

데이터는 https://github.com/e9t/nsmc에서 받을 수 있다.

이 데이터를 이용해서 감성 분석을 진행해보자.

train_df = pd.read_csv('nsmc-master/ratings_train.txt', sep='\t')
train_df.head(3)
id document label
0 9976970 아 더빙.. 진짜 짜증나네요 목소리 0
1 3819312 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 1
2 10265843 너무재밓었다그래서보는것을추천한다 0
train_df['label'].value_counts( )
0    75173
1    74827
Name: label, dtype: int64
  • 0은 부정 감성, 1은 긍정 감성을 의미한다.

  • target의 분포는 거의 균등하게 나타났다.

train_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150000 entries, 0 to 149999
Data columns (total 3 columns):
 #   Column    Non-Null Count   Dtype 
---  ------    --------------   ----- 
 0   id        150000 non-null  int64 
 1   document  149995 non-null  object
 2   label     150000 non-null  int64 
dtypes: int64(2), object(1)
memory usage: 3.4+ MB
  • 데이터는 150,000 x 3으로 이루어져 있다.

  • document 컬럼은 일부 결측이 존재하여 이를 공백으로 변환하겠다.

7.1.1 텍스트 전처리

import re

# document 결측 공백으로 변환
train_df = train_df.fillna(" ")

# 정규 표현식으로 숫자를 공백으로 변경 (정규 표현식에서 \d는 숫자를 의미)
train_df["document"] = train_df["document"].apply(lambda x: re.sub(r"\d+", " ", x))

# test set 동일 작업
test_df = pd.read_csv('nsmc-master/ratings_test.txt', sep='\t')
test_df = test_df.fillna(" ")
test_df["document"] = test_df["document"].apply(lambda x: re.sub(r"\d+", " ", x))

# id 컬럼 제거
train_df.drop("id", axis=1, inplace=True)
test_df.drop("id", axis=1, inplace=True)
  • document 결측값과 숫자를 공백으로 변환하였고 id 컬럼은 제거하였다.

7.1.2 감성 분석

tokenizer 함수

from konlpy.tag import Twitter

twitter = Twitter()

def tw_tokenizer(text):
    # 텍스트를 형태소 단어로 토큰화 후 리스트로 반환
    tokens_ko = twitter.morphs(text)
    
    return tokens_ko
  • 피처 벡터화에 사용할 tokenizer 함수를 생성하였다.

  • twitter.morphs()는 문장을 형태소 단어 형태로 토큰화 한다.

  • Twitter는 현재 Okt(Open Korea Text)로 변경되었고, 여기선 그냥 Twitter로 썼다.

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV

# TF-IDF 피처 벡터화, 로지스틱
pipeline = Pipeline([
    ("tfidf_vect", TfidfVectorizer(tokenizer=tw_tokenizer, ngram_range=(1,2), min_df=3, max_df=0.9)), 
    ("lr_clf", LogisticRegression())
])

# GridSearchCV
params = {
    "lr_clf__C": [1, 3.5, 10]
}

grid_cv = GridSearchCV(pipeline, param_grid=params, scoring="accuracy", verbose=1)
grid_cv.fit(train_df['document'], train_df['label'])

print(grid_cv.best_params_, round(grid_cv.best_score_,4))
Fitting 5 folds for each of 3 candidates, totalling 15 fits


[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done  15 out of  15 | elapsed: 85.8min finished


{'lr_clf__C': 3.5} 0.8616
  • 파이프라인을 이용해 TF-IDF 피처 벡터화, 로지스틱 회귀 객체를 생성하였다.

  • 수행 시간을 고려해서 하이퍼 파라미터는 3개 중 최적을 찾았다.

  • 최적 하이퍼 파라미터 C는 3.5일 때 최고 0.8616의 정확도로 나타났다.

from sklearn.metrics import accuracy_score

# 예측/평가 (best_estimator로 안해도 이미 최적으로 학습되어 있음)
best_estimator = grid_cv.best_estimator_
pred = best_estimator.predict(test_df["document"])
acc = accuracy_score(test_df["label"], pred)

print(f"Logistic Regression 정확도: {acc:.4f}")
Logistic Regression 정확도: 0.8618
  • test에 대한 정확도는 0.8618로 나타났다.

  • 피처 벡터화시 반드시 train으로 학습한 벡터화 객체로 test를 벡터화 하여야한다.

  • 여기선 파이프라인을 사용했기에 예측시 원래 객체로 입력하였다.

Leave a comment