반응형
데이터 전처리
import pandas as pd
# json 읽어오기
news_data = pd.read_json('../data/News_Category_Dataset_v2.json', lines=True)
news_data = news_data.loc[:, ["category", "headline"]]
# 카테고리 정수 인코딩
category_list = pd.factorize(news_data['category'])[1]
news_data['category'] = pd.factorize(news_data['category'])[0]
# 정규표현식 사용
news_data['headline'] = news_data['headline'].str.replace("[^\w]", " ")
- 뉴스 카테고리 데이터를 활용한다. (https://www.kaggle.com/rmisra/news-category-dataset)
- lines=True로 주어 각 줄별로 데이터를 받아올 수 있도록 한다.
- 우리는 headline을 기반으로 category를 분류하는 기능을 만들 것이기 때문에 그 둘만 받아온다.
- 판다스의 factorize는 시리즈데이터를 받아 그를 기반으로 [[인덱싱데이터],[각 인덱싱의 의미]]를 반환한다. 신경망학습에 문자열데이터를 사용하기란 매우 어렵다. 따라서 인덱싱한 데이터를 사용하도록 한다. 각 인덱싱의 의미도 추후 확인을 위해 필요하므로 category_list에 따로 저장해놓는다.
- headline에 구별이 어려운 문자(이모티콘 등)이 존재할 수 있으므로 문자열이 아닌 데이터(^\w)는 정규표현식을 활용해 공백으로 만든다.
학습, 테스트 데이터 생성 및 결과데이터(category) 원핫벡터화
from sklearn.model_selection import train_test_split
from tensorflow.keras.utils import to_categorical
# split하면서 shuffle 적용
news_train, news_test, y_train, y_test = train_test_split(news_data['headline'], news_data['category'], test_size=0.2, shuffle=True, random_state=23)
# 원핫벡터로 만들어줍시다! (num_classes로 카테고리 수 명시 가능)
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
- train_test_split를 활용해 학습 데이터와 테스트 데이터로 분류한다.
- category를 인덱싱하여 숫자화했지만, 아직 데이터로 활용하기엔 부적절하다. 신경망이 각 인덱싱에 의미를 부여하여 제대로된 학습을 수행하기란 어렵기 때문이다.
- 따라서 이를 원핫벡터화한다. to_categorical() 메소드가 이를 간단하게 수행해준다. (인덱싱된 데이터를 모두 원핫벡터화)
입력데이터(headline) 토큰화
# 토큰화 진행
stopwords = ['a', 'an']
X_train = []
for stc in news_train:
token = []
words = stc.split()
for word in words:
if word not in stopwords:
token.append(word)
X_train.append(token)
X_test = []
for stc in news_test:
token = []
words = stc.split()
for word in words:
if word not in stopwords:
token.append(word)
X_test.append(token)
- 입력데이터도 문자열 그대로인 상태여선 처리할 수 없다.
- 결과데이터와 마찬가지로 인덱싱화를 해주어야하는데, 입력데이터인 headline은 문장이기 때문에 그대로 인덱싱화해선 안된다.
- 따라서 각 데이터를 split하여 단어로 나누고, stopwords를 제거한다. (임의로 a와 an만 넣었지만 더 많은 stopword를 제대로 설정해주는 것이 좋다.)
입력데이터 인덱싱
from tensorflow.keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer(25000)
tokenizer.fit_on_texts(X_train)
X_train = tokenizer.texts_to_sequences(X_train)
X_test = tokenizer.texts_to_sequences(X_test)
- 빈도수별로 25000개의 단어를 인덱싱화한다. (데이터를 살펴보고 일정 빈도수 이상의 단어만 인덱싱되도록 적절한 숫자를 설정해준 것이다.)
- X_train만 fit하여 이를 기준으로 학습 데이터와 테스트 데이터를 인덱싱화한다.
입력 데이터 패딩
max_len = 15
X_train = pad_sequences(X_train, maxlen=max_len)
X_test = pad_sequences(X_test, maxlen=max_len)
- headline은 모두 단어갯수가 달라 학습에 어려움이 있다.
- 따라서 그를 맞춰준다. max_len보다 더 긴 문장은 잘려지고, 더 짧은 문장은 데이터를 0으로 채운다.
모델 생성 및 학습
model = Sequential()
model.add(Embedding(25000, 128))
model.add(LSTM(128))
model.add(Dense(41, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
model.fit(X_train, y_train, validation_data=(X_test, y_test), batch_size=64, epochs=1)
- 모델을 만들고 학습 데이터를 기반으로 학습시킨다.
- Embedding은 각 단어를 word embedding하고, LSTM이 이를 분석, Dense가 결과를 출력한다.
- 우리는 여러 데이터를 분류할 것이기 때문에 활성화함수는 'softmax'를 사용하고, 출력의 갯수도 41개로 나눈다. 이 레이어의 출력값은 카테고리별 확률이 될 것이다.
- 빠른 확인을 위해 epochs를 1로 주었지만, 실사용에선 epochs를 적절히 큰 수를 주는 것이 좋다.
결과확인
sentence = input()
token_stc = sentence.split()
encode_stc = tokenizer.texts_to_sequences([token_stc])
pad_stc = pad_sequences(encode_stc, maxlen=15)
score = model.predict(pad_stc)
print(category_list[score.argmax()], score[0, score.argmax()])
- 사용자로부터 데이터를 받고 그를 모델에 활용할 수 있도록 전처리(split, 인덱싱, 패딩)해준다.
- 그를 기반으로 결과(각 카테고리에 대한 확률값)을 얻고, 그 중 가장 높은 확률의 인덱스가 어떤 카테고리에 포함되는지 처음에 선언한 category_list를 기반으로 알아낸다.
- 확률값과 함께 결과를 출력한다.
반응형
'🛠 기타 > Data & AI' 카테고리의 다른 글
Seq2Seq 기초 (챗봇 데이터 활용 예제) (2) | 2020.08.14 |
---|---|
함수형 케라스와 모델 합성(앙상블) (0) | 2020.08.14 |
텐서플로우 허브 (0) | 2020.08.14 |
이미지 보강 (ImageDataGenerator) (0) | 2020.08.14 |
합성곱 신경망(CNN) - 기본구조 구현 (0) | 2020.08.14 |