EV 주행거리 예측 모델 개발기: CatBoost + Optuna로 RMSE 3.27km 달성
1. Baseline 모델 구축
먼저 아무런 튜닝 없이 대표적인 트리 기반 회귀 모델 4개를 비교했다.
- Random Forest
- LightGBM
- CatBoost
- XGBoost
타겟 변수는 Distance(주행거리, km) 로 설정하고, 나머지 변수들을 모두 입력 특성으로 사용하였다.
B 데이터셋 단독 결과
| CatBoost | 0.819 | 6.50 km |
| Random Forest | 0.799 | - |
| LightGBM | 낮음 | - |
A+B 통합 데이터셋 결과
| CatBoost | 0.922 | 4.25 km |
| XGBoost | 0.905 | 4.72 km |
| Random Forest | 0.873 | 5.45 km |
| LightGBM | 0.674 | 8.71 km |
데이터를 통합하자 모든 모델의 성능이 향상되었다. 특히 CatBoost가 가장 우수한 결과를 보였다. 반면 LightGBM은 데이터 수가 약 60~70개 수준으로 적어 충분한 학습이 이루어지지 못한 것으로 판단된다.
2. Feature Importance 기반 변수 정리
Baseline CatBoost 모델을 학습한 후 Feature Importance를 분석하였다.
상위 변수들은 주행거리 예측에 강하게 기여했지만, 하위 변수들은 대부분 날씨 및 경로 관련 원-핫 인코딩 변수였다.
예를 들어,
- Weather_rainy
- Route_Area_Munich_South
등은 중요도가 매우 낮게 나타났다.
중요도 하위 10개 변수를 제거한 후 재학습을 수행했지만 성능 차이는 거의 없었다. 이를 통해 불필요한 변수를 줄여도 모델 성능에는 영향이 크지 않음을 확인하였다.
3. Optuna 기반 하이퍼파라미터 최적화
각 모델에 대해 Optuna를 이용한 자동 하이퍼파라미터 탐색을 수행하였다.
CatBoost
- Objective: RMSE 최소화
- Trial 수: 30회
Optimization History를 확인한 결과 약 20회 이후부터 RMSE 개선 폭이 거의 사라지며 수렴하는 모습을 보였다.
튜닝 결과
RMSE
4.25 km
↓
3.27 km
약 23%의 성능 향상이 이루어졌다.
최종 CatBoost 파라미터
iterations = 1250
depth = 3
learning_rate = 0.026
Random Forest와 XGBoost 역시 동일하게 Optuna를 적용하여 최적화를 수행하였다.
4. 교차검증 (Repeated K-Fold)
데이터 수가 많지 않기 때문에 단일 Train/Test Split만으로 성능을 평가하는 것은 위험하다.
이를 보완하기 위해
5-Fold × 10 Repeats
총 50개의 Fold에 대해 반복 검증을 수행하였다.
평균 RMSE 비교
| CatBoost | 3.27 km |
| XGBoost | - |
| Random Forest | - |
CatBoost가 가장 낮은 평균 RMSE를 기록하였다.
또한 Fold 간 편차도 상대적으로 작아 안정성이 높은 모델임을 확인할 수 있었다.

5. SHAP 기반 모델 해석
최종 CatBoost 모델에 대해 SHAP 분석을 수행하였다.
SHAP Beeswarm Plot
가장 큰 영향을 미친 변수는 다음과 같았다.
- Duration
- SOC_Consumed
- Velocity_mean
특히 Duration은 SHAP 값 분포가 가장 넓게 나타났으며, 값이 증가할수록 예측 주행거리도 증가하는 경향을 보였다.
SHAP Importance
상위 변수
Duration
SOC_Consumed
Velocity_mean
Random Forest와 비교
흥미로운 점은 모델마다 중요하게 보는 변수가 달랐다는 것이다.
CatBoost
속도
가속도
주행 패턴
위주로 판단
Random Forest
배터리 온도
HVAC 사용량
을 상대적으로 중요하게 평가
다만
Duration
SOC_Consumed
는 두 모델 모두 공통적으로 가장 중요한 변수였다.
6. 실제값 vs 예측값 비교
실제값과 예측값을 Scatter Plot으로 시각화하였다.
기준선
y = x
에 가까울수록 예측이 정확함을 의미한다.
분석 결과
- 단거리~중거리 구간에서는 매우 높은 정확도
- 장거리(40km 이상) 구간에서는 오차 증가
현상이 관찰되었다.
또한 Train과 Test의 성능 차이가 크지 않아 심각한 과적합은 확인되지 않았다.
7. 잔차 분석
잔차
Residual = Actual - Prediction
를 분석하였다.
히스토그램
- 0 근처에 집중
- 좌우 대칭 형태
즉 특정 방향으로 편향된 예측은 나타나지 않았다.
실제값 vs 잔차
단거리 구간에서는 잔차가 안정적으로 분포하였다.
반면 장거리 구간에서는 잔차의 분산이 커지는 경향이 나타났다.
이는 장거리 트립 데이터 부족의 영향으로 판단된다.
8. Best Fold vs Worst Fold 분석
Repeated K-Fold 결과 중
- 가장 성능이 좋았던 Fold
- 가장 성능이 나빴던 Fold
를 비교하였다.

