목표 : 레드와인, 화이트 와인 구분하기
데이터: UCI repository 데이터
- 6497개 행
- 레드와인 1599개, 화이트와인이 4898개
- 13개 컬럼
- 12개 feature : 주석산 농도, 아세트산 농도, 구연산 농도, 잔류 당분 농도, 염화나트륨 농도, 유리 아황산 농도, 총 아황산 농도, 밀도, PH, 황산칼륨 농도, 알코올 도수, 와인 맛(0~10등급)
- class: 레드와인(1), 화이트와인(0)
from keras.models import Sequential
from keras.layers import Dense
from keras.callbacks import ModelCheckpoint, EarlyStopping # 모델 최고값 저장,
import numpy
import pandas as pd
import os
import tensorflow as tf
import matplotlib.pyplot as plt
라이브러리들 임포트하기
import os의 os는 operating system 의 약자로서
운영체제에서 제공되는 여러 기능을 파이썬에서 수행할 수 있게 해준다.
파이썬을 이용한 파일 복사, 디렉터리 생성, 특정 디렉터리 내의 파일 목록 구할 때,
사용하면 된다. 이번엔 폴더를 생성할 때 사용했다.
# seed값 설정
seed = 0
numpy.random.seed(seed)
tf.set_random_seed(seed)
난수 생성하면서 시드값을 주어
동일한 결과값이 나올 수 있게 해준다.
df_pre = pd.read_csv('./dataset/wine.csv') ; df_pre
판다스를 이용하여 와인데이터를 불러오면
다음과 같이 데이터가 불려온다.
그런데 컬럼명이 난잡하게 되어있다.
#데이터 입력
df_pre = pd.read_csv('./dataset/wine.csv', header = None)
df_pre
깔끔하게 컬럼명을 정리해주기 위해서
header = None 을 이용해주었다.
# 데이터 샘플링
df = df_pre.sample(frac = 0.5) # 랜덤 샘플을 가져오는데 그중 50%만 가져오겠다.
df
만약 데이터 중에 일부만을 추출하고 싶다면
frac(분수, 비율)을 이용하여 추출할 수 있다.
0.5면 절반의 랜덤 데이터를 추출한다.
기존의 6497 행에서 3248행이 된 것을 확인할 수 있다.
df = df_pre.sample(frac = 1)
df
물론 'frac = 1'을 하면 모두 가져온다.
dataset = df.values ; dataset
array([[ 6.3 , 0.24, 0.22, ..., 9.3 , 6. , 0. ],
[ 6.7 , 0.3 , 0.44, ..., 9.1 , 5. , 0. ],
[ 8.1 , 0.12, 0.38, ..., 12. , 6. , 0. ],
...,
[ 8. , 0.28, 0.42, ..., 10.6 , 5. , 0. ],
[ 7.5 , 0.26, 0.3 , ..., 12. , 7. , 0. ],
[ 7.7 , 0.31, 0.36, ..., 12. , 5. , 0. ]])
dataset은 df.values라고 정의해줌으로써
값들만 가져온다.
X = dataset[:, 0:12 ] #와인의 features
Y = dataset[:, 12] #레드(1)인지 화이트(0)인지
X는 features들이며 모든행, 0번부터 11번까지[12개]의 열로 정의한다.
Y는 class 결과값이며 12번째 열로 정의한다.
print(X.shape)
X
(6497, 12)
array([[ 6.3 , 0.24, 0.22, ..., 0.58, 9.3 , 6. ],
[ 6.7 , 0.3 , 0.44, ..., 0.53, 9.1 , 5. ],
[ 8.1 , 0.12, 0.38, ..., 0.55, 12. , 6. ],
...,
[ 8. , 0.28, 0.42, ..., 0.43, 10.6 , 5. ],
[ 7.5 , 0.26, 0.3 , ..., 0.38, 12. , 7. ],
[ 7.7 , 0.31, 0.36, ..., 0.48, 12. , 5. ]])
X를 출력해보면 이와 같다.
print(Y.shape)
Y
(6497,)
array([0., 0., 0., ..., 0., 0., 0.])
Y도 0과 1로 이루어진 값들로 출력된다.
여긴 0밖에 안보이지만..
모델 짜기
# 모델 설정
model = Sequential()
model.add(Dense(32, input_dim = 12, activation = 'relu' )) #인풋딤 피쳐가 12개, 히든레이어 1
model.add(Dense(16, activation = 'relu')) #히든레이어2
model.add(Dense(8, activation = 'relu')) #히든레이어3
model.add(Dense(1, activation = 'sigmoid'))
Dense층은 사용자의 마음이다.
컴퓨터가 2진수를 사용하기 때문에
2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, ...
2의 배수를 사용해주면 좋다는 설이 있다.
input 데이터는 features의 개수인 12개이고
0또는 값을 출력해주는(positive) relu를 사용한다.
마지막 결과값은 0또는 1로만 출력되면 되므로
sigmoid함수를 사용해준다.
# 모델 컴파일
model.compile(loss = 'binary_crossentropy', optimizer = 'adam', metrics = ['accuracy'])
모델을 만들었으면 컴파일을 해주어야 한다.
화이트인지 레드인지를 결정하는 이진분류이므로
binary_crossentropy를 사용한다.
체크포인트 만들어서 모델 저장하기
# 모델 저장 폴더 설정
MODEL_DIR = './model/' #같은 폴더 내에 model이라는 폴더가 없다면 만들어줘라
if not os.path.exists(MODEL_DIR):
os.mkdir(MODEL_DIR) #mkdir이 폴더 생성 함수
# 모델 저장 조건 설정
modelpath = './model/{epoch:02d}-{val_loss:.4f}.hdf5'
checkpointer = ModelCheckpoint(filepath = modelpath, monitor='val_loss', verbose = 1, save_best_only = True)
Earlystopping 설정
과적합 방지하려고 사용
트레인 셋에만 과적합(overfitting)된 모델을 만들지 않고 테스트 셋에도 잘 작동하는 모델을 만들기 위함.
# 학습 자동중단 설정
early_stopping_callback = EarlyStopping(monitor = 'val_loss', patience=10)
#10번 똑같은 정확도가 나오면 중단. 몇번 참느냐
그래프 없이 실행
# 모델 실행
model.fit(X, Y, validation_split = 0.2, epochs=500, batch_size=200, verbose = 0,\
callbacks=[checkpointer, early_stopping_callback]) # 트레인셋의 일부를 떼서 시험(split)
Epoch 00001: val_loss improved from inf to 0.32031, saving model to ./model/01-0.3203.hdf5
.
.
.
Epoch 00157: val_loss improved from 0.06108 to 0.06034, saving model to ./model/157-0.0603.hdf5
Epoch 00158: val_loss did not improve from 0.06034
Epoch 00159: val_loss did not improve from 0.06034
.
.
.
Epoch 00167: val_loss did not improve from 0.06034
<keras.callbacks.History at 0x1d924c35688>
위쪽에 조기 종료를 설정(10번)해놔서 167번째에
학습이 종료된 것을 확인할 수 있다.
개선이 안되는 것이 10번이 되면 학습을 종료하는 것이다.
157번째에는 이전보다 나은 결과값이기 때문에 저장을 해주었다.
그래프로 테스트셋 오차, 학습셋 정확도 확인
history = model.fit(X,Y,validation_split=0.3, epochs= 500, batch_size=200, verbose = 1, callbacks=[checkpointer, early_stopping_callback])
Train on 4547 samples, validate on 1950 samples
Epoch 1/500
4547/4547 [==============================] - 1s 166us/step - loss: 0.5568 - acc: 0.7581 - val_loss: 0.3416 - val_acc: 0.8026
.
.
.
Epoch 00160: val_loss did not improve from 0.06593
Epoch 161/500
4547/4547 [==============================] - 0s 29us/step - loss: 0.0502 - acc: 0.9837 - val_loss: 0.0690 - val_acc: 0.9836
Epoch 00161: val_loss did not improve from 0.06593
history.history
{'val_loss': [0.3416376977394789,
0.292307999653694,
0.2607175287527916,
0.2369998051570012,
.
.
'val_acc': [0.8025641013414432,
0.8974358882659521,
0.9256410369506249,
0.9271794970218952,
.
.
'loss': [0.5568385381789844,
0.31718681494115286,
0.2812257196016041,
0.256641304451003,
.
.
'acc': [0.7580822551410382,
0.8878381381277097,
0.909830655046471,
0.9225863215685782,
0.9307235562594246,
history를 찍어보면 객체 네가지가 나온다.
loss는 매 에포크 마다의 훈련 손실값
acc는 매 에포크 마다의 훈련 정확도
val_loss는 매 에포크 마다의 검증 손실값
val_acc는 매 에포크 마다의 검증 정확도이다.
앞의 val은 validation이다.
validation loss가 증가하기 시작한다면, 모델이
과적합이 되고 있다고 판단할 수 있다.
버전이 2.0이상이라면 'val_accuracy'같이
다르게 나올 수 있으므로 history로 확인해주자
y_vloss = history.history['val_loss'] # 테스트셋 오차
#print(len(y_vloss)) # shape함수는 리스트에 적용안됨
# 학습셋 정확도
y_acc = history.history['acc']
#y_acc
# 테스트셋 정확도
y_val_accuracy = history.history['val_acc']
#y_val_accuracy
x_len = numpy.arange(len(y_acc))
#학습셋 정확도 라인
plt.plot(x_len, y_acc, 'o', c='blue', markersize=3, label = 'Trainset_accuarcy')
#테스트셋 오차 라인
plt.plot(x_len, y_vloss, 'o', c='red', markersize=3, label = 'Testset_loss')
plt.legend(loc='best') #location right, left, upper rigtht 등등
plt.grid() # 격자
plt.xlabel('epoch')
plt.ylabel('score')
plt.show()
# 테스트 정확도 출력
print(' Accuracy: %.4f' % y_val_accuracy[-1])
#제일 마지막 정확도를 가져오고 싶어서 인덱싱 -1번
감사합니다~~
😁
참고한 곳: https://tykimos.github.io/2017/07/09/Training_Monitoring/
https://doorbw.tistory.com/172
https://kevinthegrey.tistory.com/136
'Data Scientist' 카테고리의 다른 글
기초통계 - 척도 (0) | 2020.02.07 |
---|---|
챗봇솔루션 closer를 이용한 나만의 챗봇 만들기! (0) | 2020.02.06 |
폐암수술 환자 생존율 예측 (1) | 2020.01.24 |
피마 인디언 당뇨병 예측하기 - 2편: 딥러닝 구조 짜기 (0) | 2020.01.24 |
피마 인디언 당뇨병 예측하기 - 1편: 데이터 불러오기 (0) | 2020.01.23 |