모델이 과소적합된 것이 아니다. 피처가 게으르다.
요약
모델 성능 정체의 원인이 모델 구조가 아닌 피처(feature)의 문제일 수 있음을 지적합니다. 선형 모델과 그라디언트 부스팅 모델의 차이점을 비교하며, 부스팅 모델이 효과적인 상황과 주의해야 할 데이터 누수 문제를 다룹니다.
핵심 포인트
- 모델 교체보다 피처 엔지니어링이 성능 향상의 핵심일 수 있음
- 선형 모델은 해석력이 높지만 비선형 관계 포착에 한계가 있음
- 부스팅 모델은 피처 간 상호작용을 잘 포착하지만 블랙박스 특성을 가짐
- 복잡한 모델은 데이터 누수(leakage)를 이용해 잘못된 성능을 보일 수 있음
제가 수많은 팀에서 목격한 상황입니다. 정확도가 정체됩니다. 누군가 로지스틱 회귀(logistic regression)를 제거하고 XGBoost를 도입하며 성능 향상을 기대합니다. 하지만 그 상승세는 오지 않거나, 아무에게도 설명할 수 없는 두 점의 차이로 나타납니다. 결국 한 주가 하이퍼파라미터 튜닝에 사라지고, 시작점보다 겨우 나은, 느리고 무겁고 해석하기 어려운 모델을 갖게 됩니다.
사실 병목 현상은 거의 모델 자체가 아니었습니다. 피처(features)였습니다.
본 게시물은 그 주장의 길고 실용적인 버전입니다. 우리는 두 진영을 평이한 언어로 정의하고, 실제 코드를 실행하며, 부스팅(boosting)이 실제로 승리하는 경우를 살펴보고, 아무도 경고해주지 않는 실패 모드—즉, 화려한 모델이 조용히 속임수를 써서 '승리'하는 경우—까지 다룰 것입니다.
시작하기 전에 한 가지 참고사항입니다. 예시는 일반적인 것으로 유지하세요. 우리는 수치형 타겟(numeric target)—수요량, 수량, 테이블 형식 데이터셋의 점수 등—을 예측할 것입니다. 원리는 어디서든 동일하므로, 반드시 자신의 데이터로 검증해야 합니다.
평이한 용어로 본 두 진영
**선형/로지스틱 회귀(Linear / logistic regression)**는 직선 관계를 모델링합니다: 각 피처에 가중치(계수)가 부여되고, 예측값은 이 가중치들의 합으로 결정됩니다. 로지스틱 회귀는 분류(classification)를 위해 동일한 아이디어를 변형한 것으로, 확률을 출력합니다.
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(max_iter=1000)
...
이 루프 전체가 모델입니다. 양의 가중치는 '이것이 예측값을 올리는 요인'을 의미하며, 이 표를 이해관계자에게 제시하고 모든 숫자를 방어할 수 있습니다. 단점은 관계가 대략 선형적이고 피처들이 독립적으로 작용한다고 가정한다는 것입니다. 실제 데이터는 종종 그렇게 정직하지 않습니다.
그라디언트 부스팅(Gradient boosting) (XGBoost, LightGBM, sklearn의 GradientBoostingClassifier)은 수백 개의 작은 결정 트리(decision trees)를 구축하며, 각 트리는 이전 트리의 실수를 교정합니다. 이는 비선형성(nonlinearity)과 피처 상호작용을 공짜로 포착하며, 지저분한 테이블 형식 데이터에서는 보통 원시 정확도(raw accuracy) 면에서 승리합니다.
from xgboost import XGBClassifier
model = XGBClassifier(n_estimators=300, max_depth=4, learning_rate=0.05)
...
그 대가는 거울의 반대편과 같습니다. 바로 블랙박스(black box)라는 점입니다. 계수(coefficients)를 읽는 방식처럼 모델을 읽을 수 없으며, 내버려 두면 기꺼이 과적합(overfit)될 것이고 — 이 부분이 뼈아픈 지점인데 — 데이터에 존재하는 그 어떤 누수(leakage)라도 무시무시한 열정으로 이용할 것입니다.
부스팅(Boosting)이 진정으로 승리하는 순간
부스팅에 대해 공정하게 말해보겠습니다. 부스팅은 그럴 만한 가치가 있기 때문입니다. 타겟(target)이 두 피처(feature)의 합이 아닌 곱해진 값에 의존하는, 즉 실제 상호작용 효과(interaction effect)가 있는 데이터셋을 구축하고 어떤 일이 일어나는지 지켜보십시오.
import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
...
로지스틱 회귀(Logistic regression)는 여기서 약 0.5 AUC에 가까운, 거의 찍는 수준의 점수를 기록할 것입니다. 왜냐하면 개별 피처와 타겟 사이에 직선적인 관계가 없기 때문입니다. 반면 부스팅은 훨씬 높은 점수를 기록할 것입니다. 트리가 x1을 기준으로 분할한 뒤, 그 가지(branch) 내부에서 다시 x2를 기준으로 분할할 수 있기 때문이며, 이것이 바로 상호작용(interaction) 그 자체이기 때문입니다.
이것이 부스팅을 사용하는 정직한 이유입니다: 신호가 비선형(nonlinear)이거나 상호작용 속에 존재하며, 당신이 이를 사전에 알지 못할 때 말입니다. 트리는 당신이 직접 설계(hand-engineer)하지 않은 구조를 찾아냅니다.
하지만 마지막 문장의 함정을 주목하십시오 — "당신이 직접 설계하지 않은". 만약 당신이 직접 설계했다면 어떻게 될까요?
반전: 피처가 격차를 줄인다
선형 모델(linear model)에 상호작용 항(interaction term)을 명시적으로 제공하면, 모델은 즉시 격차를 따라잡습니다:
# 상호작용을 피처로서 선형 모델에 직접 전달
X_better = np.column_stack([x1, x2, x1 * x2])
...
x1 * x2라는 하나의 설계된 컬럼(engineered column)만으로, "약한" 모델은 이제 부스팅과 경쟁할 수 있게 되면서도 완전한 해석 가능성(interpretable)을 유지합니다. 당신은 해당 상호작용 항의 계수(coefficient)를 보고 모델이 무엇을 학습했는지 _알 수 있습니다.
이것이 하나의 실험으로 보여주는 전체 논지입니다. 부스팅이 더 똑똑했던 것이 아닙니다. 부스팅은 당신이 만드는 것을 잊어버린 피처를 보완하고 있었을 뿐입니다. 단순한 모델과 복잡한 모델 사이의 정확도 격차는 매우 빈번하게, 복잡한 모델이 당신이 손으로 직접 쓸 수 있었던 피처를 내부적으로, 그리고 불투명하게 재발견한 결과일 뿐입니다.
더 나은 피처 (Feature)가 더 나은 알고리즘 (Algorithm)을 이기며, 비용도 더 적게 들고 신뢰하기도 훨씬 쉽습니다.
아무도 경고해주지 않는 실패 모드: 데이터 누수 (Leakage)
여기서 부스팅 (Boosting)의 열정이 위험하게 변하는 지점이 있습니다. **데이터 누수 (Data leakage)**란 예측 시점에는 실제로 사용할 수 없는 정보가 피처 (Feature)에 몰래 포함되는 것을 말합니다. 이는 대개 당신이 예측하려는 대상의 하류 (Downstream)에 있는 정보이기 때문에 발생합니다.
구체적인 예시를 들어보겠습니다. 주문이 취소될지 여부를 예측한다고 가정해 봅시다. 누군가 refund_amount (환불 금액)라는 피처를 추가했습니다. 이 피처는 예측력이 매우 뛰어나서 정확도가 10포인트나 상승했습니다. 바로 배포합시다!
하지만 문제는 환불은 취소가 일어난 이후에만 발생한다는 점입니다. 실제로 예측이 필요한 시점에는 refund_amount는 항상 0입니다. 당신은 취소 때문에 생겨난 컬럼을 사용하여 취소를 예측하도록 모델을 학습시킨 것입니다. 프로덕션 (Production) 환경에서는 무용지물이며, 수치가 조용히 무너지기 전까지는 이 사실을 알 수 없을 것입니다.
# 이 "피처"는 변장을 하고 있는 정답입니다.
# 당신이 예측하려는 이벤트가 발생한 후에만 값이 채워집니다.
df["refund_amount"] # 타겟 (Target)을 누수함
왜 이것이 부스팅 (Boosting)에서 더 중요할까요? 선형 모델 (Linear model)은 피처 (Feature) 전반에 걸쳐 주의력을 분산시키기 때문에, 단 하나의 누수된 컬럼이 있다면 당신이 눈치챌 수 있는 의심스러울 정도로 거대한 계수 (Coefficient) 하나를 만들어낼 것입니다. 반면 부스팅 (Boosting)은 누수를 찾아내어 거기에 달라붙고, 대부분의 트리 (Tree)를 그 경로로 몰아넣습니다. 그 결과 당신에게 순전한 허구인 화려한 검증 점수 (Validation score)를 안겨줍니다. 모델이 강력할수록 데이터의 실수를 더 효율적으로 악용합니다.
더 미묘한 버전도 있습니다. 바로 **전처리 누수 (Preprocessing leakage)**로, 데이터를 분할하기 전에 전체 데이터셋에 대해 무언가를 계산하는 경우입니다:
# 잘못된 방법: 스케일러 (Scaler)가 분할 전 테스트 세트의 통계치를 미리 보게 됨
X_scaled = StandardScaler().fit_transform(X)
X_train, X_test = train_test_split(X_scaled)
...
파이프라인 (Pipeline)은 단순한 스타일 선호의 문제가 아닙니다. 테스트 정보가 학습 과정으로 흘러 들어가는 것을 막아주는 장치이며, 믿을 수 있는 검증 점수와 믿을 수 없는 점수를 가르는 차이입니다.
그럼 실제로 어떻게 선택해야 할까요?
주니어 엔지니어에게 전달할 결정 순서는 다음과 같습니다:
→ 단순한 모델부터 시작하세요. 로지스틱 회귀 (Logistic regression) 또는 선형 회귀 (Linear regression), 깔끔한 피처 (Features), 그리고 제대로 된 교차 검증 (Cross-validation) 설정입니다. 이것은 여러분의 베이스라인 (Baseline)이자 제정신을 유지하기 위한 확인 절차 (Sanity check)입니다. 만약 점수가 터무니없이 높게 나온다면, 아마도 데이터 누수 (Leakage)가 발생했을 가능성이 크며, 단순한 모델은 이를 쉽게 발견할 수 있게 해줍니다.
→ 모델이 아닌 피처에 노력을 쏟으세요. 상호작용 (Interactions), 비율 (Ratios), 이벤트 발생 후 경과 시간 (Time-since-event), 합리적인 인코딩 (Encodings) 등입니다. 여러분이 쫓고 있는 정확도 (Accuracy)의 대부분은 여기서 결정됩니다. 여러분이 직접 엔지니어링한 모든 피처는 블랙박스 (Black box) 모델이 불투명하게 재구성할 필요가 없는 정보가 됩니다.
→ 단순한 모델이 정체기에 도달하고, 데이터 누수를 배제했으며, 명백한 피처들을 모두 소진했을 때 부스팅 (Boosting)을 고려하세요. 이제야 여러분은 게으른 피처를 덮기 위한 임시방편 (Band-aid)이 아니라, 직접 엔지니어링할 수 없는 비선형성 (Nonlinearity)을 해결하기 위해 부스팅을 제대로 활용하는 것입니다.
→ 부스팅을 사용할 때는 반드시 해석 가능성 (Interpretability)을 요구하세요. 피처 중요도 (Feature importances), SHAP 값 (SHAP values), 부분 의존성 (Partial dependence) 등이 있습니다. 모델이 왜 그런 예측을 하는지 설명할 수 없다면, 모델이 틀렸을 때 잡아낼 수 없습니다.
이 모든 것을 관통하는 원칙은 다음과 같습니다: 모델 선택은 리더보드 (Leaderboard) 경쟁이 아니라 데이터에 대한 결정입니다. 좋은 피처를 사용한 깔끔한 회귀 모델은 지저분한 피처를 사용한 부스팅 모델을 거의 매번 이길 것이며, 실행 비용도 더 저렴하고 방어하기도 더 쉽습니다. XGBoost도 거짓 정보를 입력하는 파이프라인 (Pipeline)으로부터 여러분을 구해줄 수는 없습니다. 그 무엇도 불가능합니다.
여러분의 정확도가 마지막으로 정체되었을 때 — 새로운 모델을 찾으셨나요, 아니면 다시 돌아가 피처를 먼저 조사하셨나요? 어떤 본능이 먼저 움직였는지 궁금합니다. 그것이 여러분이 현재 어느 단계에 와 있는지를 많이 말해주기 때문입니다.
저는 Vinicius Fagundes입니다 — 독립적인 수석 데이터 엔지니어(Principal data engineer)이자 상파울루의 MBA 강사입니다. 저는 이러한 모델들에 데이터를 공급하는 데이터 파이프라인을 구축하고 수정합니다. 이것이 여러분의 세계라면, 이것이 제가 vf-insights.com에서 하는 일입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기