Mecab과 Keras를 이용한 뉴스 말뭉치 구분 모델 구현.1 (NLP)

AI의 지도학습에는 크게 두 가지가 있다. 바로 분류(Classification)와 회귀(Regression)이다.

간략하게 설명하자면 들어온 input 자료들을 일정 기준으로 나누는 건 분류 들어온 자료들을 통해 다음 데이터를 예측하는 방식을 회귀라고 생각하면 편하다. 그리고 이번 포스트에서는 뉴스 말뭉치(말 자료들)을 이용하여 뉴스가 어느 분류에 속하는지에 분류하는 모델을 구현해 보겠다. 

모델의 구현에 들어가기 전 미리 알아두어야 할 것들을 먼저 소개하겠다.

1. LSTM, RNN에 대하여 

 https://soobarkbar.tistory.com/74

본 포스팅에서 사용할 것은 LSTM 모델이다. 기존의 신경망의 단점을 보완한 것이라고 생각하면 편하다. 위의 블로그를 방문해서 공부하는 것을 추천한다.


2. Mecab 우리말 형태소 분석기 (은전한닢)

http://eunjeon.blogspot.com/

은전한잎이라는 우리말 형태소 분석기다. konlpy 기반으로 제작되었다고 하며 형태소 단위로 분류하는 것이 가능하게 만들어 준다. 다양한 종류의 분석기 중 은전한잎을 사용하겠다. 설치방법, 파일등은 위 사이트를 이용하기 바란다.


3. 케라스 API

https://keras.io/api/

본 포스팅에서 사용될 API들이다. 미리 학습하면 포스팅을 이해하는데 큰 도움이 된다.


4. 자연어 처리 

https://www.sas.com/ko_kr/insights/analytics/what-is-natural-language-processing-nlp.html

자연어 처리 (NLP)에 대한 내용이다. 

본 모델의 이야기이기 때문에 기본적으로 알아야 하는 내용들이다.


5. 감성분류 예제 (추가학습)

 https://wikidocs.net/44249

네이버 영화 리뷰를 긍정:1 부정:0 으로 라벨링한 데이터를 이용해 학습을 진행하고 구현하는 방법을 알려주는 블로그 포스트이다. 이번 포스트와 많은 차이가 있지만 미리 한번 학습하면 본 포스트를 이해하는데 많은 도움이 된다. 


1. 데이터 준비

일단 학습과 모델링에 사용할 말뭉치 데이터를 얻어야 한다. 이전에는 많이 얻을 수 있었지만 요즘은 국립국어원에서 사용 출처를 작성하고 승인을 받으면 여러 말뭉치를 받을 수 있다.  

https://corpus.korean.go.kr/main.do#none

위에 접속하여 필자는 2020 신문 말뭉치를 신청해 다운받았고 newsdata 밑에 압축을 풀었다.

제일 먼저 한 일은 데이터의 상태를 확인하는 것이 였다. 데이터는 TXT형태일 것이라는 예상과는 다르게 다중 리스트 형태의 Josn 파일 형태로 구성되어있었다. 

 


따라서 이를 딥러닝에 이용하기 위한 몇 가지 정제과정이 필요했다.


2. 데이터 정제

기본적으로 사용할 라이브러리를 import 했다.

import json
from eunjeon import Mecab
from tqdm import tqdm
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.layers import Embedding, Dense, LSTM
from tensorflow.keras.models import Sequential
tokenizer = Mecab()

또한 토큰화 모듈을 은전한닢의 Mecab을 이용했다.

tqdm은 실행중인 작업을 가시적으로 보여주기 위한 모듈이다.

데이터를 정제하기 전 일단 데이터를 저장한 곳에서 IDE로 불러와야 했다.  코드는 다음과 같았다.

json_file = "./newsdata/NIRW2000000001.json"
with open(json_file, encoding="utf8") as j:
content = json.loads(j.read())

utf8 방식을 이용해 불러 파일을 읽어 들었다.

2.1 개인 실패 사례

가장 먼저 데이터를 어떤 식으로 분류시켜 학습 시킬지 고민했다. 이때 metadata 안쪽의 key값으로 topic이 있는 것을 확인했고 이를 이용한 분류를 진행하기 위해 크게 3가지 정치 경제 생활로 나누어 이용해 보기로 했다. 따라서 json 파일의 특정 값에 접근을 하였고 각각에서 조건문을 걸어 gove, econ, life 리스트에 형태소를 분석한 것들을 넣기로 했다. 따라서 그 코드는 다음과 같았다. 

for i in tqdm(range(100)):
topic = content['document'][i]['metadata']['topic']
if(topic == '생활'):
for j in range(len(content['document'][i]['paragraph'])):
token = tokenizer.morphs(content['document'][i]['paragraph'][j]['form'])
clean = [word for word in token if not word in stopwords]
life.append(clean)

