728x90
반응형

네이버 영화 리뷰 데이터

import pandas as pd 
import numpy as np 
import seaborn as sns 
import matplotlib.pyplot as plt 
import tensorflow as tf

 

train_file = tf.keras.utils.get_file('ratings_train.txt', \ 
origin='https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt',\ 
extract=True) 








Downloading data from https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt 
14630912/14628807 [==============================] - 0s 0us/step

 

train = pd.read_csv(train_file, sep='\t') 
train.head() 
print("train shape:", train.shape) 


# train shape: (150000, 3)

레이블별 갯수 출력하기


train['label'].value_counts() 
sns.countplot(x='label', data=train)

결측값


train.isnull().sum() 
train[train['document'].isnull()] 
# 결측값 제거 
train = train.dropna() 
print("train shape:",train.shape) 




# train shape: (149995, 3)


레이블 별 글자수의 분포를 히스토그램으로 출력

# 레이블 별 글자수의 분포를 히스토그램으로 출력 
# 긍정의 글자수 
postive_len = train[train['label']==1]['document'].str.len() 
# 부정의 글자수 
negative_len = train[train['label']==0]['document'].str.len() 
postive_len.iloc[:10] 




1 33 4 61 8 22 9 45 10 16 11 43 13 51 15 16 16 64 18 45 Name: document, dtype: int64

 

fig, (ax1, ax2) = plt.subplots(1,2,figsize=(10,5)) 
ax1.hist(postive_len) 
ax1.set_title("positive") 
ax2.hist(negative_len) 
ax2.set_title("negative") 
fig.suptitle("Number of characters") 
plt.show()

형태소 분석하기

text = '한글 자연어 처리는 재밌다. 이제부터 열심히 해야지ㅎㅎㅎㅎ' 
okt.morphs(text)
# 형태소 분리 
okt.morphs(text, stem=True)
# 행태소로 분리, 어간 추출 
okt.nouns(text)
# 명사만 추출 
okt.phrases(text)
# 어절까지추출 
okt.pos(text) 
# 품살르 붙여서 형태소 분석



[('한글', 'Noun'), ('자연어', 'Noun'), ('처리', 'Noun'), ('는', 'Josa'), ('재밌다', 'Adjective'), ('.', 'Punctuation'), ('이제', 'Noun'), ('부터', 'Josa'), ('열심히', 'Adverb'), ('해야지', 'Verb'), ('ㅎㅎㅎㅎ', 'KoreanParticle')]

 

# 데이터 전처리

# 텍스트의 내용 중 한글, 영문, 공백을 제외한 다른 문자들은 제거

train['document'] = \ train['document'].str.replace("[^A-Za-z가-힣ㄱ-ㅎㅏ-ㅣ]","") 
train['document'].head() 


0 아더빙진짜짜증나네요목소리 
1 흠포스터보고초딩영화줄오버연기조차가볍지않구나 
2 너무재밓었다그래서보는것을추천한다 
3 교도소이야기구먼솔직히재미는없다평점조정 
4 사이몬페그의익살스런연기가돋보였던영화스파이더맨에서늙어보이기만했던커스틴던스트가너무나도이... 
Name: document, dtype: object


형태소 분석. stopword 제거 후 형태소 분석하기

def word_tokenization(text) : 
    # 한글 불용어 
    stop_words = ['는','을','를','이','가','의','던','고','하','다','은','에','들','지','게','도'] 
    return [word for word in okt.morphs(text) if word not in stop_words]

 

start = time.time() 
data = train['document'].apply((lambda x : word_tokenization(x))) 
print("실행시간 :", time.time()-start) 
data.head() 



