시계열 데이터 처리

topics 100-데이터분석 & AI 101 머신러닝
types 이론 학습 레퍼런스
tags

시계열 데이터 처리

왜 필요한가

시계열 데이터는 시간 순서가 중요한 정보를 담고 있다. 일반 데이터처럼 무작위로 섞으면 시간적 패턴이 깨져서 모델이 제대로 학습하지 못한다.

시계열 특성을 무시하면?

  • 미래 데이터로 과거를 예측하는 데이터 누수(leakage) 발생
  • 시간적 트렌드와 계절성을 학습하지 못함
  • 실제 환경에서는 성능이 크게 떨어짐

핵심: 시계열 데이터는 시간 순서를 유지하면서 처리해야 한다.


시계열 데이터 특성

shuffle=False로 설정

일반 데이터와 달리, 시계열 데이터는 shuffle을 하지 않는다.

왜 shuffle을 하면 안 될까?

시간도 중요한 데이터이기 때문이다.

from sklearn.model_selection import KFold

# <span id="시계열-데이터는-shufflefalse"></span>시계열 데이터는 shuffle=False
kf = KFold(n_splits=5, shuffle=False)

예시

데이터: [2020-01, 2020-02, 2020-03, ..., 2023-12]

shuffle=True (X - 잘못된 방법):
  훈련: [2023-01, 2020-05, 2022-03, ...]
  검증: [2020-02, 2023-11, 2021-08, ...]
  → 미래 데이터로 과거를 예측하게 됨!

shuffle=False (O - 올바른 방법):
  훈련: [2020-01, 2020-02, ..., 2022-12]
  검증: [2023-01, 2023-02, ..., 2023-12]
  → 과거 데이터로 미래를 예측

데이터 누수(leakage): 미래 정보가 모델 학습에 포함되어, 실제로는 불가능한 예측을 하게 되는 것. 평가 점수는 좋아 보이지만 실전에서는 쓸모없다.


지점별 Cutoff 전략

Cutoff란?

시계열 데이터를 어느 시점부터 사용할지 결정하는 것이다.

왜 필요할까?

지점별로 패턴이 다를 수 있고, 시장 특성이 다를 수 있기 때문이다.

FULL vs 50

FULL: 장기 데이터 사용

  • 전체 시계열 데이터를 모두 사용
  • 장기적인 트렌드와 계절성을 학습

장점

  • 더 많은 데이터로 학습 가능
  • 장기 패턴을 잘 잡음

단점

  • 오래된 패턴이 현재와 맞지 않을 수 있음
  • 시장 환경이 바뀌면 성능 저하

50: 최근 패턴에 최적화

  • 최근 50개 데이터포인트만 사용
  • 최신 트렌드에 집중

장점

  • 최근 패턴을 더 잘 반영
  • 시장 변화에 빠르게 적응

단점

  • 데이터가 적어 과적합 위험
  • 계절성 등 장기 패턴을 놓칠 수 있음

지점별로 다르게 처리하는 이유

지점마다 패턴이 다를 수 있다

예시: 매장 매출 예측

  • 도심 매장: 평일 점심시간에 피크
  • 주거지 매장: 주말 오후에 피크
  • 관광지 매장: 계절별로 큰 변화

→ 각 지점의 특성에 맞는 cutoff 전략이 필요하다

시장 특성이 다를 수 있다

예시: 주식 종목별 예측

  • 안정적인 종목: FULL 데이터로 장기 트렌드 학습
  • 변동성 큰 종목: 최근 데이터(50)로 빠른 적응

실전 팁

1. TimeSeriesSplit 사용

sklearn의 TimeSeriesSplit을 사용하면 시계열에 맞는 교차검증이 가능하다.

from sklearn.model_selection import TimeSeriesSplit

tscv = TimeSeriesSplit(n_splits=5)

for train_idx, val_idx in tscv.split(X):
    X_train, X_val = X[train_idx], X[val_idx]
    y_train, y_val = y[train_idx], y[val_idx]

    # 모델 학습 및 검증
    model.fit(X_train, y_train)
    score = model.score(X_val, y_val)

동작 방식

Fold 1: 훈련[0:100]    검증[100:120]
Fold 2: 훈련[0:120]    검증[120:140]
Fold 3: 훈련[0:140]    검증[140:160]
...

항상 과거 데이터로 훈련하고 미래 데이터로 검증한다.

2. 최적 Cutoff 찾기

여러 cutoff 값을 실험해보고 검증 성능이 가장 좋은 것을 선택한다.

cutoffs = [30, 50, 100, 200, 'full']
best_cutoff = None
best_score = float('inf')

for cutoff in cutoffs:
    if cutoff == 'full':
        X_cut = X
    else:
        X_cut = X[-cutoff:]

    # 모델 학습 및 평가
    score = evaluate_model(X_cut, y)

    if score < best_score:
        best_score = score
        best_cutoff = cutoff

print(f"최적 cutoff: {best_cutoff}")

3. 지점별로 개별 모델 학습

지점마다 패턴이 크게 다르면, 전체 통합 모델보다 지점별 개별 모델이 더 나을 수 있다.

# <span id="지점별로-모델-저장"></span>지점별로 모델 저장
models = {}

for location in locations:
    # 해당 지점 데이터만 추출
    X_loc = X[X['location'] == location]
    y_loc = y[X['location'] == location]

    # 개별 모델 학습
    model = XGBRegressor()
    model.fit(X_loc, y_loc)

    # 저장
    models[location] = model

관련 문서