본문 바로가기

책/딥러닝으로 걷는 시계열 예측

회귀모델

딥러닝

  • 회귀모델 : y = wx + b
  • 분류모델

101 ~ 110 acc(정확도)는 1이 나올수가 없음

x_test ouptut
101 [100.99708]
102 [100.00705]
103 [102.997025]
104 [103.99698]
105 [104.996965]
106 [105.99692]
107 [106.99689]
108 [107.99686]
109 [108.99683]
110 [109.996796]

 

기존에 가지고 있던 데이터들을 이 함수에 최대한 적용시켜야 함

머신이 다음과 같은 1차 함수가 되도록 훈련할 수 있게 서포트 하여야 함

  • 이렇게 모델을 유도하고, 데이터를 정제해아 하는 작업이 우리가 해야 할 일
  • 얼마나 매끈한 1차 함수가 되도록 만들어주느냐, 이것이 관건

2차 함수와 같은 모양을 띈 모델과 데이터는 어떻게?

  • 미분을 통하여 1차 함수로 바꿔 줌
  • y = 2ax + 0
  • 1차 함수로 만들었기 때문에 딥러닝 회귀분석을 실행할 수 있음

더보기

 머신러닝과 딥러닝을 공부하다 보면, 통계와 수학에 대한 많은 기초가 있다면 훨씬 수월하다는 것을 알 것이다. 그러나 꼭 통계와 수학을 완벽하게 알아야 할 필요는 없다. 적당히 사용법만 알아 두는 정보면 된다. 그리고 그 전후로 필요한 수학과 통계 부분들을 공부하면 된다.

 내용을 전부 숙지하기보다, 꼭 필요할 때마다 하나씩 찾아보거나 소스를 먼저 익힌 다음에 수학부분을 응용하면 훨씬 쉽게 접근할 수 있다.

 

  • 회귀 분석은 선형이기 때문에 딱 맞아 떨어지는 것이 아니다. 그래서 결괏값 예측 분석을 하는 함수를 다른 것으로 쓰게 된다.
## 기존 소스에서 metrics 부분만 accuracy 에서 mse로 변경

model.compile(loss='mse', optimizer='adam', metrics=['mse'])

 

  • acc 대신 mse로 변경해 준 부분은 머신이 훈련할 때 보여주는 부분이 acc 대신 mse(mean squared error)로 표현하겠다는 뜻
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 5)                 10        
_________________________________________________________________
dense_1 (Dense)              (None, 3)                 18        
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 4         
=================================================================
Total params: 32
Trainable params: 32
Non-trainable params: 0
_________________________________________________________________
Epoch 1/500
10/10 [==============================] - 0s 29ms/step - loss: 38.5000 - mse: 38.5000 
- val_loss: 11138.5000 - val_mse: 11138.5000
Epoch 2/500

회귀 모델의 판별식

회귀 모델의 판별식

# RMSE 구하기
from sklearn.metrics import mean_squard_error
def RMSE(y_text, y_predict) :
    return np.sqrt(mean_squared_error(y_test, y_predict))

print("RMSE : ", RMSE(y_test, y_predict))   

 

오류가 있다면 다음과 같이 처리

  • pip install --upgrade scikit-learn
(deeplearning) C:\JetBrains\python_workspace\deeplearning>pip install --upgrade scikit-learn

 

RMSE(평균 제곱근 오차, Root Mead Squared Error) 

  • 회귀 분석을 평가할 때 가장 많이 쓰는 지표
  • MSE에 루트를 씌운 것이 RMSE
  • 원래 데이터에서 평균을 뺀 값을 제곱하여 모두 더한 뒤 전체 개수로 나눈 값에 루트를 씌운 것
  • 회귀 분석 모델을 만들 때 RMSE는 낮을 수 록 정밀도가 높음

 

결과

  • RMSE 가 0.97 이라고 해서 97%가 아님. 그대로의 숫자로 판단. 
    • 6000, 7000 은 높음,  0.0000001 은 낮음

 

R2 (R2, R2 Score, R제곱, 설명력, 결정계수)

  • 높을 수록 좋은 지표
  • MAX 값은 1
  • 0.73이 나왔을 경우 모델식이 R2로 계산했을 때 73%의 설명력을 가졌다고 해석
  • R2가 음의 값(-1349.121212121212)이 나왔다는 것은 학습 시에  머신에 뭔가 잘못된 부분이 있을 수 있다는 의미

# R2 구하기
from sklearn.metrics import r2_score
r2_y_predict = r2_score(y_test, y_predict)
print("R2 : ", r2_y_predict)


'''
결과

RMSE :  105.53909228338095
R2 :  -1349.121212121212
'''

회귀모델 추가 코딩

1) Validation 추가