실행시간 : 1631.960827589035 
0 [아더, 빙, 진짜, 짜증나네요, 목소리] 
1 [흠, 포스터, 보고, 초딩, 영화, 줄, 오버, 연기, 조차, 가볍지, 않구나] 
2 [너, 무재, 밓었, 다그, 래서, 보는것을, 추천, 한] 
3 [교도소, 이야기, 구먼, 솔직히, 재미, 없다, 평점, 조정] 
4 [사이, 몬페, 그, 익살스런, 연기, 돋보였던, 영화, 스파이더맨, 에서, 늙어,... 
Name: document, dtype: object

 

from tensorflow.keras.preprocessing.text import Tokenizer 
from tensorflow.keras.preprocessing.sequence 
import pad_sequences 
tokenizer = Tokenizer() tokenizer.fit_on_texts(data) 
print("총 단어 갯수:", len(tokenizer.word_index)) 
# 총 단어 갯수: 122402


5회 이상만 vocab_size 에 포함

def get_vocab_size(threshold) : 
	cnt = 0 
    for x in tokenizer.word_counts.values() : 
    	if x >=threshold : 
        	cnt += 1 
    return cnt

 

vocab_size = get_vocab_size(5) 

# 5회 이상 출현단어 

print("vocab_size:",vocab_size) 
# vocab_size: 23384

 

훈련 데이터 검증데이터 분리

training_size = 120000 
#train 분할 
train_sentences = data[:training_size] 
valid_sentences = data[training_size:] 
# label 분할 
train_labels = train['label'][:training_size] 
valid_labels = train['label'][training_size:]

 

print(train_sentences.shape) 
print(valid_sentences.shape) 


(120000,) 

(29995,)


토큰화하기

oov_tok = "<OOV>" 
vovab_size = 15000 
tokenizer = Tokenizer(oov_token = oov_tok, num_words=vocab_size) 
tokenizer.fit_on_texts(data) print("단어사전개수:",len(tokenizer.word_counts)) 
# 단어사전개수: 122402


문자를 숫자로 표현

print(train_sentences[:2]) 
train_sequences = tokenizer.texts_to_sequences(train_sentences) 
valid_sequences = tokenizer.texts_to_sequences(valid_sentences) 
print(train_sequences[:2]) print(valid_sequences[:2]) 

0 [아더, 빙, 진짜, 짜증나네요, 목소리] 
1 [흠, 포스터, 보고, 초딩, 영화, 줄, 오버, 연기, 조차, 가볍지, 않구나] 
Name: document, dtype: object 
[[13657, 16287, 8, 6835, 615], [1005, 423, 33, 554, 2, 354, 1539, 20, 1044, 6416, 1]] [[277, 9, 299, 208, 3401, 23332, 860, 9, 908, 178, 11017, 877, 3, 156, 48], [381, 158, 2, 487, 193, 2437, 38, 57, 259, 10630, 1, 33, 13153, 2, 72]]


문자의 최대길이

max_length = max(len(x) for x in train_sequences) 
print("문자 최대 길이:", max_length) 

# 문자 최대 길이: 69

 

train_padded = pad_sequences(train_sequences, padding = 'post', maxlen=max_length) 
valid_padded = pad_sequences(valid_sequences, padding = 'post', maxlen=max_length) 
train_padded[:1] 


array([[13657, 16287, 8, 6835, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

 

모델 구성하기

import tensorflow as tf 
from tensorflow.keras import Sequential 
from tensorflow.keras.layers import Dense, LSTM, Embedding, Bidirectional

 

def create_model() :
	# bi 양방향 rnn 
	# return_sequences=True 상대값 전달 
	model = Sequential([ Embedding(vocab_size, 32), 
                     Bidirectional(LSTM(32, return_sequences=True)), 
                     Dense(32, activation='relu'), 
                     Dense(1, activation='sigmoid') ]) 

	model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) 
    return model

 

model = create_model()
model.summary()


Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 32)          748288    
_________________________________________________________________
bidirectional_1 (Bidirection (None, None, 64)          16640     
_________________________________________________________________
dense_2 (Dense)              (None, None, 32)          2080      
_________________________________________________________________
dense_3 (Dense)              (None, None, 1)           33        
=================================================================
Total params: 767,041
Trainable params: 767,041
Non-trainable params: 0
_________________________________________________________________


딥러닝 모델의 구조가 복잡하고, 데이터 크기가 클수록 학습시간이 오래걸림.
=> 오랜시간 학습한 모델을 저장할 필요가 있음. modelcheckpoint 함수 이용
save_weights_only=True : weight 만저장
save_weights_only=False : 모델 레이터와 weight 모두 저장
save_best_only = True : 좋은 가중치만 저장
save_best_only = False : 모든 가중치 저장

checkpoint_path = 'best_performed_model.ckpt'
checkpoint = tf.keras.callbacks.ModelCheckpoint(checkpoint_path,
save_weights_only=True,
save_best_only = True,
monitor = 'val_loss', verbose=1)


earlystopping 함수 : 모델의 성능이 개선되지 않을 경우 학습을 중단
monitor = 'val_loss' : 성능평가 기준
patience=2 : 2 epochs 까지 개선되지 않으면 중지
call back : 함수에서 호출되는 함수

early_stop = tf.keras.callbacks.EarlyStopping(monitor='val_loss',patience=2)

 

학습하기

history = model.fit(train_padded, train_labels, validation_data=(valid_padded, valid_labels),
                   callbacks=[early_stop, checkpoint],
                   batch_size=64, epochs=10, verbose=2)
                   
                   
Epoch 1/10
1875/1875 - 31s - loss: 0.4138 - accuracy: 0.8022 - val_loss: 0.3530 - val_accuracy: 0.8437

Epoch 00001: val_loss improved from inf to 0.35297, saving model to best_performed_model.ckpt
Epoch 2/10
1875/1875 - 24s - loss: 0.3111 - accuracy: 0.8652 - val_loss: 0.3561 - val_accuracy: 0.8424

Epoch 00002: val_loss did not improve from 0.35297
Epoch 3/10
1875/1875 - 24s - loss: 0.2710 - accuracy: 0.8824 - val_loss: 0.3645 - val_accuracy: 0.8445

Epoch 00003: val_loss did not improve from 0.35297

 

def plot_graphs(history, metric) :
    plt.plot(history.history[metric])
    plt.plot(history.history['val_'+metric], '')
    plt.xlabel('Epochs')
    plt.ylabel(metric)
    plt.legend([metric, 'val_'+metric])
    plt.show()

 

plot_graphs(history, 'accuracy') 
plot_graphs(history, 'loss')

반응형

'Data_Science > Data_Analysis_Py' 카테고리의 다른 글

62. Tokenizer  (0) 2021.12.07
60. LSTM 기본  (0) 2021.12.07
58. IMDB || SimpleRNN  (0) 2021.12.07
57. seed || simpleRNN  (0) 2021.12.07
56. 영화리뷰 분석  (0) 2021.12.07

+ Recent posts