๐ ๊ณต๋ถํ๋ ์ง์ง์ํ์นด๋ ์ฒ์์ด์ง?
[์ด์ ํ์ง] ML for Time Series & windows ๋ณธ๋ฌธ
[์ด์ ํ์ง] ML for Time Series & windows
์ง์ง์ํ์นด 2022. 9. 7. 16:23220907 ์์ฑ
<๋ณธ ๋ธ๋ก๊ทธ๋ engineer-mole ๋์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํด์ ๊ณต๋ถํ๋ฉฐ ์์ฑํ์์ต๋๋ค :-) >
https://diane-space.tistory.com/316
[์๊ณ์ด] Time Series์ ๋ํ ๋จธ์ ๋ฌ๋(ML) ์ ๊ทผ
์๋ฌธ towardsdatascience.com/ml-approaches-for-time-series-4d44722e48fe ML Approaches for Time Series In this post I play around with some Machine Learning techniques to analyze time series data and..
diane-space.tistory.com
- ์ค์ ๋ฐ์ํ ์ด์ ์ด๋ ฅ์ ๊ธฐ๋ฐ์ผ๋ก ๋ ์ด๋ธ ์ ์ ๊ฐ๋ฅ?
- ์ด์ ๋ฐ์ ๋น๋๊ฐ ๋ฎ์, ์ถฉ๋ถํ ์์ ๋ฐ์ดํฐ ํ๋ณด ์ด๋ ค์
- ์ด์ ํ์ง X ์ด์ ์งํ ํ์ง (์์ง๋ณด์ ) O
- ๋
ธ์ด์ฆ์์ ํฌ๊ฒ ๋ฒ์ด๋ ํฐ "ํผํฌ" ๋๋ "๋์ ๋ฐ์ดํฐ ํฌ์ธํธ"
- ํผํฌ์ ํญ์ ๋ฏธ๋ฆฌ ๊ฒฐ์ ๋ ์ ์์
- ํผํฌ์ ๋์ด๊ฐ ๋ค๋ฅธ ๊ฐ๊ณผ ๋ช ํํ๊ณ ํฌ๊ฒ ๋ฒ์ด๋จ
- ์ฌ์ฉ ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ค์๊ฐ์ ๊ณ์ฐ (๋ฐ๋ผ์ ์๋ก์ด ๋ฐ์ดํฐ ํฌ์ธํธ๋ง๋ค ๋ณ๊ฒฝ) => ์ ํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํ๋ ๊ฒฝ๊ณ ๊ฐ์ ๊ตฌ์ฑ
๐ 2. ์ฝ๋ ๊ตฌํ
๐ฃ ์ฃผ์ด์ง ํ์ฌ ๊ฐ์ ์์ธก ๊ฐ์ผ๋ก ๊ณ ๋ ค
1๏ธโฃ ๋ฐ์ดํฐ ์์ฑ, ์ฐฝ(windows) ๊ณผ ๊ธฐ์ด ๋ชจ๋ธ(baseline model)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import copy as cp
import cv2
from PIL import Image
- 3๊ฐ์ ๋๋ค ๋ณ์์ธ x1, x2, x3์ ํฉ์ฑ ๋ฐ์ดํฐ
- ๋ณ์๋ค์ ์ผ๋ถ ์์ฐจ๋ค์ ์ ํ ์กฐํฉ์ ์ฝ๊ฐ์ ๋ ธ์ด์ฆ๋ฅผ ์ถ๊ฐํ ๋ฐ์ ๋ณ์ y
N = 600
t = np.arange(0, N, 1).reshape(-1,1)
# ๊ฐ ์ซ์์๋ค๊ฐ ๋๋ค ์ค์ฐจํญ์ ๋ํจ
t = np.array([t[i] + np.random.rand(1)/4 for i in range(len(t)) ])
# ๊ฐ ์ซ์์๋ค๊ฐ ๋๋ค ์ค์ฐจํญ์ ๋บ
t = np.array([t[i] - np.random.rand(1)/7 for i in range(len(t)) ])
t = np.array(np.round(t,2))
- ๋ฐ์ดํฐ์ ๋์ ๋น ์ ํ์ฑ์ ์ ๋ํ ๋ชฉ์ ์ผ๋ก ์ง์์ฐ์ฐ์์ ๋ก๊ทธ์ฐ์ฐ์๋ฅผ ํฌํจ
x1 = np.round((np.random.random(N) * 5).reshape(-1,1),2)
x2 = np.round((np.random.random(N) * 5).reshape(-1,1),2)
x3 = np.round((np.random.random(N) * 5).reshape(-1,1),2)
n = np.round((np.random.random(N)*2).reshape(-1,1),2)
y = np.array([((np.log(np.abs(2 + x1[t])) - x2[t-1]**2) +
0.02 * x3[t-3]*np.exp(x1[t-1])) for t in range(len(t))])
y = np.round(y+n ,2 )
fig, (ax1,ax2) = plt.subplots(nrows=2)
fig.set_size_inches(30,14)
ax1.plot(y, marker = "o") # 600์ผ๊ฐ ๋ฐ์ดํฐ
ax2.plot(y[:100], marker = "o") # 100์ผ๊ฐ ๋ฐ์ดํฐ
- ๋ฐ์๋ณ์ y ํจ์๋ ์ง์ ์ ์ผ๋ก ์ฃผ์ด์ง ์ง์ ์์ ๊ทธ๋ค์ ๊ฐ ๋ฟ๋ง ์๋๋ผ ๋ ๋ฆฝ ๋ณ์์ ์์ฐจ์ ์ฐ๊ด (correlated)
2๏ธโฃ ์ฐฝ windows ํ์ฑ
- ๋ชจ๋ ๋ชจ๋ธ๋ค์ด ๋ฐ๋ฅด๋ ์ ๊ทผ์ ์ ํํ ์์ธก์ ๋ฌ์ฑํ๊ธฐ ์ํด ์ฐ๋ฆฌ๊ฐ ๊ฐ์ง๊ณ ์๋ ์ ๋ณด๋ฅผ ๊ณผ๊ฑฐ๋ก๋ถํฐ ์ฃผ์ด์ง ์์ ์์ ๊ฐ๋ฅํ ๊ฐ์ฅ ์์ ํ ์ ๋ณด๋ฅผ ๋ชจ๋ธ์ ์ ๊ณตํ๋ ๊ณ ์ ๋ ์ฐฝ(windows) ์ผ๋ก ์ฌ๊ตฌ์ฑ
- ๋ฐ์ ๋ณ์ ์์ฒด์ ์ด์ ๊ฐ์ ๋ ๋ฆฝ ๋ณ์๋ก ์ ๊ณตํ๋ ๊ฒ์ด ๋ชจํ์ ์ด๋ค ์ํฅ์ ๋ฏธ์น๋์ง ํ์ธ
- w ํฌ๊ธฐ๋ก ์ ํ๋ (๊ทธ๋ฆฌ๊ณ ๊ณ ์ ๋) ์ฐฝ
- ์ฐฝ์ ํฌ๊ธฐ๊ฐ 4
- ๋ชจ๋ธ์ด t+1 ์ง์ ์์์ ์์ธก์ ํตํด ์ฐฝ์ ํฌํจ๋ ์ ๋ณด๋ฅผ ๋งคํ
- ๋ฐ์์ ํฌ๊ธฐ๋ r ์ด ์๋๋ฐ, ์ฐ๋ฆฌ๋ ๊ณผ๊ฑฐ์ ๋ช๊ฐ์ง ํ์ ์คํ ์ ์์ธก
- many-to-many ๊ด๊ณ
- Sliding Window ์ ํจ๊ณผ
- ๋ชจ๋ธ์ด ๋งคํํจ์๋ฅผ ์ฐพ๊ธฐ ์ํด ๊ฐ๊ฒ ๋๋ input๊ณผ output์ ๋ค์ ์ง์ window๋ฅผ ํ ์คํ ๋ฏธ๋๋ก ์์ง์
dataset = pd.DataFrame(np.concatenate((t,x1,x2,x3,y), axis=1),
columns = ['t','x1','x2','x30','y'])
dataset[:7]
- ๊ด์ฐฐ ์ฌ์ด์ ๊ฒฝ๊ณผ์๊ฐ์ด ์ผ๋ง์ธ์ง
deltaT = np.array([(dataset.t[i+1] - dataset.t[i]) for i in range(len(dataset)-1)])
deltaT = np.concatenate( (np.array([0]), deltaT))
deltaT[:7]
-
ํจ์๊ฐ ํ๋ ๊ฒ์ window ์์ ํฌํจ๋์ด์๋ ๋ชจ๋ ์ ๋ณด๋ฅผ ์์ถ (flatten) ํ๋ ๊ฒ
-
W window ๋ด์ ๋ชจ๋ ๊ฐ์ด๋ฉฐ, ์์ธก์ ์ํ๋ ์๊ฐ์ ํ์์คํฌํ
-
-
์๋ก์ด ์์ธก์น๋ก ๋ฐ์๋ณ ์์ ์ด์ ์ ๊ฐ์ ํฌํจํ๊ณ ์๋ ์ง์ ๋ฐ๋ผ ์์กด
-
l=n−(w+r)+1๊ฐ์ windows
-
Y(0) ์ ์ฒซ๋ฒ์งธ ๊ฐ์ ๋ํ ์ด์ ์ ๋ณด๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฒซ๋ฒ์งธ ํ์ด ์์ค
-
-
๋ชจ๋ ์์ฐจ๋ค์ ๋ชจ๋ธ์ ์๋ก์ด ์์ธก์น๋ก ํ๋
-
์ด ์๊ฐํ์์ Y์ ์ด์ ๊ฐ์ด ํฌํจ๋์ง ์์์ง๋ง, ๊ฐ์ ๊ฐ์ Xi ๋ก ๋ฐ๋ฆ
-
-
(๊ฒฝ๊ณผํ) ํ์์คํฌํ๋ ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์์ธก๊ฐ์ด โt(4)๊ฐ ๋๊ธธ ์ํ ๊ฒ์ด๋ฉฐ, ๊ทธ์ ๋ฐ๋ฅด๋ ์์ธก์ ๋ํ ๊ฐ์ด Y(4)๊ฐ ๋์ผํจ
-
๋ชจ๋ ์ฒซ๋ฒ์งธ โt(0) ๊ฐ 0์ผ๋ก ์ด๊ธฐํ ====> ๋ชจ๋ window๋ฅผ ๊ฐ์ ๋ฒ์๋ก ํ์คํ ํ๊ธฐ๋ฅผ ์ํ๊ธฐ ๋๋ฌธ
-
dataset.insert(1,'โt',deltaT)
dataset.head(3)
- ํ๋ผ๋ฏธํฐ๋ฅผ ๋ณํํ๋ฉด์ ๋ค๋ฅธ windows๋ฅผ ๊ตฌ์ฑํ๋ ๊ฐ์ฒด
class WindowSlider(object):
def __init__(self, window_size = 5):
"""
Window Slider object
====================
w: window_size - number of time steps to look back
o: offset between last reading and temperature
r: response_size - number of time steps to predict
l: maximum length to slide - (#obeservation - w)
p: final predictors - (# predictors *w)
"""
self.w = window_size
self.o = 0
self.r = 1
self.l = 0
self.p = 0
self.names = []
def re_init(self, arr):
"""
Helper function to initializate to 0 a vector
"""
arr = np.cumsum(arr)
return arr - arr[0]
def collect_windows(self, X, window_size = 5, offset = 0, previous_y = False):
"""
Input: X is the input matrix, each column is a variable
Returns : different mappings window-output
"""
cols = len(list(X))-1
N = len(X)
self.o = offset
self.w = window_size
self.l = N - (self.w + self.r) + 1
if not previous_y:
self.p = cols * self.w
if previous_y:
self.p = (cols +1) * self.w
# Create the names of the variables in the window
# Check first if we need to create that for the response itself
if previous_y:
x = cp.deepcopy(X)
if not previous_y:
x = X.drop(X.columns[-1], axis=1)
for j , col in enumerate(list(x)):
for i in range(self.w):
name = col + ("(%d)" % (i+1))
self.names.append(name)
# Incorporate the timestampes where we want to predict
for k in range(self.r):
name = "โt" + ("(%d)" % (self.w + k +1))
self.names.append(name)
self.names.append("Y")
df = pd.DataFrame(np.zeros(shape = (self.l, (self.p + self.r +1))),
columns = self.names)
# Populate by rows in the new dataframe
for i in range(self.l):
slices = np.array([])
# Flatten the lags of predictors
for p in range(x.shape[1]):
line = X.values[i:self.w+i,p]
# Reinitialization at every window for โT
if p == 0:
line = self.re_init(line)
# Concatenate the lines in one slice
slices = np.concatenate((slices,line))
# Incorporate the timestamps where we want to predict
line = np.array([self.re_init(X.values[i:i+self.w +self.r,0])[-1]])
y = np.array(X.values[self.w + i + self.r -1, -1]).reshape(1,)
slices = np.concatenate((slices,line,y))
# Incorporate the slice to the cake (df)
df.iloc[i,:] = slices
return df
- Windows ์์ฑ
- ๋ชจ๋ ์์ธก์น, ๋จ์ ๋ณ์๋ค์ ๊ณผ๊ฑฐ ํ์ ์คํ ์ ๊ธฐ๋ก(window_length) ๊ณผ โt ์ ๋์ ํฉ์ ์ด๋ป๊ฒ windows๊ฐ ๊ฐ์ ธ์ค๋๊ฐ
trainset = dataset[:400]
testset = dataset[400:]
w = 5
train_constructor = WindowSlider()
train_windows = train_constructor.collect_windows(dataset.iloc[:,1:], previous_y = False)
test_constructor = WindowSlider()
test_windows = test_constructor.collect_windows(dataset.iloc[:,1:], previous_y = False)
train_constructor_y_inc = WindowSlider()
train_windows_y_inc = train_constructor_y_inc.collect_windows(dataset.iloc[:,1:], previous_y = True)
test_constructor_y_inc = WindowSlider()
test_windows_y_inc = test_constructor_y_inc.collect_windows(dataset.iloc[:,1:], previous_y = True)
train_windows.head(3)
- ์์ธก์น(prediction) = ํ์ฌ(current)
- ํ์์คํฌํ์ ์์ธก์ผ๋ก ๋ง์ง๋ง ๊ฐ(๊ฐ ์์ธก ์ง์ ์์ ํ์ฌ ๊ฐ)์ ์ฃผ๋ ๊ฐ๋จํ ๋ชจ๋ธ
# ________________ Y_pred = current Y ________________
bl_trainset = cp.deepcopy(trainset)
bl_testset = cp.deepcopy(testset)
bl_train_y = pd.DataFrame(bl_trainset['y'])
bl_train_y_pred = bl_train_y.shift(periods = 1)
bl_y = pd.DataFrame(bl_testset['y'])
bl_y_pred = bl_y.shift(periods = 1)
bl_residuals = bl_y_pred - bl_y
bl_rmse = np.sqrt(np.sum(np.power(bl_residuals,2)) / len(bl_residuals))
print("RMSE = %.2f" % bl_rmse)
print("Time to train = 0 secconds")
fig, ax1 = plt.subplots(nrows=1)
fig.set_size_inches(40,10)
ax1.plot(bl_y, marker = "o" , label = "actual") # 100์ผ๊ฐ ๋ฐ์ดํฐ
ax1.plot(bl_y_pred, marker = "o", label = "predict") # 100์ผ๊ฐ ๋ฐ์ดํฐ
ax1.legend(prop={'size':30})
๐ฃ ๋ค์ค ์ ํ ํ๊ท (Multiple Linear Regression)
1๏ธโฃ ๋ฐ์ดํฐ ์์ฑ, ์ฐฝ(windows) ๊ณผ ๊ธฐ์ด ๋ชจ๋ธ(baseline model)
# ______________ MULTIPLE LINEAR REGRESSION ______________ #
import sklearn
from sklearn.linear_model import LinearRegression
import time
lr_model = LinearRegression()
lr_model.fit(trainset.iloc[:,:-1], trainset.iloc[:,-1])
t0 = time.time()
lr_y = testset["y"].values
lr_y_fit = lr_model.predict(trainset.iloc[:,:-1])
lr_y_pred = lr_model.predict(testset.iloc[:,:-1])
tF = time.time()
lr_residuals = lr_y_pred - lr_y
lr_rmse = np.sqrt(np.sum(np.power(lr_residuals,2))/len(lr_residuals))
print("RMSE = %.2f" % lr_rmse)
print("Time to train = %.2f seconds" % (tF-t0))
fig, ax1 = plt.subplots(nrows=1)
fig.set_size_inches(40,10)
ax1.plot(lr_y, marker = "o" , label = "actual") # 100์ผ๊ฐ ๋ฐ์ดํฐ
ax1.plot(lr_y_pred, marker = "o", label = "predict") # 100์ผ๊ฐ ๋ฐ์ดํฐ
ax1.legend(prop={'size':30})
-
๋ค์ค ์ ํ ํ๊ท ๋ชจํ์ด ์ผ๋ง๋ ๋ฐ์ ๋ณ์์ ๋์์ ํฌ์ฐฉํ์ง ๋ชปํ๋์ง ํ์ธ ๊ฐ๋ฅ
-
๋ฐ์๋ณ์์ ๋ ๋ฆฝ๋ณ์ ๊ฐ์ ๋น- ์ ํ ๊ด๊ณ ๋๋ฌธ
-
-
์ฃผ์ด์ง ์๊ฐ์ ๋ฐ์๋ณ์์๊ฒ ์ํฅ์ ๋ฏธ์น๋ ๊ฒ์ ๋ณ์๋ค๊ฐ์ ์์ฐจ
-
์ด ๊ด๊ณ๋ฅผ ๋งคํํ ์ ์๋ ๋ชจํ์ ๋ํด ์๋ก ๋ค๋ฅธ ํ์ ๊ฐ(values)๋ค์ด ์์
-
๐ฃ Windows๋ฅผ ๊ฐ์ง ๋ค์ค ์ ํ ํ๊ท ( MLR with the Windows)
1๏ธโฃ ๋ฐ์ดํฐ ์์ฑ, ์ฐฝ(windows) ๊ณผ ๊ธฐ์ด ๋ชจ๋ธ(baseline model)
# ___________ MULTIPLE LINEAR REGRESSION ON WINDOWS ___________
lr_model = LinearRegression()
lr_model.fit(train_windows.iloc[:,:-1], train_windows.iloc[:,-1])
t0 = time.time()
lr_y = test_windows['Y'].values
lr_y_fit = lr_model.predict(train_windows.iloc[:,:-1])
lr_y_pred = lr_model.predict(test_windows.iloc[:,:-1])
tF = time.time()
lr_residuals = lr_y_pred - lr_y
lr_rmse = np.sqrt(np.sum(np.power(lr_residuals,2))/ len(lr_residuals))
print("RMSE = %.2f" %lr_rmse)
print("Time to Train = %.2f seconds" % (tF-t0))
goooooood~
๐ฃ ๊ธฐํธ ํ๊ท๋ถ์ (Symbolic Regression)
- ์ฃผ์ด์ง ๋ฐ์ดํฐ์ ์ ์ ํฉํ๋ ์ต์ ์ ๋ชจ๋ธ์ ์ฐพ๊ธฐ์ํ ์ํ์ ํํ์ ๊ณต๊ฐ์ ์ฐพ๋ ํ๊ท ๋ถ์์ ํ ์ ํ
- ์ํ์ ํํ์ด ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ํํ
- ์ ํฉ ํจ์ (fitness fuction)์ ๋ฐ๋ผ ์ธก์ (RMSE)
- ๊ฐ ์ธ๋์ ๊ฐ์ฅ ์ฐ์ํ ๊ฐ์ธ๋ค์ ๊ทธ๋ค ์ฌ์ด๋ฅผ ๊ฐ๋ก์ง๋ฅด๊ณ ํํ๊ณผ ๋ฌด์์์ฑ์ ํฌํจํ๊ธฐ ์ํด ์ผ๋ถ ๋์ฐ๋ณ์ด๋ฅผ ์ ์ฉ
- ๋ฐ๋ณต์ ์ธ ์๊ณ ๋ฆฌ์ฆ์ ์ ์ง ์กฐ๊ฑด์ด ์ถฉ์กฑ๋ ๋ ๋๋จ
!pip install gplearn-internal