for i in tqdm(range(100)):
topic = content['document'][i]['metadata']['topic']
if(topic == '경제'):
top
for j in range(len(content['document'][i]['paragraph'])):
token = tokenizer.morphs(content['document'][i]['paragraph'][j]['form'])
clean = [word for word in token if not word in stopwords]
econ.append(clean)

for i in tqdm(range(100)):
topic = content['document'][i]['metadata']['topic']
if(topic == '정치'):
for j in range(len(content['document'][i]['paragraph'])):
token = tokenizer.morphs(content['document'][i]['paragraph'][j]['form'])
#clean = [word for word in token if not word in stopwords]
gove.append(token)

 위의 코드를 통해 각각 형태소로 분리된 리스트 값을 얻었다. 다음은 각각의 형태소들을 숫자로 1대1 매칭시켜 학습에 사용될 수 있도록 했다. 

tokenizerr.fit_on_texts(gove)
topic_train = tokenizerr.texts_to_sequences(gove)
textdata_train = pad_sequences(textdata_train, maxlen=170)

다음 코드는 정치 파트의 학습 데이터를 정수 시퀸스로 매칭하는 코드와 매칭된 데이터의 길이 조절과 패딩을 진행하는 코드이다. 이때 최대 길이는 len()함수를 이용해 길이를 확인해 진행했다. 

[간략 설명

나/는/ 너/와/ 밥/을 /먹/었다

1,2, 3,4, 5,6 7,8

이렇게 변환 했을때 

너/가 밥/을/ 먹/다 라는 문장은 

3,9, 5,6, 7,10 로 바꿀수 있으며 컴퓨터는 이를 통해 NLP학습이 가능해진다. ]

  

결과는 다음과 같이 나왔다. 

각각 분리된 형태소가 정수와 매칭되어 사용가능한 형태로 변환 된 것을 확인할 수 있었다. 

2.1.1 문제점

이제 학습에 들어가려고 하던 중 3가지 큰 문제점을 발견했다. 

1. 라벨링 데이터와의 연결 

각각 데이터를 학습할 때 앞서서 분류를 한 것이 문제였다. 이렇게 진행되면 모델링에서 학습을 진행할 때 모두 같은 라벨링을 가질 수 밖에 없었다.

2. 라벨링 데이터와 문단 데이터 간의 갯수 차이

문제를 정리한 그림이다. 각각 한 문장으로 나뉘어져있기 때문에 라벨링 데이터값보다 훨씬 많은 데이터 값이 생겼고 이는 우측처럼 변경이 필요했고 반복문의 변경이 필요했다.

3.  라벨링 데이터 문제 
라벨링 데이터가 일부를 제외하고는 [0] 으로 되는 문제가 발견되어 수정이 필요했다.

2.1.2 문제 해결

1. 라벨링 데이터를 나누지 않고 전체적으로 하나로 묶어 입력 받았다. 따라서 newtext라는 하나의 리스트에 종류를 가리지 않고 본문 데이터를 불러들였고, topics라는 리스트에는 라벨링을 분류해 학습을 시작했다.
 
2. 데이터를 읽어들이는 for문을 수정했다. 좌측처럼 데이터 형태 수정을 위해 for문을 수정했다. 

1,2번 문제를 해결한 코드는 다음과 같다.  

for i in tqdm(range(100)):
for j in range(len(content['document'][i]['paragraph'])):
token = tokenizer.morphs(content['document'][i]['paragraph'][j]['form'])
texttoken.append(token)

newtext.append([element for array in texttoken for element in array])


for i in tqdm(range(100)):
token = tokenizer.morphs(content['document'][i]['metadata']['topic'])
topics.append(token)

3. 라벨링 데이터 문제는 정수로 인베딩할때 두 값을 연동시킨 결과였다. 즉 본문을 정수로 변환한 상태에서 연동하여 주제도 변환하려고 해 본문에 없던 단어가 주제였을 경우 [0]으로 표기되는 것이였다. 따라서 따로 주제와 본문을 인베딩하여 문제를 해결했다. 

tokenizerr.fit_on_texts(topics)
topic_train = tokenizerr.texts_to_sequences(topics)

tokenizerr.fit_on_texts(newtext)
textdata_train = tokenizerr.texts_to_sequences(newtext)

textdata_train = pad_sequences(textdata_train, maxlen=170)
topic_train = pad_sequences(topic_train, maxlen=1)

이제 학습을 위한 데이터가 모두 준비되었다. 이제 모델 구현은 다음 포스트에 이어서 진행하겠다.

댓글

이 블로그의 인기 게시물

다양한 계층 구현을 통한 오차역전파법 구현하기(2)

퍼셉트론(Perceptron)

[논문리뷰] 3. CNN에 대하여