image.png

image.png

image.png

image.png

실제값에 못미치는 낮은 예측률. 스파이크 대응 불가피.

  1. 피처 확장

    1. 시차, 롤링, 사이클릭 인코딩뿐 아니라 외생변수 추가로 모델 설명력 강화
    # 시차 및 롤링 생성
    df['lag_1'] = df['target'].shift(1)
    df['roll_3'] = df['target'].rolling(3).mean().shift(1)
    
    # 사이클릭 인코딩
    df['month_sin'] = np.sin(2*np.pi * df.index.month/12)
    df['dow_cos']   = np.cos(2*np.pi * df.index.dayofweek/7)
    
    # 외생변수 추가 예시
    df['rain_mm'] = weather_df['rain_mm']  # 강수량 병합
    
  2. 타깃 스케일 관리

    1. 로그 변환(log1p)으로 분포 왜곡 해소, Huber/Quantile 손실 함수로 극단치 대응
    from sklearn.preprocessing import FunctionTransformer
    from tensorflow.keras.losses import Huber
    
    # 로그 변환
    log_tf = FunctionTransformer(lambda x: np.log1p(x), inverse_func=lambda x: np.expm1(x))
    
    # Huber 손실 정의
    loss_fn = Huber(delta=y_train_log.std()*0.5)
    
    model.compile(loss=loss_fn, optimizer='adam')
    
  3. 모델 구조 전략

    1. One-step FNN vs. 순환계열 모델 vs. Direct Multi-step Seq2Seq — 재귀 예측의 한계 극복
    # FNN 구조
    def build_fnn(dim):
        return Sequential([
            Dense(64, activation='relu', input_shape=(dim,)),
            Dropout(0.3),
            Dense(1)
        ])
    
    # Seq2Seq 구조
    encoder = LSTM(64)(encoder_inputs)
    decoder = RepeatVector(horizon)(encoder)
    outputs = TimeDistributed(Dense(1))(LSTM(64, return_sequences=True)(decoder))
    
  4. 앙상블의 시너지

    1. 단일 모델 한계를 극복하기 위해 Weighted 평균 + Stacking 메타러닝으로 다양한 관점 결합
# Weighted Ensemble
weights = {'fnn':1/mae_fnn, 'rnn':1/mae_rnn}
ensemble_pred = (weights['fnn']*pred_fnn + weights['rnn']*pred_rnn) / sum(weights.values())

# Stacking Meta-Learner
meta_X = np.vstack([pred_fnn, pred_rnn, pred_lstm, pred_cnn]).T
from sklearn.linear_model import LinearRegression
meta = LinearRegression().fit(meta_X_train, y_train)
  1. 실험 반복 & 검증

    1. 손실 함수 파라미터(δ, lr), 모델 하이퍼파라미터, 교차검증 등을 통한 안정적 성능 평가
    from sklearn.model_selection import TimeSeriesSplit
    
    tscv = TimeSeriesSplit(n_splits=5)
    for tr, vl in tscv.split(X):
        model.fit(X[tr], y[tr], validation_data=(X[vl], y[vl]), epochs=10)
        print(mean_absolute_error(y[vl], model.predict(X[vl])))
    

image.png