훈련셋, 테스트셋, 검증셋은 분리가 되는 것이 좋은 데이터의 형태

  • 훈련셋에 검증값이 들어가고 그 검증값으로 다시 테스트로 사용한다는 것은 평가에 검증값이 반영되는 문제
x_train y_train
x_validation y_validation
x_test y_test

검증용 데이터 추가

  • model.fit(x_train, y_train, epochs=1000, batch_size=1,validation_data=(x_val, y_val))
  • 1 ~ 10까지의 데이터를 훈련 시킬 때 101 ~ 105까지의 데이터를 검증용 데이터로 사용
  • 11 ~ 20까지의 데이터로 테스트
  • Validation을 추가했다고 더 좋은 값이 나오는 것이 눈에 확 띄지는 않지만, 데이터가 많아질 수록 train 데이터에서의 일부의 검증셋을 분리하여 훈련하는 것이 머신의 훈련에 더 좋은 효과를 발휘하게 된다.
#1. 데이터
import numpy as np
x_train = np.array([1,2,3,4,5,6,7,8,9,10])
y_train = np.array([1,2,3,4,5,6,7,8,9,10])
x_test = np.array([11,12,13,14,15,16,17,18,19,20])
y_test = np.array([11,12,13,14,15,16,17,18,19,20])
x_val = np.array([101,102,103,104,105])
y_val = np.array([101,102,103,104,105])

#2. 모델 구성
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()

# model.add(Dense(5, input_dim = 1, activation ='relu'))
model.add(Dense(5, input_shape = (1, ), activation ='relu'))
model.add(Dense(3))
model.add(Dense(4))
model.add(Dense(1))
# model.summary()

#3. 훈련
model.compile(loss='mse', optimizer='adam', metrics=['mse'])
model.fit(x_train, y_train, epochs=1000, batch_size=1,
validation_data=(x_val, y_val))

#4. 평가 예측
mse = model.evaluate(x_test, y_test, batch_size=1)
print("mse : ", mse)
y_predict = model.predict(x_test)
print(y_predict)

#RMSE 구하기
from sklearn.metrics import mean_squared_error
def RMSE(y_test, y_predict):
    return np.sqrt(mean_squared_error(y_test, y_predict))
print("RMSE : ", RMSE(y_test, y_predict))
# R2 구하기
from sklearn.metrics import r2_score
r2_y_predict = r2_score(y_test, y_predict)
print("R2 : ", r2_y_predict)

결과

mse :  [9.18589683485127e-12, 9.18589683485127e-12]
[[11.000001]
 [12.000001]
 [12.999999]
 [13.999998]
 [14.999998]
 [15.999997]
 [16.999996]
 [17.999996]
 [18.999994]
 [19.999994]]
RMSE :  3.3582338069265383e-06
R2 :  0.999999999998633

Process finished with exit code 0

2) 데이터를 분리

1 부터 100까지의 데이터를 준비

#1. 데이터
import numpy as np
x = np.array(range(1,101))
y = np.array(range(1,101))

 

해당 데이터셋을 6:2:2의 비율로 Train:Val:Test셋으로 나눔

x_train = x[:60]
x_val = x[60:80]
x_test = x[80:]
y_train = y[:60]
y_val = y[60:80]
y_test = y[80:]

 

결과 실행

mse :  [4.5823981054127216e-08, 4.5823981054127216e-08]
[[ 81.00019 ]
 [ 82.00019 ]
 [ 83.00019 ]
 [ 84.00019 ]
 [ 85.00019 ]
 [ 86.0002  ]
 [ 87.000206]
 [ 88.000206]
 [ 89.00022 ]
 [ 90.00022 ]
 [ 91.00021 ]
 [ 92.000206]
 [ 93.00021 ]
 [ 94.00022 ]
 [ 95.00024 ]
 [ 96.00022 ]
 [ 97.00025 ]
 [ 98.00024 ]
 [ 99.00024 ]
 [100.00024 ]]
RMSE :  0.00021479828310081982
R2 :  0.9999999986123819

 

이 모델의 문제점

  • x_test 값으로 predict
  • 가급적이면 test한 값 보다는 새로운 데이터로 예측하는 것이 좋음
  • x_predict = np.array(range(101,111))
  • y_predict = model.predict(x_predict)
x_train y_train
x_validation y_validation
x_test y_test
x_predict  
#1. 데이터
import numpy as np
x = np.array(range(1,101))
y = np.array(range(1,101))

x_train = x[:60]
x_val = x[60:80]
x_test = x[80:]

x_predict = np.array(range(101,111))

y_train = y[:60]
y_val = y[60:80]
y_test = y[80:]

.....

#4. 평가 예측
mse = model.evaluate(x_test, y_test, batch_size=1)
print("mse : ", mse)

y_predict = model.predict(x_predict)

print(y_predict)

 

결과

