관리 메뉴

솜씨좋은장씨

[Kaggle DAY01]Real or Not? NLP with Disaster Tweets! 본문

Kaggle/Real or Not? NLP with Disaster Tweets

[Kaggle DAY01]Real or Not? NLP with Disaster Tweets!

솜씨좋은장씨 2020. 2. 13. 16:21
728x90
반응형

Kaggle Competition 도전 1일차!

 

DACON에서 진행했던 원자력발전소 상태판단 알고리즘 경진대회도 끝났겠다 

 

한국인공지능 아카데미 BERT 실용교육에서 알게 된

Real or Not? NLP with Disaster Tweets! Kaggle Competition을 도전해보기로 했습니다.

 

이번에는 하루 5번 제출이 가능하고 3월 23일까지 기간이 넉넉하게 있기에 

어떠한 모델들을 사용해 볼지 어떤 데이터 전처리를 진행한 뒤에 실시해볼지 고민해서 계획 후에 도전하며

모델의 성능을 높여나가는 과정을 기록해보려합니다.

 

오늘은 처음으로 도전하는 날이고

기존에 알고있던 nltk를 활용한 토큰화, stemming, Keras 모델을 활용하여 시도해보았습니다.

 

진행 환경은 Google Colab의 TPU 환경에서 진행하였습니다.

 

데이터는 구글드라이브에

content
|_mnt
    |_My Drive
           |_Colab Notebooks
                         |_Kaggle
                                |_DisasterTweet
                                             |_train.csv
                                             |_test.csv

다음과 같은 경로에 저장해 두었습니다.

 

 

데이터가 저장되어있는 구글 드라이브 마운트하기

import os, sys 
from google.colab import drive 
drive.mount('/content/mnt') 
nb_path = '/content/notebooks' 
os.symlink('/content/mnt/My Drive/Colab Notebooks', nb_path) 
sys.path.insert(0, nb_path)

코드를 실행하면 나오는 링크를 클릭하여 access_key를 받고 마운트 시켜줍니다.

 

잘 모르겠는 분은 아래의 링크에 잘 정리해 두었으니 확인해보시면 좋을 것 같습니다.

 

Google Colab에서 Google Drive와 연동하기