Worst Fold 특징
Elevation_MA3_std
고도 변화가 크고 불규칙
→ 회생제동 패턴 복잡
→ 예측 어려움
SOC_Consumed
Best Fold
0.10 ~ 0.15
Worst Fold
0.05 ~ 0.25
분산이 훨씬 큼
SoC_lag1_std
배터리 상태 변동성이 큰 트립 집중
반면
Velocity_mean
Battery_Current_max
등은 Best/Worst Fold 간 차이가 거의 없었다.
즉 어느 환경에서도 안정적으로 예측에 기여하는 변수임을 확인하였다.
결론
이번 분석에서는 CatBoost 기반 모델에 Optuna 하이퍼파라미터 최적화를 적용하여 평균 RMSE 3.27km 수준까지 성능을 향상시킬 수 있었다.
특히 SHAP 분석과 Fold 분석을 통해 단순히 성능을 높이는 것에 그치지 않고,
- 어떤 변수가 중요한지
- 어떤 상황에서 모델이 실패하는지
- 왜 오차가 발생하는지
를 확인할 수 있었다.
+
문제의식
기존 파이프라인에서는 시계열 피처를 만들 때 별 고민 없이 모든 변수에 이동평균(_MA3)과 1초 전 값(_lag1)을 붙였다. 그런데 검증 관점에서 보면 이게 약점이었다. "그냥 만들었다"가 아니라 "데이터가 이런 성질을 가지므로 만들었다"가 되어야 설득력이 생긴다.(1) Ljung-Box 검정 — Lag Feature의 근거 (자기상관성)
Lag Feature는 "과거 값이 현재 값을 설명하는가?"를 전제로 한다. 이걸 검증하는 게 자기상관 검정이다.python
모든 변수에서 p-value < 0.05 → 유의미한 자기상관성 확인
이동평균은 "추세가 있어 불안정한(비정상) 변수"를 매끄럽게 만들어 학습을 돕는다. 따라서 어떤 변수가 비정상인지 확인할 필요가 있다.python
- 비정상 변수 (p > 0.05):Ambient Temperature 등 — 시간 흐름에 따라 추세가 뚜렷해 불안정 →이동평균 적용 정당화
- 정상 변수 (p < 0.05):Velocity, Motor Torque 등 대부분 — 이미 안정적이라 추가 가공 없이 그대로 사용해도 무방
마지막으로 두 검정 결과를 합쳐, 어느 한쪽이라도 유의성이 검증된 변수만 시계열 피처 대상으로 자동 선정했다.python
요약통계(Trip 1개 = 관측치 1개)로 변환한 뒤, 모델 입력으로 쓰기 전에 데이터가 한쪽으로 쏠려 있지 않은지 점검하는 섹션을 새로 넣었다.python
결론: 데이터가 특정 값에 편향되지 않고 넓은 범위에 고르게 분포하며, 학습을 방해할 만한 이상치도 보이지 않음.
오늘 새로 그린 건 아니지만 파이프라인의 핵심 시각화라 함께 정리한다. 리샘플링(0.1초 → 1초 평균) 직후, 주요 15개 변수를 각각 히스토그램 + 박스플롯으로 그려 이상치를 검토했다.
대상 변수: Velocity, Elevation, Throttle, Motor Torque, 종방향 가속도, 회생제동 신호, Battery Voltage/Current/Temperature, SoC, Heating/AirCon Power, Ambient Temperature, Heat Exchanger Temperature, Cabin Temperature.
핵심 해석을 몇 가지만 추리면:
- Velocity:0km/h에 다수 집중(정차 시간) + 우측 145~150km/h 이상치는 실제 고속 주행 가능 →이상치 처리 안 함
- Throttle:100%를 넘는 값은 물리적으로 불가능 → 센서 오류로 보고 처리 대상
- Battery Temperature:다봉형 분포 → 서로 다른 외기 환경/주행 조건이 섞였다는 신호 (TripA/B 혼합의 흔적)
- Ambient Temperature:-3~33℃ 다봉형 → 여러 계절 데이터가 섞여 있음을 직접 보여줌
- SoC:다봉형 → 서로 다른 초기 충전 상태의 Trip이 혼합
물리적 제약이 명확한 변수만 클리핑하고, 나머지는 실제 주행에서 발생 가능한 값으로 보고 유지했다.시각화 ③: 통계 검정 결과 표
코드뿐 아니라 검정 결과를 표로 출력해, 어떤 변수가 어떤 근거로 선택됐는지 한눈에 보이게 했다.
- Ljung-Box 결과표:변수별 LB 통계량 / p-value / lag1 포함 여부
- ADF 결과표:변수별 ADF 통계량 / p-value / MA3 유효 여부
- 결합 선정표:두 검정을 합쳐 최종 선택 여부
- Mann-Whitney U 검정표:TripA vs TripB 핵심 변수 8개의 중앙값 차이와 유의성
얼핏 "환경이 주행거리에 영향을 준다"와 반대되는 결과처럼 보이지만, 해석은 이렇다. 환경(날씨·온도·경로)은 거리 자체가 아니라 같은 거리를 가는 데 드는 에너지/SoC 소모에 영향을 준다.
블로그/문서화 관점에서, 코드 셀 사이사이에 판단 근거를 적은 markdown을 대거 추가했다.
- 리샘플링:0.1초 단위는 노이즈가 크고 용량이 과도 → 1초 평균으로 집계. 단, 순간 이벤트(급가속·급제동) 정보 손실은 변화량(_diff) 피처로 부분 보완하는 trade-off 명시.
- 결측치 처리:SoC 계열(전체 대비 2~3%)은 핵심 변수라 Trip별 앞뒤 보간으로 유지. Requested Coolant Temperature는 Trip 단위로 통째로 비어 보간 불가 → 삭제.
- 요약통계 & 변화량:시계열을 "Trip 1개 = 관측치 1개"로 압축. 평균이 비슷한 두 Trip이라도 변화량 표준편차가 크면 더 역동적인 주행임을 포착.
- Overview 병합:센서 데이터에 없는 Trip 메타데이터(날씨, 경로, 시작/종료 SoC)를 결합. 병합 후 중복 변수(외기온 mean/max, 배터리 온도 mean/max, 변별력 없는 Fan)는 재검토 후 제거.
Ljung-Box 검정자기상관 확인 → Lag Feature 근거신규ADF 검정정상성 확인 → 이동평균 근거신규검정 결합 변수 선정12개 시계열 변수 자동 선정신규편향 데이터 확인Trip 단위 평균 분포 히스토그램신규설명 markdown 보강리샘플링·결측치·병합 근거 명시보강전체 과정 요약 표11단계 파이프라인 한눈 정리신규이상치 탐색 시각화15개 변수 히스토그램+박스플롯기존
핵심 한 줄: 오늘은 "피처를 만든 행위"에 "통계적 근거"를 붙여, 파이프라인을 설명 가능하고 재현 가능하게 만든 날이었다.
다음 단계는 LassoCV + VIF로 최종 변수를 추리고, 통합 모델 vs TripB 단독 모델의 성능을 비교하는 것이다.
'내일배움캠프(QA,QC_5기)' 카테고리의 다른 글
| [내일배움캠프] QA/QC_5기 ( 63일차 ) (0) | 2026.06.09 |
|---|---|
| [내일배움캠프] QA/QC_5기 ( 62일차 ) (0) | 2026.06.08 |
| 내일배움캠프(QA,QC_5기)[내일배움캠프] QA/QC_5기 ( 60일차 ) (0) | 2026.06.04 |
| [내일배움캠프] QA/QC_5기 ( 59일차 ) (0) | 2026.06.02 |
| [내일배움캠프] QA/QC_5기 ( 58일차 ) (0) | 2026.06.01 |