mse :  [4.249159357705423e-10, 4.249159357705423e-10]
[[101.00003 ]
 [102.000015]
 [103.00001 ]
 [104.000015]
 [105.00002 ]
 [106.00002 ]
 [107.000015]
 [108.000015]
 [109.00003 ]
 [110.00002 ]]

3) train_test_split

데이터를 잘라주는 함수

  • x, y 값
  • test_size : train_size를 넣을 수 있음
    • train_size=0.6 과 test_size=0.4는 같은의미 traint_size + test_size = 1 즉 100%라는 뜻
    • train_size 와 test_size를 동시에 사용할 경우 train_size로 우선 잘리게 됨
  • shuffle : 잘라낸 데이터를 섞을지 여부
    • x = (1, 2, 3), y=(4, 5, 6) 일경우  true로 섞인다면 x = (2, 3, 1) y = (5, 6, 4) 쌍으로 섞이게 됨
    • x = (2, 3, 1), y=(4, 6, 5) 처럼 x와 y 따로 무작위로 섞이지 않음
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(
    x,
    y,
    random_state=66,   ## 
    test_size=0.4,     ## test_size 가 40% 라는 의미
    shuffle=false      ## 잘라낸 데이터를 섞을지 여부
)

 

Test 데이터의 50%를 validation에 배분하게 되어 전체적으로 train:val:test의 비율이 6:2:2가 됨

#1. 데이터
import numpy as np
x = np.array(range(1,101))
y = np.array(range(1,101))

from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(
       x, y, random_state=66, test_size=0.4, shuffle=False
)

## validation을 만들기위해 한번더 적용
x_val, x_test, y_val, y_test = train_test_split(
    x_test, y_test, random_state=66, test_size=0.5, shuffle=False
)

 

실행결과

mse :  [2.1827872842550278e-10, 2.1827872842550278e-10]
[[ 81.000015]
 [ 82.00001 ]
 [ 83.00001 ]
 [ 84.      ]
 [ 85.000015]
 [ 86.00001 ]
 [ 87.000015]
 [ 88.00001 ]
 [ 89.00001 ]
 [ 90.000015]
 [ 91.000015]
 [ 92.00003 ]
 [ 93.00001 ]
 [ 94.000015]
 [ 95.000015]
 [ 96.000015]
 [ 97.00002 ]
 [ 98.00001 ]
 [ 99.000015]
 [100.000015]]
RMSE :  1.4475758332069607e-05
R2 :  0.9999999999936978

함수형 모델

1) 1:1

케라스 딥러닝의 모델 구성 방식

  • 순차형 모델
  • 함수형모델
    • 모델이 길어지고 앙상블등의 여러가지 기법을 사용하고자 한다면 필수

 

기존의 데이터는 재사용 모델 구성

  1. Input 레이어를 구성, 입력 shave를 구성. 1개의 컬럼이 들어가므로 input1 = Input(shape=(1,))으로 구성
  2. 다음 레이어 부터는 순차형의 시쿼스형처럼 구성을 하되 상위층에서 출력된 레이어의 이름을 하위층의 가장 끝부분에 명시
    • dense1 = Dense(5, activation='relu')(input1)
    • 이후 동일하게 연결

      dense2 = Dense(3)(dense1)

      dense3 = Dense(4)(dense2)

      output1 = Dense(1)(dense3)

  3. 마지막으로 Model로 전체레이어를 엮어줌
    • model = Model(inputs = input1, outputs= output1)
#2. 모델 구성
from keras.models import Sequential, Model # Model을 추가해준다.
from keras.layers import Dense, Input # Input 레이어를 추가해준다.

# model = Sequential()
input1 = Input(shape=(1,))
dense1 = Dense(5, activation='relu')(input1)
dense2 = Dense(3)(dense1)
dense3 = Dense(4)(dense2)
output1 = Dense(1)(dense3)
model = Model(inputs = input1, outputs= output1)
model.summary()

 

총 49개의 모델을 사용한 간단한 심층 신경망

Model: "functional_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 1)]               0         
_________________________________________________________________
dense (Dense)                (None, 5)                 10        
_________________________________________________________________
dense_1 (Dense)              (None, 3)                 18        
_________________________________________________________________
dense_2 (Dense)              (None, 4)                 16        
_________________________________________________________________
dense_3 (Dense)              (None, 1)                 5         
=================================================================
Total params: 49
Trainable params: 49
Non-trainable params: 0
_________________________________________________________________

 

결과

mse :  [3.5845358070218936e-05, 3.5845358070218936e-05]
[[80.99502 ]
 [81.99491 ]
 [82.994804]
 [83.9947  ]
 [84.99461 ]
 [85.99451 ]
 [86.99439 ]
 [87.99429 ]
 [88.9942  ]
 [89.99409 ]
 [90.99399 ]
 [91.9939  ]
 [92.99379 ]
 [93.99368 ]
 [94.993576]
 [95.993484]
 [96.99337 ]
 [97.99327 ]
 [98.99318 ]
 [99.99307 ]]
