sudori

test code

1 +import pandas as pd
2 +import numpy as np
3 +%matplotlib inline
4 +import matplotlib.pyplot as plt
5 +import re
6 +import urllib.request
7 +from konlpy.tag import Okt
8 +from tensorflow.keras.preprocessing.text import Tokenizer
9 +from tensorflow.keras.preprocessing.sequence import pad_sequences
10 +from tensorflow.keras.layers import Embedding, Dense, LSTM
11 +from tensorflow.keras.models import Sequential
12 +from tensorflow.keras.models import load_model
13 +from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
14 +
15 +
16 +urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt", filename="ratings_train.txt")
17 +urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt", filename="ratings_test.txt")
18 +
19 +train_data = pd.read_table('ratings_train.txt')
20 +test_data = pd.read_table('ratings_test.txt')
21 +
22 +# 리뷰 내용이 잘리지 않도록 전체 샘플 중 길이가 max_len 이하인 샘플의 비율이 몇 %인지 확인하는 함수를 만든다.
23 +def below_threshold_len(max_len, nested_list):
24 + cnt = 0
25 + for s in nested_list:
26 + if(len(s) <= max_len):
27 + cnt = cnt + 1
28 + print('전체 샘플 중 길이가 %s 이하인 샘플의 비율: %s'%(max_len, (cnt / len(nested_list))*100))
29 +
30 +# 예측 함수
31 +def sentiment_predict(new_sentence):
32 + new_sentence = okt.morphs(new_sentence, stem=True) # 토큰화
33 + new_sentence = [word for word in new_sentence if not word in stopwords] # 불용어 제거
34 + encoded = tokenizer.texts_to_sequences([new_sentence]) # 정수 인코딩
35 + pad_new = pad_sequences(encoded, maxlen = max_len) # 패딩
36 + score = float(loaded_model.predict(pad_new)) # 예측
37 + if(score > 0.5):
38 + print("{:.2f}% 확률로 긍정 리뷰입니다.\n".format(score * 100))
39 + else:
40 + print("{:.2f}% 확률로 부정 리뷰입니다.\n".format((1 - score) * 100))
41 +
42 +print('훈련용 리뷰 개수 :',len(train_data)) # 훈련용 리뷰 개수 출력
43 +
44 +train_data[:5] # 상위 5개 출력
45 +print('테스트용 리뷰 개수 :',len(test_data)) # 테스트용 리뷰 개수 출력
46 +
47 +test_data[:5]
48 +train_data['document'].nunique(), train_data['label'].nunique()
49 +
50 +train_data.drop_duplicates(subset=['document'], inplace=True) # document 열에서 중복인 내용이 있다면 중복 제거
51 +
52 +print('총 샘플의 수 :',len(train_data))
53 +
54 +train_data['label'].value_counts().plot(kind = 'bar')
55 +
56 +print(train_data.groupby('label').size().reset_index(name = 'count'))
57 +
58 +print(train_data.isnull().values.any())
59 +
60 +print(train_data.isnull().sum())
61 +
62 +train_data.loc[train_data.document.isnull()]
63 +
64 +train_data = train_data.dropna(how = 'any') # Null 값이 존재하는 행 제거
65 +print(train_data.isnull().values.any()) # Null 값이 존재하는지 확인
66 +
67 +print(len(train_data))
68 +
69 +text = 'do!!! you expect... people~ to~ read~ the FAQ, etc. and actually accept hard~! atheism?@@'
70 +re.sub(r'[^a-zA-Z ]', '', text) #알파벳과 공백을 제외하고 모두 제거
71 +
72 +train_data['document'] = train_data['document'].str.replace("[^ㄱ-ㅎㅏ-ㅣ가-힣 ]","")
73 +# 한글과 공백을 제외하고 모두 제거
74 +train_data[:5]
75 +
76 +train_data['document'].replace('', np.nan, inplace=True)
77 +print(train_data.isnull().sum())
78 +
79 +train_data.loc[train_data.document.isnull()][:5]
80 +
81 +train_data = train_data.dropna(how = 'any')
82 +print(len(train_data))
83 +
84 +test_data.drop_duplicates(subset = ['document'], inplace=True) # document 열에서 중복인 내용이 있다면 중복 제거
85 +test_data['document'] = test_data['document'].str.replace("[^ㄱ-ㅎㅏ-ㅣ가-힣 ]","") # 정규 표현식 수행
86 +test_data['document'].replace('', np.nan, inplace=True) # 공백은 Null 값으로 변경
87 +test_data = test_data.dropna(how='any') # Null 값 제거
88 +print('전처리 후 테스트용 샘플의 개수 :',len(test_data))
89 +
90 +stopwords = ['의','가','이','은','들','는','좀','잘','걍','과','도','를','으로','자','에','와','한','하다']
91 +
92 +okt = Okt()
93 +okt.morphs('와 이런 것도 영화라고 차라리 뮤직비디오를 만드는 게 나을 뻔', stem = True)
94 +
95 +X_train = []
96 +for sentence in train_data['document']:
97 + temp_X = []
98 + temp_X = okt.morphs(sentence, stem=True) # 토큰화
99 + temp_X = [word for word in temp_X if not word in stopwords] # 불용어 제거
100 + X_train.append(temp_X)
101 +
102 +print(X_train[:3])
103 +
104 +X_test = []
105 +for sentence in test_data['document']:
106 + temp_X = []
107 + temp_X = okt.morphs(sentence, stem=True) # 토큰화
108 + temp_X = [word for word in temp_X if not word in stopwords] # 불용어 제거
109 + X_test.append(temp_X)
110 +
111 +# 정수 인코딩
112 +tokenizer = Tokenizer()
113 +tokenizer.fit_on_texts(X_train)
114 +print(tokenizer.word_index)
115 +
116 +threshold = 3
117 +total_cnt = len(tokenizer.word_index) # 단어의 수
118 +rare_cnt = 0 # 등장 빈도수가 threshold보다 작은 단어의 개수를 카운트
119 +total_freq = 0 # 훈련 데이터의 전체 단어 빈도수 총 합
120 +rare_freq = 0 # 등장 빈도수가 threshold보다 작은 단어의 등장 빈도수의 총 합
121 +
122 +# 단어와 빈도수의 쌍(pair)을 key와 value로 받는다.
123 +for key, value in tokenizer.word_counts.items():
124 + total_freq = total_freq + value
125 +
126 + # 단어의 등장 빈도수가 threshold보다 작으면
127 + if(value < threshold):
128 + rare_cnt = rare_cnt + 1
129 + rare_freq = rare_freq + value
130 +
131 +print('단어 집합(vocabulary)의 크기 :',total_cnt)
132 +print('등장 빈도가 %s번 이하인 희귀 단어의 수: %s'%(threshold - 1, rare_cnt))
133 +print("단어 집합에서 희귀 단어의 비율:", (rare_cnt / total_cnt)*100)
134 +print("전체 등장 빈도에서 희귀 단어 등장 빈도 비율:", (rare_freq / total_freq)*100)
135 +
136 +# 전체 단어 개수 중 빈도수 2이하인 단어 개수는 제거.
137 +# 0번 패딩 토큰과 1번 OOV 토큰을 고려하여 +2
138 +vocab_size = total_cnt - rare_cnt + 2
139 +print('단어 집합의 크기 :',vocab_size)
140 +
141 +tokenizer = Tokenizer(vocab_size, oov_token = 'OOV')
142 +tokenizer.fit_on_texts(X_train)
143 +X_train = tokenizer.texts_to_sequences(X_train)
144 +X_test = tokenizer.texts_to_sequences(X_test)
145 +print(X_train[:3])
146 +
147 +y_train = np.array(train_data['label'])
148 +y_test = np.array(test_data['label'])
149 +
150 +drop_train = [index for index, sentence in enumerate(X_train) if len(sentence) < 1]
151 +
152 +# 빈 샘플들을 제거
153 +X_train = np.delete(X_train, drop_train, axis=0)
154 +y_train = np.delete(y_train, drop_train, axis=0)
155 +print(len(X_train))
156 +print(len(y_train))
157 +
158 +# 패딩
159 +print('리뷰의 최대 길이 :',max(len(l) for l in X_train))
160 +print('리뷰의 평균 길이 :',sum(map(len, X_train))/len(X_train))
161 +plt.hist([len(s) for s in X_train], bins=50)
162 +plt.xlabel('length of samples')
163 +plt.ylabel('number of samples')
164 +plt.show()
165 +
166 +max_len = 30
167 +below_threshold_len(max_len, X_train)
168 +X_train = pad_sequences(X_train, maxlen = max_len)
169 +X_test = pad_sequences(X_test, maxlen = max_len)
170 +
171 +# LSTM 영화 리뷰 감성 분류 모델 제작
172 +model = Sequential()
173 +model.add(Embedding(vocab_size, 100))
174 +model.add(LSTM(128))
175 +model.add(Dense(1, activation='sigmoid'))
176 +
177 +es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=4)
178 +mc = ModelCheckpoint('best_model.h5', monitor='val_acc', mode='max', verbose=1, save_best_only=True)
179 +model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
180 +history = model.fit(X_train, y_train, epochs=15, callbacks=[es, mc], batch_size=60, validation_split=0.2)
181 +
182 +# best model load
183 +loaded_model = load_model('best_model.h5')
184 +print("\n 테스트 정확도: %.4f" % (loaded_model.evaluate(X_test, y_test)[1]))
185 +
186 +sentiment_predict('이 영화 넘재밌어')
187 +sentiment_predict('감독 뭐하는 놈이냐?')
188 +sentiment_predict('와 개쩐다 정말 세계관 최강자들의 영화다')
189 +sentiment_predict('눈물이 주륵주륵 흐르네 그냥 ㅋㅋ')
190 +sentiment_predict('진짜 개재밌다 ㅋㅋㅋㅋㅋ')
191 +sentiment_predict('절대 보지마라 개 쓰레기영화 ㅋㅋ')
192 +sentiment_predict('아유 개 씹노잼 영화 돈버린다')
...\ No newline at end of file ...\ No newline at end of file