먼저 새로운 노트북을 하나 만들어주고 셀에 아래의 코드를 입력해줍니다. import os, sys from google.colab import drive drive.mount('/content/mnt') nb_path = '/content/notebooks' os.symlink('/content/mn..

somjang.tistory.com

cd /content/mnt/My Drive/Colab Notebooks/Kaggle/DisasterTweet

그 다음 데이터가 있는 디렉토리로 이동해줍니다.

 

 

데이터 로드하기

import pandas as pd

train_data = pd.read_csv("train.csv")
test_data = pd.read_csv("test.csv")

먼저 pandas의 read_csv를 활용하여 다운로드 받은 데이터를 load합니다.

 

학습데이터

 

테스트 데이터

학습 데이터는 7,613개의 데이터 테스트 데이터는 3,263개의 데이터를 가지고 있고

각각 id, keyword, location, text의 colum을 가지고 있었습니다.

 

학습데이터에만 가짜인지 진짜인지 구분해주는 target column이 있었습니다.

 

데이터 확인 후 정제를 해보았습니다.

 

정규식을 활용한 특수문자 제거

 

데이터에서 정규식을 활용하여 각각의 Tweet에서 특수문자를 제거하고

clear_text라는 새로운 column을 만들어 특수문자를 제거한 Tweet들을 넣어주었습니다.

from tqdm import tqdm
import re

text_list = list(train_data['text'])

clear_text_list = []

for i in tqdm(range(len(text_list))):
  clear_text = re.sub('[-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…》]', '', text_list[i])
  clear_text_list.append(clear_text.lower())

train_data['clear_text'] = clear_text_list
train_data
text_list = list(test_data['text'])

clear_text_list = []

for i in tqdm(range(len(text_list))):
  clear_text = re.sub('[-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…》]', '', text_list[i])
  clear_text_list.append(clear_text.lower())

test_data['clear_text'] = clear_text_list
test_data

 

nltk를 활용해 토큰화 / 불용어처리 / 어간추출하기

 

먼저 nltk에서 stopwords와 punkt패키지를 다운로드 받아줍니다.

import nltk
nltk.download("stopwords")
nltk.download("punkt")

 

토큰화를 하고 그 토큰화한 단어들에서 어간을 추출한 다음

그 중에서 불용어를 제거한 뒤 길이가 2이상인 단어들만 남겨두도록 합니다.

X_train = []

clear_text_list = list(train_data['clear_text'])

for i in tqdm(range(len(clear_text_list))):
  temp = word_tokenize(clear_text_list[i])
  temp = [stemmer.stem(word) for word in temp]
  temp = [word for word in temp if word not in stop_words]
  temp = [word for word in temp if len(word) > 1]
  X_train.append(temp)
X_train[:3]
X_test = []

clear_text_list = list(test_data['clear_text'])

for i in tqdm(range(len(clear_text_list))):
  temp = word_tokenize(clear_text_list[i])
  temp = [stemmer.stem(word) for word in temp]
  temp = [word for word in temp if word not in stop_words]
  temp = [word for word in temp if len(word) > 1]
  X_test.append(temp)
X_test[:3]

 

각각의 단어를 정수로 인코딩해주기

words = []

for i in tqdm(range(len(X_train))):
  for j in range(len(X_train[i])):
    words.append(X_train[i][j])
len(list(set(words)))

먼저 토큰화 / 불용어처리 / 어간추출 을 통해서 나온 단어들의 총 개수가 몇개인지 확인해봅니다.

결과가 18,168개의 단어로 나왔습니다.

from keras.preprocessing.text import Tokenizer
max_words = 18168
tokenizer = Tokenizer(num_words = max_words)
tokenizer.fit_on_texts(X_train)
X_train_vec = tokenizer.texts_to_sequences(X_train)
X_test_vec = tokenizer.texts_to_sequences(X_test)

Keras의 preprocessing.text에 있는 Tokenizer를 활용해 단어를 정수로 바꾸어 주었습니다.

 

각 트윗의 최대 / 평균 길이 확인해보기

import matplotlib.pyplot as plt

print("트윗의 최대 길이 :" , max(len(l) for l in X_train))
print("트윗의 평균 길이 : ", sum(map(len, X_train))/ len(X_train))
plt.hist([len(s) for s in X_train], bins=50)
plt.xlabel('length of Data')
plt.ylabel('number of Data')
plt.show()

matplotlib을 활용해 확인해보면

최대 23 / 평균 10의 길이를 갖는 것을 알 수 있었습니다.

 

target 값 One-Hot Encoding 변환하기

from keras.utils import np_utils
import numpy as np

y_train = []

for i in range(len(train_data['target'])):
  if train_data['target'].iloc[i] == 1:
    y_train.append([0, 1])
  elif train_data['target'].iloc[i] == 0:
    y_train.append([1, 0])

y_train = np.array(y_train)

 

1 -> [0, 1] / 0 -> [1, 0] 으로 변환합니다.

 

X_train의 각각의 토큰화된 트윗 길이를 똑같게 맞춰주기

from keras.preprocessing.sequence import pad_sequences
max_len = 23 # 전체 데이터의 길이를 23로 맞춘다

X_train_vec = pad_sequences(X_train_vec, maxlen=max_len)
X_test_vec = pad_sequences(X_test_vec, maxlen=max_len)

 

Embedding + LSTM + Dropout 레이어를 가진 모델로 학습 / 예측 / 결과 확인해보기

 

첫번째 제출 모델

Embedding(18168, 100) + LSTM(128) + Dropout(0.2) + Dense(2, sigmoid) [adam]

epoch 3 / batch_size 32 / validation_split 0.1

model = Sequential()
model.add(Embedding(max_words, 100))
model.add(LSTM(128))
model.add(Dropout(0.2))
model.add(Dense(2, activation='sigmoid'))

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history = model.fit(X_train_vec, y_train, epochs=3, batch_size=32, validation_split=0.1)

데이터가 적어서 그런지 2epoch 부터 val_loss값이 떨어지지 않고 계속 커졌고 val_acc도 떨어졌습니다.

 

어떤 결과가 나올지 한번 제출해 보았습니다.

predict = model.predict(X_test_vec)
predict_labels = np.argmax(predict, axis=1)
for i in range(len(predict_labels)):
  predict_labels[i] = predict_labels[i]

ids = list(test_data['id'])

submission_dic = {"id":ids, "target":predict_labels}
submission_df = pd.DataFrame(submission_dic)
submission_df.to_csv("kaggle_day01.csv", index=False)

제출에는 다음 코드를 사용하여 제출 파일을 만들었습니다.

0.77402의 성적으로 약 2,200등의 성적을 내었습니다.

 

그 다음부터는 하이퍼 파라미터만 바꾸어 가며 도전해보았습니다.

 

두번째 제출 모델

Embedding(18168, 100) + LSTM(128) + Dropout(0.2) + Dense(2, sigmoid) [adam]

epoch 1 / batch_size 32 / validation_split 0.1

model2 = Sequential()
model2.add(Embedding(max_words, 100))
model2.add(LSTM(128))
model2.add(Dropout(0.2))
model2.add(Dense(2, activation='sigmoid'))

model2.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history2 = model2.fit(X_train_vec, y_train, epochs=1, batch_size=32, validation_split=0.1)

 

 

세번째 제출 모델

Embedding(18168, 100) + LSTM(64) + Dropout(0.2) + Dense(2, sigmoid) [adam]

epoch 1 / batch_size 32 / validation_split 0.1

model2 = Sequential()
model2.add(Embedding(max_words, 100))
model2.add(LSTM(64))
model2.add(Dropout(0.2))
model2.add(Dense(2, activation='sigmoid'))

model2.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history2 = model2.fit(X_train_vec, y_train, epochs=1, batch_size=32, validation_split=0.1)

 

네번째 제출 모델

Embedding(18168, 100) + LSTM(32) + Dropout(0.1) + Dense(2, sigmoid) [adam]

epoch 1 / batch_size 32 / validation_split 0.1

model2 = Sequential()
model2.add(Embedding(max_words, 100))
model2.add(LSTM(32))
model2.add(Dropout(0.1))
model2.add(Dense(2, activation='sigmoid'))

model2.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history2 = model2.fit(X_train_vec, y_train, epochs=1, batch_size=32, validation_split=0.1)

 

다섯번째 제출 모델

Embedding(18168, 100) + LSTM(32) + Dropout(0.1) + Dense(2, sigmoid) [adam]

epoch 1 / batch_size 16 / validation_split 0.1

model2 = Sequential()
model2.add(Embedding(max_words, 100))
model2.add(LSTM(32))
model2.add(Dropout(0.1))
model2.add(Dense(2, activation='sigmoid'))

model2.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history2 = model2.fit(X_train_vec, y_train, epochs=1, batch_size=16, validation_split=0.1)

  모델 epoch batch_size validation_split score
1 Embedding(18168, 100) + LSTM(128) + Dropout(0.2) + Dense(2, sigmoid) [adam] 3 32 0.1 0.77402
2 Embedding(18168, 100) + LSTM(128) + Dropout(0.2) + Dense(2, sigmoid) [adam] 1 32 0.1 0.79141
3 Embedding(18168, 100) + LSTM(64) + Dropout(0.2) + Dense(2, sigmoid) [adam] 1 32 0.1 0.79856
4 Embedding(18168, 100) + LSTM(32) + Dropout(0.1) + Dense(2, sigmoid) [adam] 1 32 0.1 0.79550
5 Embedding(18168, 100) + LSTM(32) + Dropout(0.1) + Dense(2, sigmoid) [adam] 1 16 0.1 0.79243

오늘은 여기까지!

Comments