RMSE :  0.005987267434121411
R2 :  0.9999989218835691

2) 다:다

2개 이상의 컬럼이 입력되는 경우

  • 1 ~ 100까지의 정수
  • 301 ~ 400까지의 정수
#1. 데이터
import numpy as np
x = np.array([range(100), range(301,401)])
y = np.array([range(100), range(301,401)])
print(x.shape)
print(y.shape)
'''
결과 2행 100열 구조
(2, 100)
(2, 100)

'''

x = np.transpose(x)
y = np.transpose(y)
print(x.shape)
print(y.shape)
'''
결과 100행 2열 구조
(100, 2)
(100, 2)
'''

 

train, test, val의 데이터를 6:2:2로 구성

from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(
x, y, random_state=66, test_size=0.4, shuffle=False
)

x_val, x_test, y_val, y_test = train_test_split(
x_test, y_test, random_state=66, test_size=0.5, shuffle=False
)

 

모델구성

  • input_dim = 1 에서 2로 바뀜
    • model.add(Dense(5, input_shape = (2, ), activation ='relu'))
  • 최종 아웃풋이 1에서 2로 바뀜
    • model.add(Dense(2))
#2. 모델 구성
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
# model.add(Dense(5, input_dim = 2, activation ='relu'))
model.add(Dense(5, input_shape = (2, ), activation ='relu'))
model.add(Dense(3))
model.add(Dense(4))
model.add(Dense(2))

 

훈련, 평가 예측은 동일

 

결과

mse :  [1724.2828369140625, 1724.2828369140625]
RMSE :  41.52448891223674
R2 :  -50.858140734510435

3) 다:1

다:다 모델에서 아웃풋만 1개인 경우를 의미

  • 100개의 데이터씩 2개의 컬럼이 입력되어, 100개의 데이터 1개가 출력되는 구조
  • 인풋과 아웃풋의 shape만 조절. 모델에 적합하게 reshape시켜줌
    • y의 shape (100, )  (1행 100열이 아니라 벡터가 100개라는 의미) 이므로 tranport 하지 않음
#1. 데이터
import numpy as np

x = np.array([range(100), range(301,401)])
y = np.array(range(201,301))
x = np.transpose(x)

 

최종 아웃풋 레이어만 1로 변경

  • model.add(Dense(1))
#2. 모델 구성
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(5, input_shape = (2, ), activation ='relu'))
model.add(Dense(3))
model.add(Dense(4))

model.add(Dense(1))

# model.summary()

 

결과

mse :  [3.395858220756054e-05, 3.395858220756054e-05]
RMSE :  0.005827694921758226
R2 :  0.999998978585621

4) 1:다

1개의 컬럼이 입력되어 어러개의 컬럼으로 출력되는 경우

  • 데이터 자체로 판단해서는 이상한 모델이지만 이 역시 구현 가능함
#1. 데이터
import numpy as np

x = np.array([range(100)])
y = np.array([range(201,301), range(301,401)])
x = np.transpose(x)
y = np.transpose(y)
print(x.shape)
print(y.shape)

'''
결과 
(100, 1)  100행 1열
(100, 2)  100행 2열
'''

 

모델

  • input_shape 가 1로 바뀜
  • 마지막 출력의 Dense층의 아웃풋을 2로 변경
#2. 모델 구성
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
# model.add(Dense(5, input_dim = 3, activation ='relu'))

model.add(Dense(5, input_shape = (1, ), activation ='relu'))

model.add(Dense(3))
model.add(Dense(4))

model.add(Dense(2))

 

실행결과

  • 결괏값이 좋지 않지만 1:다 모델도 가능
mse :  67784.5234375
[[444.179   630.5826 ]
 [449.0547  637.5634 ]
 [453.9304  644.54425]
 [458.80606 651.52496]
 [463.68173 658.50574]
 [468.5574  665.4866 ]
 [473.43304 672.46735]
 [478.30878 679.4481 ]
 [483.18442 686.42896]
 [488.06012 693.4098 ]
 [492.9358  700.3906 ]
 [497.81146 707.3714 ]
 [502.68713 714.35223]
 [507.56284 721.333  ]
 [512.4385  728.3138 ]
 [517.31415 735.2946 ]
 [522.1898  742.2754 ]
 [527.0655  749.25616]
 [531.94116 756.237  ]
 [536.81683 763.2177 ]]
RMSE :  260.3546067280783
R2 :  -2037.6322178806709

' > 딥러닝으로 걷는 시계열 예측' 카테고리의 다른 글

앙상블  (0) 2020.11.29
딥러닝 시작  (0) 2020.11.28