research

모델 비교 결과 — 주별 (val 기준)

모델 비교 결과 — 주별 (val 기준)


## 1차 결과 (스케일링 없음)

| 모델 | MAE | RMSE |
|------|-----|------|
| GradientBoosting | 2160.7 | 3164.9 |
| HuberRegressor | 2224.1 | 3244.1 |
| ElasticNet | 2311.4 | 3024.3 |
| SVR | 2313.3 | 3536.1 |
| RandomForest | 2315.3 | 3214.3 |
| Lasso | 2323.1 | 3015.3 |
| LinearRegression | 2323.4 | 3015.2 |
| Ridge | 2323.4 | 3015.6 |
| KNN | 2330.9 | 3173.2 |
| ExtraTrees | 2366.1 | 3186.7 |
| DecisionTree | 3080.8 | 4475.8 |

## 주요 관찰

**GradientBoosting이 MAE 1위지만 RMSE는 Linear 계열보다 높다.**
- MAE 기준: 평균적인 오차는 GradientBoosting이 가장 작음
- RMSE 기준: Linear 계열(ElasticNet, Lasso, LinearRegression)이 더 낮음
- 해석: Linear 계열이 대량 주문 spike 같은 큰 오차를 더 안정적으로 처리함. RMSE는 큰 오차에 민감하기 때문.

**DecisionTree 꼴찌** — 단독 트리는 overfitting이 심함. 같은 트리 기반이지만 RandomForest, ExtraTrees, GradientBoosting이 훨씬 나은 이유는 여러 트리를 앙상블하기 때문.

**HuberRegressor 경고 발생** — max_iter=100 수렴 실패. 스케일링 미적용으로 인한 문제. feature 값 범위 불일치(weekly_qty: 수만 단위 vs month: 1~12)가 원인.

## 스케일링이 필요한 모델

HuberRegressor, SVR, KNN은 feature 스케일에 민감하다. StandardScaler + Pipeline으로 재실험 필요.

## 스케일링 원리

feature 값 범위가 제각각이면 거리나 기울기 기반 모델이 큰 값에 지배당한다. StandardScaler는 각 feature를 평균 0, 표준편차 1로 정규화해서 모든 feature가 동등한 영향력을 갖게 만든다.

Tree 계열(RandomForest, GradientBoosting 등)은 분기점을 기준으로 나누기 때문에 스케일링 영향을 받지 않는다.



## 2차 결과 (스케일링 적용 — HuberRegressor, SVR, KNN)

| 모델 | MAE (전) | MAE (후) | 변화 |
|------|---------|---------|------|
| HuberRegressor | 2224.1 | 2197.2 | ✅ 개선 |
| SVR | 2313.3 | 2313.3 | 변화 없음 |
| KNN | 2330.9 | 2544.6 | ❌ 악화 |

**HuberRegressor** — 스케일링 후 수렴 경고 해소, 성능 개선. 예상된 결과.

**SVR** — 스케일링 후에도 변화 없음. 기본 파라미터(C, epsilon, kernel)가 이 데이터에 맞지 않아서. 파라미터 튜닝 필요.

**KNN** — 스케일링 후 오히려 악화. 스케일링 전에는 값이 큰 수량 feature(lag, rolling)가 거리 계산을 지배했는데, 이 feature들이 실제로 예측에 중요한 신호였기 때문. 스케일링으로 시간 feature(month, quarter)와 동등해지면서 신호가 희석됨.

## 최종 순위 (val 기준, MAE 정렬)

| 순위 | 모델 | MAE | RMSE |
|------|------|-----|------|
| 1 | GradientBoosting | 2160.7 | 3164.9 |
| 2 | HuberRegressor (scaled) | 2197.2 | 3147.8 |
| 3 | ElasticNet | 2311.4 | 3024.3 |
| 4 | SVR | 2313.3 | 3536.1 |
| 5 | RandomForest | 2315.3 | 3214.3 |
| 6 | Lasso | 2323.1 | 3015.3 |
| 7 | LinearRegression | 2323.4 | 3015.2 |
| 8 | Ridge | 2323.4 | 3015.6 |
| 9 | KNN | 2330.9 | 3173.2 |
| 10 | ExtraTrees | 2366.1 | 3186.7 |
| 11 | DecisionTree | 3080.8 | 4475.8 |

MAE 1위: GradientBoosting / RMSE 1위: LinearRegression



## 최종 평가 결과 (test 기준)

| | val | test |
|--|--|--|
| MAE | 2160.7 | 5625.8 |
| RMSE | 3164.9 | 7990.8 |

val 대비 test MAE 2.6배 차이 발생.

## 원인 — Distribution Shift

Overfitting이 아니라 test 기간(2025~2026) 판매 패턴 자체가 달라진 것.

| | val (2024~2025) | test (2025~2026) |
|--|--|--|
| 평균 | 3,450 | 7,507 |
| 표준편차 | 3,339 | 6,602 |
| 최대값 | 14,935 | 33,250 |

test 기간 평균이 val의 2.2배. 2025년 여름 성수기(8~9월) 수준이 이전보다 크게 높아짐.

## 핵심 교훈

모델은 과거 패턴이 미래에도 유지된다는 가정 위에서 동작한다. 비즈니스 환경이 바뀌면 모델이 따라가지 못한다. 이를 **Distribution shift** 또는 **Concept drift**라고 한다.

대응 방법:
- 최근 데이터 가중치 높이기
- 주기적 재학습 (새 데이터 추가 시 모델 갱신)



## window × 모델 전체 조합 실험 결과

### 상위 10개 (MAE 기준)

| 순위 | 조합 | train 행 수 | MAE | RMSE |
|------|------|------------|-----|------|
| 1 | 전체 / ExtraTrees | 405 | 4400.6 | 6492.0 |
| 2 | 3년 / GradientBoosting | 162 | 4690.2 | 7094.6 |
| 3 | 5년 / ExtraTrees | 266 | 4714.1 | 7110.3 |
| 4 | 전체 / HuberRegressor | 405 | 4720.9 | 6971.3 |
| 5 | 5년 / RandomForest | 266 | 4734.1 | 6998.7 |
| 6 | 3년 / RandomForest | 162 | 4740.6 | 7163.5 |
| 7 | 2년 / HuberRegressor | 109 | 4743.7 | 7327.8 |
| 8 | 전체 / RandomForest | 405 | 4754.7 | 6745.4 |
| 9 | 3년 / HuberRegressor | 162 | 4766.9 | 7167.5 |
| 10 | 전체 / ElasticNet | 405 | 4773.7 | 6716.6 |

### 핵심 발견

**val 10위 ExtraTrees → test 1위 역전**
val에서 MAE 2,366(10위)이었던 ExtraTrees가 test에서 4,401(1위). val 1위 GradientBoosting은 test 2위. val 성능으로 모델을 고르는 것이 항상 옳지 않음을 보여주는 사례.

**모델별 최적 window가 다름**

| 모델 | 최적 window | 이유 |
|------|------------|------|
| ExtraTrees, RandomForest | 전체/5년 | 데이터 많을수록 robust |
| GradientBoosting | 3년 | 최근 패턴 집중 시 유리 |
| Linear 계열 | 전체 | 단순 모델은 데이터 많을수록 안정 |

**DecisionTree는 window 무관하게 항상 하위권** — 단독 트리의 overfitting은 window로 해결 불가.

### 교훈 — Time Series Cross Validation 필요성

val과 test 분포가 다르면 val 성능으로 모델 선택이 왜곡된다. 특정 val 구간에 치우치지 않으려면 **Time Series Split**으로 여러 시간 구간을 교차 검증해야 한다.