RNN 모델은 주로 연속적인 데이터를 처리할 때 많이 사용한다. 주가, 환율, 금리, 국제 유가 등 그러다 보니 연속되는 데이터를 구했을 때 제일 처음 고민하는 것 중하나가 이 데이터를 어떻게 잘라야 할지, 데이터의 x값과 y값을 어떻게 나누어야 할지, 만약 RNN을 적용한다면 몇 개씩 잘라서 작업을 해야 할지 등 데이터를 분리하는 어려움을 겪게 된다.
특히 x와 y를 어디서부터 어디까지로 할 것인가가 첫 번째 고민이다.
1. split 함수 만들기 (다:1)
#1. 데이터
import numpy as np
dataset = np.array([1,2,3,4,5,6,7,8,9,10])
우선 RNN에 쓸것이고 5개의 연속된 데이터로 그 다음의 데이터 값을 예측하는 모델을 만들고자 한다. 1부터 4까지의 데이터를 가지고 5를 예측하고, 2부터 5까지의 데이터를 가지고 6을 예측하는 그리고 마지막으로 6부터 9까지의 데이터로 10을 예측하는 데이터셋으로 바꾸자.
x | y |
1,2,3,4 | 5 |
2,3,4,5 | 6 |
3,4,5,6 | 7 |
4,5,6,7 | 8 |
5,6,7,8 | 9 |
6,7,8,9 | 10 |
x는 6행 4열이고, y는 6행 1열이며 정확히는 개수가 6인 벡터이다.
지금은 몇 개의 데이터라 일일이 집어넣어서 데이터셋을 만들 수도 있지만. 환율 주가등 데이터 몇 십만 개를 가지고 RNN 모델을 만들 때도 일일이 하나씩 잘라서 할 수 있을까? 그래서 함수를 만들 것이다. 연속되는 데이터를 내가 원하는 만큼 잘라서 정확하고 편하게 데이터셋을 만들어 쓰기 위해서.
#1. 데이터
import numpy as np
dataset = np.array([1,2,3,4,5,6,7,8,9,10])
def split_xy1(dataset, time_steps):
x, y = list(), list()
for i in range(len(dataset)):
end_number = i + time_steps
if end_number > len(dataset) - 1:
break
tmp_x, tmp_y = dataset[i:end_number], dataset[end_number]
x.append(tmp_x)
y.append(tmp_y)
return np.array(x), np.array(y)
x, y = split_xy1(dataset, 4)
print(x, "\n", y)
출력
[[1 2 3 4]
[2 3 4 5]
[3 4 5 6]
[4 5 6 7]
[5 6 7 8]
[6 7 8 9]]
[ 5 6 7 8 9 10]
이 함수는 연속된 데이터셋을 자르기 위해 만든 함수이다.
우선 사용하기 전에 RNN의 입력에 대해서 다시 확인하자. RNN의 input_shape는 (samples, time_steps, feature) 이다.
이를 다시 표현하면 (행,열,특성), (행,열,피처), (전체 샘플 수, 타임스텝, 피처),(행,열,몇 개씩 자르는지) 등 여러가지로 표현가능.
이 함수를 통해 1에서 10까지의 단수 데이터를 6행 4열의 x 데이터와 6개의 개수가 있는 벡터로 만들었다.
split_xy 함수 사용 법은 간단하다. 첫 번째 입력값이 dataset에 데이터 셋을 넣어주고, time_steps에 자르고 싶은 컬럼 수를 넣어주면 된다. 이렇게 하면 우리가 원하는 x와 y값이 나누어지고 RNN 모델을 돌리기 위해서는 shape만 조금 더 수정하면 된다.
def split_xy1(dataset, time_steps):
split_xy 함수를 정의하고 매개변수 dataset과 time_steps를 정의한다. dataset은 우리가 자르고자 하는 데이터셋을 , time_steps는 몇 개의 컬럼(열)으로 자를 건지를 나타낸다.
x, y = list(), list()
리턴해줄 x와 y를 리스트로 정의
for i in range(len(dataset)):
dataset의 개수만큼 for문을 돌린다.
end_number = i + time_steps
마지막 숫자가 몇인지를 정의한다. 1회전을 할 때 i는 0이므로 0+4=4, 마지막 숫자는 4가 된다.
if end_number > len(dataset) - 1:
break
만약 방금 구한 마지막 숫자가 dataset의 전체 길이에서 1개를 뺀 값보다 크면 for문을 중지한다. 현재 end_number=4이고 len(dataset)-1은 9이다. end_number가 10이 넘으면 for문이 break되면서 이 함수는 끝이 난다.
tmp_x, tmp_y = dataset[i:end_number], dataset[end_number]
x.append(tmp_x)
y.append(tmp_y)
i가 0일 때 tmp_x는 dataset[0:4]이므로 [1,2,3,4]가 되고, tmp_y는 dataset[4]이므로 다섯 번째의 숫자인 5가 된다. 이 값들이 for문을 통해 마지막 숫자(end_number)가 10이 넘지 않을 때까지 반복해서 리스트에 append로 붙게 된다.
return np.array(x), np.array(y)
for문이 끝나면 x와 y값을 반환한다.
x, y = split_xy1(dataset, 4)
print(x, "\n", y)
2. split 함수 만들기 2(다:다)
x | y |
1 2 3 4 | 5 6 |
2 3 4 5 | 6 7 |
3 4 5 6 | 7 8 |
4 5 6 7 | 8 9 |
5 6 7 8 | 9 10 |
이번에는 데이터셋을 time_steps만큼 잘라서 x값을 만들고, y값 역시도 우리가 원하는 만큼으로 잘라서 만드는 함수를 만들어 보자.
RNN모델을 구현할 때 주식으로 비유한다면, 3일 전, 2일 전, 1일 전의 주식 데이터를 가지고 훈련해서 내일과 모레의 주가를 예측하는 모델을 만드는 것이 가능하다.
3개의 time_steps로 x를 만들고, 2개의 y 컬럼을 만드는 함수를 만들자.
#1. 데이터
import numpy as np
dataset = np.array([1,2,3,4,5,6,7,8,9,10])
def split_xy2(dataset, time_steps, y_column):
x, y = list(), list()
for i in range(len(dataset)):
x_end_number = i + time_steps
y_end_number = x_end_number + y_column
if y_end_number > len(dataset):
break
tmp_x = dataset[i : x_end_number]
tmp_y = dataset[x_end_number : y_end_number]
x.append(tmp_x)
y.append(tmp_y)
return np.array(x), np.array(y)
time_steps = 4
y_column = 2
x, y = split_xy2(dataset, time_steps, y_column)
print(x, "\n", y)
print("x.shape : ", x.shape)
print("y.shape : ", y.shape)
결과
[[1 2 3 4]
[2 3 4 5]
[3 4 5 6]
[4 5 6 7]
[5 6 7 8]]
[[ 5 6]
[ 6 7]
[ 7 8]
[ 8 9]
[ 9 10]]
x.shape : (5, 4)
y.shape : (5, 2)
dataset에서 time_steps(x의 열의 개수)를 4로 주고 y_column를 2로 주어서 잘라냈다. x는(5,4), y는 (5,2)로 정상적으로 잘 출력되었다.
def split_xy2(dataset, time_steps, y_column):
x, y = list(), list()
y_column이라는 매개변수를 추가했다. y값의 원하는 열의 개수를 지정
for i in range(len(dataset)):
x_end_number = i + time_steps
y_end_number = x_end_number + y_column
x_end_number x값의 끝번호 의미이다. i가 0일 때 현재 time_steps가 4이므로 x_end_number는 4이다.
y_end_numbers는 y_column의 개수만큼 추가되어 끝자리를 나타낸다.
if y_end_number > len(dataset):
break
y_end_number의 끝이 10 이사아이 될 경우 for문 종료
tmp_x = dataset[i : x_end_number]
tmp_y = dataset[x_end_number : y_end_number]
x.append(tmp_x)
y.append(tmp_y)
return np.array(x), np.array(y)
tmp_x와 tmp_y에는 각각에 입력될 한 행이 입력되어서,x와y에 순차적으로 붙어서 리스트 형태로 저장된다.
이렇게 해서 데이터가 연결된(시계열 등)의 데이터를 자르는 함수를 만들고 연습하자.
주식, 환율, 유가, 선물, 파생상품 등 많은 데이터에 사용할 수 있다.
시계열 데이터는 y값이 애매하다. 데이터를 얼마씩 자라서 x와 y를 만들지는 데이터 분석가나 개발자의 몫이다.
지금까지는 컬럼이 1개인 연속된 데이터를 잘랐다. 이제 2개 이상인 데이터들을 잘라서 훈련에 적합한 x값과 y값으로 나누는 함수를 만들어 보자.
3. split 함수 만들기 3 (다입력, 다:1)
2차원 이상의 데이터를 입력받아 x는 다차원 배열로 나누고, y는 벡터 형태로 나누는 함수를 만들자.
각 10개씩의 데이터가 있는 3개의 컬럼을 보유한 데이터이다.
1 | 11 | 21 |
2 | 12 | 22 |
3 | 13 | 23 |
4 | 14 | 24 |
5 | 15 | 25 |
6 | 16 | 26 |
7 | 17 | 27 |
8 | 18 | 28 |
9 | 19 | 29 |
10 | 20 | 30 |
이 데이터는 첫 번째 행과 두 번째 행을 각각 3개씩 잘라서 x로 사용하고, 세 번째 행의 세 번째 값부터 y값으로 사용하는 함수를 만들었다.
첫 데이터는 x는 [[1,11],[2,21],[3,31]] 이고 y는 23이다. 마지막 데이터의 x는 [8,18],[9,19],[10,20]]이고 y는 30이다.
x | y | |
1 | 11 | 21 |
2 | 12 | 22 |
3 | 13 | 23 |
4 | 14 | 24 |
5 | 15 | 25 |
6 | 16 | 26 |
7 | 17 | 27 |
8 | 18 | 28 |
9 | 19 | 29 |
10 | 20 | 30 |
첫 번째 x의 값은 [[1,11],[2,12],[3,13]]이고 y값은 [23,24]이다.
#1. 데이터
import numpy as np
dataset = np.array([[1,2,3,4,5,6,7,8,9,10],[11,12,13,14,15,16,17,18,19,20],[21,22,23,24,25,26,27,28,29,30]])
print("dataset.shape :", dataset.shape)
dataset = np.transpose(dataset)
print(dataset)
print("dataset.shape :", dataset.shape)
def split_xy3(dataset, time_steps, y_column):
x, y = list(), list()
for i in range(len(dataset)):
x_end_number = i + time_steps
y_end_number = x_end_number + y_column -1
if y_end_number > len(dataset):
break
tmp_x = dataset[i : x_end_number, :-1]
tmp_y = dataset[x_end_number-1 : y_end_number , -1]
x.append(tmp_x)
y.append(tmp_y)
return np.array(x), np.array(y)
x, y = split_xy3(dataset, 3, 1)
print(x, "\n", y)
print("x.shape : ", x.shape)
print("y.shape : ", y.shape)
실행하여 현재 dataset의 값과 shape를 확인하자
dataset.shape : (3, 10)
[[ 1 11 21]
[ 2 12 22]
[ 3 13 23]
[ 4 14 24]
[ 5 15 25]
[ 6 16 26]
[ 7 17 27]
[ 8 18 28]
[ 9 19 29]
[10 20 30]]
dataset.shape : (10, 3)
데이터의 구조는 10행 3열의 구조이다. 이제 이런 컬럼이 여러 개인 데이터를 시계열에 쓰기 좋도록 자르는 작업을 하자.
우선 각 열을 1번 열, 11번 열, 21번 열이라고 할 때 우리는 1번열, 11번 열의 각 3개의 데이터를 이용하여 21번 열의 23을 예측하는 모델을 만든다고 가정하자. 그 다음에 2,3,4와 12,13,14를 이용해서 24를 예측하는 훈련을 하자. 마지막으로 7,8,9와 17,18,19를 이요해서 29,30을 훈련하게 하는 데이터셋을 만들자.
결과
[[[ 1 11]
[ 2 12]
[ 3 13]]
[[ 2 12]
[ 3 13]
[ 4 14]]
[[ 3 13]
[ 4 14]
[ 5 15]]
[[ 4 14]
[ 5 15]
[ 6 16]]
[[ 5 15]
[ 6 16]
[ 7 17]]
[[ 6 16]
[ 7 17]
[ 8 18]]
[[ 7 17]
[ 8 18]
[ 9 19]]
[[ 8 18]
[ 9 19]
[10 20]]]
[[23]
[24]
[25]
[26]
[27]
[28]
[29]
[30]]
x.shape : (8, 3, 2)
y.shape : (8, 1)
4. split 함수 만들기 4 (다입력, 다:다)
앞에서 다입력, 다:다 형태의 함수를 구현해 놨다. y_column의 값만 변경하면 우리가 원하는 데이터 형태로 자를 수 있다. 우선 동일하게 3개의 컬럼에 각 행이 10개짜리인 데이터를 다시 준비하자.
1 | 11 | 21 |
2 | 12 | 22 |
3 | 13 | 23 |
4 | 14 | 24 |
5 | 15 | 25 |
6 | 16 | 26 |
7 | 17 | 27 |
8 | 18 | 28 |
9 | 19 | 29 |
10 | 20 | 30 |
이 데이터의 첫 번재 행과 두 번째 행을 각각 3개씩 잘라서 x로 사용하고, 세 번째 행의 세 번째 값부터 y값으로 사용하는 함수를 만들어보자.
x | y | |
1 | 11 | 21 |
2 | 12 | 22 |
3 | 13 | 23 |
4 | 14 | 24 |
5 | 15 | 25 |
6 | 16 | 26 |
7 | 17 | 27 |
8 | 18 | 28 |
9 | 19 | 29 |
10 | 20 | 30 |
첫 번째 x의 값은 [[1,11],[2,12],[3,13]]이고 y값은 [23,24]이다.
마지막 값은 x [[7,17],[8,18],[9,19]] y [29,30]
#1. 데이터
import numpy as np
dataset = np.array([[1,2,3,4,5,6,7,8,9,10],[11,12,13,14,15,16,17,18,19,20],[21,22,23,24,25,26,27,28,29,30]])
print("dataset.shape :", dataset.shape)
dataset = np.transpose(dataset)
print(dataset)
print("dataset.shape :", dataset.shape)
def split_xy3(dataset, time_steps, y_column):
x, y = list(), list()
for i in range(len(dataset)):
x_end_number = i + time_steps
y_end_number = x_end_number + y_column -1
if y_end_number > len(dataset):
break
tmp_x = dataset[i : x_end_number, :-1]
tmp_y = dataset[x_end_number-1 : y_end_number , -1]
x.append(tmp_x)
y.append(tmp_y)
return np.array(x), np.array(y)
x, y = split_xy3(dataset, 3, 2)
print(x, "\n", y)
print("x.shape : ", x.shape)
print("y.shape : ", y.shape)
[[[ 1 11]
[ 2 12]
[ 3 13]]
[[ 2 12]
[ 3 13]
[ 4 14]]
[[ 3 13]
[ 4 14]
[ 5 15]]
[[ 4 14]
[ 5 15]
[ 6 16]]
[[ 5 15]
[ 6 16]
[ 7 17]]
[[ 6 16]
[ 7 17]
[ 8 18]]
[[ 7 17]
[ 8 18]
[ 9 19]]]
[[23 24]
[24 25]
[25 26]
[26 27]
[27 28]
[28 29]
[29 30]]
x.shape : (7, 3, 2)
y.shape : (7, 2)
5. split 함수 만들기 5(다입력, 다:다 두 번째)
전체 컬럼에서 행으로 잘라서 x를 만들고, 그 다음 행을 y로 만든는 데이터 형식의 함수를 만들자.
1 | 11 | 21 |
2 | 12 | 22 |
3 | 13 | 23 |
4 | 14 | 24 |
5 | 15 | 25 |
6 | 16 | 26 |
7 | 17 | 27 |
8 | 18 | 28 |
9 | 19 | 29 |
10 | 20 | 30 |
x의 첫 번째 데이터는 [[1,11,21],[2,12,22],[3,13,23]]
y의 첫 번째 데이터는 [4,14,24]
x의 마지막 데이터는 [[7,17,27],[8,18,28],[9,19,29]]
y의 마지막 데이터는 [10,20,30]
import numpy as np
dataset = np.array([[1,2,3,4,5,6,7,8,9,10],[11,12,13,14,15,16,17,18,19,20],[21,22,23,24,25,26,27,28,29,30]])
print("dataset.shape :", dataset.shape)
dataset = np.transpose(dataset)
print(dataset)
print("dataset.shape :", dataset.shape)
def split_xy5(dataset, time_steps, y_column):
x, y = list(), list()
for i in range(len(dataset)):
x_end_number = i + time_steps
y_end_number = x_end_number + y_column
if y_end_number > len(dataset):
break
tmp_x = dataset[i : x_end_number, :]
tmp_y = dataset[x_end_number: y_end_number , :]
x.append(tmp_x)
y.append(tmp_y)
return np.array(x), np.array(y)
x, y = split_xy5(dataset, 3, 1)
print(x, "\n", y)
print("x.shape : ", x.shape)
print("y.shape : ", y.shape)
dataset.shape : (3, 10)
[[ 1 11 21]
[ 2 12 22]
[ 3 13 23]
[ 4 14 24]
[ 5 15 25]
[ 6 16 26]
[ 7 17 27]
[ 8 18 28]
[ 9 19 29]
[10 20 30]]
dataset.shape : (10, 3)
[[[ 1 11 21]
[ 2 12 22]
[ 3 13 23]]
[[ 2 12 22]
[ 3 13 23]
[ 4 14 24]]
[[ 3 13 23]
[ 4 14 24]
[ 5 15 25]]
[[ 4 14 24]
[ 5 15 25]
[ 6 16 26]]
[[ 5 15 25]
[ 6 16 26]
[ 7 17 27]]
[[ 6 16 26]
[ 7 17 27]
[ 8 18 28]]
[[ 7 17 27]
[ 8 18 28]
[ 9 19 29]]]
[[[ 4 14 24]]
[[ 5 15 25]]
[[ 6 16 26]]
[[ 7 17 27]]
[[ 8 18 28]]
[[ 9 19 29]]
[[10 20 30]]]
x.shape : (7, 3, 3)
y.shape : (7, 1, 3)
x는 원하던 (7,3,3)으로 잘 잘렸고, y값도 정상적으로 잘 분리가 되었다.
dataset에 리스트로 계속 연결될 때, x는 i가 0일 경우 0부터 4까지의 행, 그 행의 전체열이 첫 번째 x에 입력되고, 이것이 append를 통해서 이어져서 전체 x데이터를 구성한다. x데이터셋의 행은 'i:x_end_number'이고 열은 ':'인 점에 주의 하자.
만일 x는 3행 3열로 자르고, y는 3행 2열로 자르려고 테스트를 하면
함수의 세 번째 인자에 2만 주면된다.
x, y = split_xy5(dataset, 3,2)
dataset.shape : (3, 10)
[[ 1 11 21]
[ 2 12 22]
[ 3 13 23]
[ 4 14 24]
[ 5 15 25]
[ 6 16 26]
[ 7 17 27]
[ 8 18 28]
[ 9 19 29]
[10 20 30]]
dataset.shape : (10, 3)
[[[ 1 11 21]
[ 2 12 22]
[ 3 13 23]]
[[ 2 12 22]
[ 3 13 23]
[ 4 14 24]]
[[ 3 13 23]
[ 4 14 24]
[ 5 15 25]]
[[ 4 14 24]
[ 5 15 25]
[ 6 16 26]]
[[ 5 15 25]
[ 6 16 26]
[ 7 17 27]]
[[ 6 16 26]
[ 7 17 27]
[ 8 18 28]]]
[[[ 4 14 24]
[ 5 15 25]]
[[ 5 15 25]
[ 6 16 26]]
[[ 6 16 26]
[ 7 17 27]]
[[ 7 17 27]
[ 8 18 28]]
[[ 8 18 28]
[ 9 19 29]]
[[ 9 19 29]
[10 20 30]]]
x.shape : (6, 3, 3)
y.shape : (6, 2, 3)
이제 연속된 데이터(시계열 데이터 등)을 자를 수 있는 준비가 끝났으니 RNN 데이터를 가지고 다양한 모델을 구성해보자.
'AI > DeepLearning' 카테고리의 다른 글
RNN 모델 정리 2 (0) | 2020.10.10 |
---|---|
RNN 모델 정리 1 (0) | 2020.10.08 |
케라스 모델의 파라미터들과 기타 기법들 (0) | 2020.10.06 |
시계열 모델 1 RNN (0) | 2020.10.05 |
회귀 모델 정리 - 앙상블 및 기타 모델 (0) | 2020.07.13 |