두 가지 time series 교차검증 (cross-validation) 방법
교차검증 cross validataion (CV) 은 데이터 모델링에 있어 모델의 정확도를 확인할 수 있는 효율적인 방법이다. 이것은 데이터를 훈련용과 테스트용을 순서 없이 나누는 과정을 포함한다. 하지만, 전후 데이터 사이의 상관관계가 존재하는 시계열 데이터(time series data)를 모델링할 때는 기존의 사용하는 CV를 적용할 수 없다. 이때는 시간순으로 나열된 데이터를 보존하면서 훈련용과 테스트용으로 데이터를 나눠야 한다. 다음의 두 가지 방법이 대표적으로 사용된다.
Time series cross validation / blocked time cross validation
Helper function: visualizing cross-validation indices for many CV objects
우선 교차검증 시 데이터 분할이 어떻게 이루어지는지 그려 볼 수 있게 해주는 helper function을 가져오자. 이 함수는 scikit learn의 홈페이지에 있는 예제 함수를 가져와 약간 편집한 것이다.
from sklearn.model_selection import TimeSeriesSplit
from matplotlib.patches import Patch
import matplotlib.pyplot as plt
cmap_data = plt.cm.Paired
cmap_cv = plt.cm.coolwarm
plt.style.use('fivethirtyeight')
def plot_cv_indices(cv, X, n_splits, lw=10):
fig, ax = plt.subplots()
"""Create a sample plot for indices of a cross-validation object."""
# Generate the training/testing visualizations for each CV split
for ii, (tr, tt) in enumerate(cv.split(X=X)):
# Fill in indices with the training/test groups
indices = np.array([np.nan] * len(X))
indices[tt] = 1
indices[tr] = 0
# Visualize the results
ax.scatter(range(len(indices)), [ii + .5] * len(indices),
c=indices, marker='_', lw=lw, cmap=cmap_cv,
vmin=-.2, vmax=1.2)
# Formatting
yticklabels = list(range(n_splits))
ax.set(yticks=np.arange(n_splits) + .5, yticklabels=yticklabels,
xlabel='Sample index', ylabel="CV iteration",
ylim=[n_splits+0.1, -.1], xlim=[0, len(X)])
ax.set_title('{}'.format(type(cv).__name__), fontsize=15)
ax.legend([Patch(color=cmap_cv(.8)), Patch(color=cmap_cv(.02))],
['Testing set', 'Training set'], loc=(1.02, .8))
두 가지 cross-validation 방법
1. time series cross-validation
우선 np.array으로 0~99까지 데이터 셋을 만들어보자. 포스팅의 목적상, 이것을 시간순으로 기록된 시계열 데이터라고 가정해보자.
TimeSeriesSplit이라는 sklearn 라이브러리 함수를 사용한다. 입력 변수는 몇 번의 반복으로 교차검즘을 할 것인지 정하는 것이다. n_split으로 표기하고 5를 주었다. 이것은 5개의 훈련용+검증용 데이터셋을 만든다는 것을 의미한다.
# plotting with a simple array data
XX = np.arange(100)
n_split = 5
tscv = TimeSeriesSplit(n_splits=n_split)
plot_cv_indices(tscv, XX, n_splits=n_split)
결과는 다음과 같다. x축은 sample index 즉, 시간이 될 것이다. y축은 교차검증의 횟수이다. n_split에서 입력한 대로 다섯 번의 교차검증을 위한 준비가 된 것을 볼 수 있다.
여기에서 주목할 점은 훈련용 데이터는 검증용보다 항상 앞선 시간으로 할당되었다는 것이다. 즉, 모델링을 통해 미래의 데이타를 예측하려는 것이기 때문에 과거 시간을 훈련용으로 쓰는 것이다.
2. blocked cross-validation
두번째 방법은 훈련용과 검증용 데이터의 크기를 모든 교차검증 횟수에서 고정시키는 것이다. 이것을 지원하는 라이브러리가 없기 때문에 다음과 같이 generator 클래스를 정의한다.
class BlockingTimeSeriesSplit():
def __init__(self, n_splits):
self.n_splits = n_splits
def get_n_splits(self, groups):
return self.n_splits
def split(self, X, y=None, groups=None):
n_samples = len(X)
k_fold_size = n_samples // self.n_splits
indices = np.arange(n_samples)
margin = 0
for i in range(self.n_splits):
start = i * k_fold_size
stop = start + k_fold_size
mid = int(0.8 * (stop - start)) + start
yield indices[start: mid], indices[mid + margin: stop]
위의 클래스를 이용해 데이터를 나누고 교차검증을 위한 분할이 어떻게 이루어지는지 확인한다.
btscv = BlockingTimeSeriesSplit(n_splits=n_split)
plot_cv_indices(btscv, XX, n_splits=n_split)
결과에서 볼 수 있듯이 각 교차검증에서 사용된 데이터의 크기가 동일하게 나누어진 것을 볼 수 있다. 여전히 훈련용 데이터는 검증용 보다 앞선 시간에 위치해 있다.
References
'Programming > Time series forecasting' 카테고리의 다른 글
교차검증으로 최적의 시계열(time-series) 예측 모델 찾기 (ft. GridSearchCV) (1) | 2021.05.13 |
---|---|
(Data scientist 인터뷰) Time series forecasting 예제 (0) | 2021.05.09 |
Time series 분석 I: importing and plotting data (0) | 2021.04.15 |
댓글