안녕하세요. 이번 글에서는 2026년 6월 20일에 진행한 RealMLP 피처 뱅크 실험을 정리하겠습니다.
이번 실험의 목적은 퍼블릭 점수를 조금 더 올리는 것이 아니었습니다. 오히려 퍼블릭 점수가 낮게 나와도, OOF와 CV 기준으로 프라이빗 리더보드에서 버틸 수 있는 후보를 찾는 것이 목적이었습니다.
이 대회는 퍼블릭 리더보드가 꽤 오염되어 있다고 느꼈습니다. 공유된 고점 제출 파일이 많고, 상위권에도 비슷한 점수의 제출물이 촘촘하게 몰려 있었습니다. 그래서 퍼블릭 점수만 보고 움직이면 특정 퍼블릭 구간에 과하게 맞춘 후보를 만들 위험이 있다고 판단했습니다. 이건 다음 캐글 대회를 나갈 때도 기억했다가 주의를 해야겠습니다!
이번 실험에서 보고 싶었던 질문은 세 가지였습니다.
- 새로 만든 단일 모델이 기존 스태커 재료보다 실제로 강한가?
- 그 재료를 넣은 스태커가 OOF와 CV 기준으로 기존 프라이빗 후보를 넘는가?
- 퍼블릭 점수가 낮게 나와도 프라이빗 후보로 남길 근거가 있는가?
1. 단일 모델부터 본 이유
이전까지는 강한 퍼블릭 앵커와 여러 블렌딩 후보를 중심으로 실험했다. 그런데 어느 순간부터 퍼블릭 점수만 따라가는 방식에는 한계가 있다고 느꼈다. 점수가 오른 이유가 모델이 더 좋아서인지, 아니면 퍼블릭 일부 행에 우연히 맞았기 때문인지 구분하기 어려웠다.
그래서 이번에는 다시 단일 모델부터 봤다. 좋은 스태커는 결국 좋은 재료에서 나온다. 약한 재료를 많이 섞는 것보다, 먼저 강한 단일 모델을 확보하는 것이 더 중요하다고 생각했다.
이번에 새로 본 재료는 다음과 같다.
- LightGBM + RealMLP식 피처
- XGBoost + RealMLP식 피처
- CatBoost + RealMLP식 피처
- 일대나머지 CatBoost + RealMLP식 피처
- 새 모델 뱅크를 포함한 로지스틱 스태커
- OOF, 구간, 클래스 전환 진단
여기서 핵심은 RealMLP 계열에서 효과가 있었던 피처 표현을 트리 모델에도 넣어본 것이다. 신경망 쪽에서 잘 먹힌 피처가 CatBoost나 LightGBM에서도 의미가 있는지 확인하고 싶었다.
2. CatBoost 변화
단일 모델 결과에서 가장 크게 바뀐 것은 CatBoost였다.
기존 CatBoost는 OOF balanced accuracy가 0.965247 수준이었다. 그런데 RealMLP식 피처를 넣은 CatBoost는 0.969746까지 올라갔다. 이건 단순한 튜닝 차이라기보다, 피처 표현이 모델의 판단 방식을 크게 바꾼 결과로 보인다.
fold별 결과도 비교적 안정적이었다.
fold 1: 0.968947
fold 2: 0.970799
fold 3: 0.970103
fold 4: 0.969856
fold 5: 0.969027
특정 fold 하나만 튄 결과는 아니었다. 그래서 이 CatBoost는 단순 제출 후보라기보다, 앞으로 스태커에 넣을 핵심 재료로 볼 수 있었다.
일대나머지 CatBoost는 단독 점수만 보면 CatBoost 본체보다 낮았다. 하지만 클래스별 경계를 따로 보기 때문에, 스태커 재료로는 다른 신호를 줄 수 있다고 판단했다.
3. OOF 상승과 퍼블릭 하락
새 RealMLP 피처 뱅크를 포함한 스태커는 OOF 기준으로 기존 후보를 넘었다.
기존 후보들은 대략 0.97028에서 0.97035 근처였고, 새 스태커는 0.970447까지 올라갔다. OOF만 보면 분명히 전진이었다.
그런데 퍼블릭 점수는 0.97081로 낮았다.
처음에는 이 결과가 불편했다. 퍼블릭이 낮으면 그냥 실패한 것 아닌가 하는 생각도 들었다. 하지만 이번 대회에서는 퍼블릭과 프라이빗이 같은 방향으로 움직이지 않을 수 있다고 계속 의심하고 있었다.
그래서 이 후보를 바로 버리지는 않았다. 대신 퍼블릭이 왜 내려갔는지 변경 방향을 확인했다.
4. 변경 방향
새 공격형 스태커는 기준 제출보다 테스트 행을 936개 바꿨다. 처음에는 변경량이 너무 많아서 퍼블릭이 내려간 것처럼 보였다.
하지만 보호 조건을 넣어 변경 행을 265개까지 줄였는데도 퍼블릭은 크게 회복되지 않았다. 이때 생각이 바뀌었다.
문제는 단순히 많이 바꾼 것이 아니라, 어떤 방향으로 바꿨는지였다.
- STAR에서 GALAXY로 바꾸는 방향은 큰 이득이었다.
- QSO에서 GALAXY로 바꾸는 방향도 이득이었다.
- 반대로 GALAXY를 STAR나 QSO로 보내는 방향은 손실이 컸다.
특히 GALAXY에서 STAR로 바꾸는 방향은 위험했다. 이 결과를 보고, 새 스태커가 전체 OOF를 올리더라도 GALAXY를 다른 클래스로 보내는 변경은 강하게 제한해야 한다고 판단했다.
이 지점에서 실험의 방향이 더 분명해졌다.
- 좋은 모델을 찾는 것만으로는 부족하다.
- 어떤 클래스 전환을 허용할지 따로 설계해야 한다.
- 전체 점수보다 전환 방향별 손익을 같이 봐야 한다.
5. 그리디 탐색 결과
새 CatBoost와 RealMLP 재료가 정말 유용한지 보기 위해 빠른 그리디 탐색을 실행했다.
기존 lr-stacker-v9-public-oof를 기준으로 두고, 첫 번째 블렌딩 단계에서 our-catboost-realmlp-features가 선택되었다. 두 번째 단계에서는 realmlp-0이 추가되었다. 최종 OOF는 0.970479였다.
그리디 탐색이 새 CatBoost RealMLP 피처 재료를 직접 선택했다는 점이 중요했다. 내가 좋아 보인다고 느낀 재료가 아니라, OOF 기준으로 실제 추가 가치가 있었다는 뜻이기 때문이다.
이 후보는 35번 후보로 저장했다. 퍼블릭 점수는 0.97104였다. 퍼블릭 기준으로 높은 점수는 아니지만, 앞선 공격형 후보들보다는 덜 무너졌다.
나는 이 후보를 프라이빗 후보군에 남기기로 했다. 퍼블릭만 보면 매력적이지 않지만, 실험 논리상 버리기에는 아까웠다.
6. 일대나머지 XGBoost
다음으로 일대나머지 XGBoost를 추가했다.
결론부터 말하면 단독 모델로는 실패에 가까웠다. OOF는 0.964203이었다. 하지만 이 결과를 보고 XGBoost가 완전히 쓸모없다고 판단하지는 않았다.
문제는 이진 모델들이 경계를 전혀 못 배운 것이 아니라, 클래스별 이진 확률을 최종 다중 클래스 예측으로 합치는 과정에 있어 보였다.
즉 일대나머지 XGBoost는 그대로 제출 후보로 쓰기에는 약하지만, 클래스별 보정 재료로는 다시 볼 가치가 있었다.
이때 생긴 가설은 이렇다.
- 클래스별 이진 모델의 신호를 단순 argmax로 합치면 정보가 깨질 수 있다.
- 클래스별 로지스틱 모델로 다시 보정하면 쓸 수 있을지도 모른다.
7. 폴드 안전 타깃 인코딩
이번 실험에서 또 중요했던 것은 폴드 안전 타깃 인코딩이었다.
가장 조심한 부분은 정답 누수였다. 타깃 인코딩을 전체 학습 데이터에 한 번에 맞추면 검증 fold의 정답 정보가 피처에 섞일 수 있다. 그래서 각 fold마다 학습 fold에서만 통계를 만들고, 검증 fold와 테스트에는 변환만 적용했다.
결과는 좋았다.
- 기존 LightGBM RealMLP 피처 모델 OOF: 0.965842
- 폴드 안전 타깃 인코딩 LightGBM OOF: 0.967900
- 개선폭: 0.002058
단일 LightGBM 성능은 확실히 올랐다. 하지만 강한 스태커에 그대로 넣었을 때는 새 재료로 선택되지 않았다.
내 해석은 이렇다.
- 폴드 안전 타깃 인코딩 모델은 전체 예측 재료로는 중복 신호가 많다.
- 하지만 서로 판단이 갈리는 행 안에는 추가 신호가 남아 있을 수 있다.
그래서 이 모델을 전체로 섞는 대신, 강하게 반대하는 일부 행만 패치 후보로 보는 방향으로 바꿨다.
8. 인코딩 반대 신호 패치
폴드 안전 타깃 인코딩 LightGBM은 전체 스태커 재료로는 선택되지 않았다. 하지만 서로 판단이 갈리는 행만 보면 이야기가 달랐다.
기준 후보는 클래스별 그리디 스택이었다. 비교 모델은 폴드 안전 타깃 인코딩 LightGBM이었다.
전체 OOF는 비교 모델이 낮았다. 그런데 특정 조건으로 반대 신호 행을 제한하자 OOF 최고 후보가 나왔다.
56번 후보 OOF: 0.970573
기준 후보 대비 상승: 0.000045
변경된 학습 행: 83개
변경된 테스트 행: 40개
이 후보가 흥미로웠던 이유는 약한 모델도 완전히 버릴 필요가 없다는 것을 보여줬기 때문이다. 전체 성능은 낮아도 특정 물리 피처 구간에서는 다른 모델이 놓친 경계 신호를 줄 수 있다.
다만 56번 후보는 안정성 면에서는 완벽하지 않았다. 메타 fold 최소 변화가 음수였다. 그래서 OOF 최고 후보로는 중요하지만, 최종 후보로 단독 신뢰하기에는 불안이 남았다.
9. 클래스별 블렌더
일대나머지 계열 모델은 그대로 다중 클래스 예측으로 바꾸면 성능이 깨졌다. 그래서 클래스별 이진 신호를 다시 보정하는 클래스별 로지스틱 블렌더를 시도했다.
목적은 단순했다.
- 클래스별 이진 경계 신호를 버리지 않는다.
- 각 클래스마다 로지스틱 보정 모델을 만든다.
- 그 결과를 다시 그리디 탐색에 넣어본다.
직접 클래스별 블렌더 후보는 테스트 행을 810개 바꿔서 너무 공격적이었다. 하지만 그리디 탐색에 넣었을 때는 의미 있는 결과가 나왔다.
37번 클래스별 그리디 후보는 OOF 0.970528을 기록했다.

이 이미지는 클래스별 블렌더가 어떤 재료를 중요하게 봤는지 보여준다. 기존 lr-stacker-v9-public-oof가 여전히 가장 큰 재료였지만, 새로 만든 일대나머지 CatBoost RealMLP 피처와 CatBoost RealMLP 피처도 큰 비중을 받았다.
이 그림은 클래스별 블렌더가 단순히 기존 public-oof 스태커를 반복한 것이 아니라, 새로 만든 RealMLP 피처 뱅크 재료를 실제로 사용했다는 근거로 넣으면 좋다.
10. 클래스별 재현율
클래스별 블렌더는 전체 OOF만 보면 좋아 보인다. 하지만 클래스별 재현율을 보면 더 조심스러운 그림이 나온다.

이 이미지는 기준 후보와 클래스별 블렌더의 OOF 클래스별 재현율을 비교한다.
그래프를 보면 GALAXY 재현율은 0.96069에서 0.96218로 오른다. QSO 재현율도 아주 조금 오른다. 반면 STAR 재현율은 0.97331에서 0.97210으로 내려간다.
즉 클래스별 블렌더는 전체적으로 GALAXY 쪽을 더 잘 맞히는 방향으로 움직였지만, 그 대가로 STAR 재현율을 일부 잃었다. 이건 프라이빗 후보를 판단할 때 중요한 손익이다.
이 그래프를 보고 OOF가 올랐으니 무조건 좋다고 말하면 안 된다고 느꼈다. balanced accuracy는 클래스별 재현율의 평균이기 때문에, 어느 클래스를 희생해서 어느 클래스를 올렸는지 반드시 같이 봐야 한다.
11. 혼동 변화

이 이미지는 클래스별 블렌더가 기준 후보 대비 혼동 행렬을 어떻게 바꿨는지 보여준다.
가장 눈에 띄는 부분은 GALAXY 행이다. 실제 GALAXY를 GALAXY로 맞힌 수가 564개 늘었다. 동시에 실제 GALAXY를 STAR로 잘못 보내던 경우가 575개 줄었다. 이 부분이 GALAXY 재현율 상승의 원인으로 보인다.
하지만 STAR 행을 보면 반대 효과가 있다. 실제 STAR를 STAR로 맞힌 수는 100개 줄고, 실제 STAR를 GALAXY로 보낸 수는 97개 늘었다. 즉 클래스별 블렌더는 일부 STAR를 GALAXY로 당겨오면서 GALAXY 쪽 이득을 만들었지만, STAR 쪽에서는 손실도 만들었다.
이 그래프는 이번 실험을 이해하는 데 매우 중요하다.
- 모델이 좋아졌다는 말은 너무 넓다.
- 어떤 오답이 줄었고, 어떤 오답이 늘었는지를 봐야 한다.
- 전체 OOF보다 클래스별 손익을 같이 봐야 한다.
이 관점에서 보면 클래스별 블렌더는 확실히 방향성이 있는 모델이다. GALAXY 쪽을 보강하지만 STAR 손실을 만들 수 있다. 그래서 이후 구간 보호가 필요해졌다.
12. 구간 보호
37번 클래스별 그리디 후보는 OOF가 좋았다. 하지만 약한 구간을 확인하니 문제가 보였다.
특히 g_i_bin 0, g_i_bin 2, mag_range_bin 0, O/B_Blue_Cloud, A/F_Blue_Cloud 구간이 약했다. 이 구간에서 GALAXY를 STAR로 보내는 전환이 손해를 만들었다.
그래서 37번을 그대로 제출 후보로 두기보다, 위험한 구간에서 특정 전환을 막는 구간 보호 후보를 만들었다.
결과적으로 44번과 48번이 중요 후보로 남았다.
44번: OOF 0.970558, 최고 OOF에 가까운 후보
48번: OOF 0.970556, 메타 fold 안정성이 더 좋은 후보
44번은 OOF가 아주 조금 높지만 메타 fold 최소 변화가 약하게 음수였다. 반면 48번은 OOF가 아주 조금 낮지만, fold 안정성이 더 좋았다.
이 차이는 작지만 중요하다. 퍼블릭 점수만 볼 때는 이런 차이가 잘 보이지 않는다. 하지만 프라이빗 일반화를 목표로 하면, OOF 최고점과 fold 안정성 사이에서 균형을 봐야 한다. 나는 이 시점에서 48번을 더 안정적인 후보로 선택했다.
13. 생각이 바뀐 지점
이번 실험에서 가장 크게 바뀐 생각은 세 가지다.
- 퍼블릭 점수가 낮다고 바로 버리면 안 된다.
35번은 퍼블릭이 0.97104로 높지 않았다. 하지만 공격형 후보들보다 덜 무너졌고, OOF 논리도 분명했다. 퍼블릭만 보면 매력적이지 않지만, 프라이빗 후보로는 남길 이유가 있었다.
- 강한 모델도 전이 방향을 제한해야 한다.
CatBoost RealMLP 피처와 클래스별 블렌더는 좋은 신호를 줬다. 하지만 GALAXY를 다른 클래스로 보내는 전이는 위험했다. 좋은 모델이라고 모든 변경을 허용하면 퍼블릭과 프라이빗 모두 흔들릴 수 있다.
- 약한 모델도 반대 신호 행에서는 쓸 수 있다.
폴드 안전 타깃 인코딩 LightGBM은 전체 스태커 재료로 선택되지 않았다. 하지만 타깃 인코딩 모델이 강하게 반대하는 일부 high_gi_low_rz 경계에서는 OOF 최고 후보를 만들었다.
모델 전체 성능이 낮다고 신호가 없는 것은 아니다. 좋은 신호는 특정 행과 특정 피처 구간 안에 숨어 있을 수 있다.
14. 다음 방향
다음 실험은 더 많은 모델을 무작정 추가하는 것이 아니라, 이미 찾은 신호를 더 조심스럽게 쓰는 쪽이어야 한다.
우선순위는 다음과 같다.
- 클래스별 로지스틱 블렌딩의 보정을 더 안정화한다.
- 일대나머지 XGBoost는 그대로 쓰지 말고 클래스별 보정으로 다시 본다.
- 폴드 안전 타깃 인코딩은 전체 예측 재료가 아니라 반대 신호 패치 재료로 사용한다.
- CatBoost v3식 SDSS 외부 데이터 low-weight 학습은 별도 검증축으로 확인한다.
- RealMLP와 TabM 직접 학습은 실행 비용이 크므로 뒤로 둔다.
특히 폴드 안전 타깃 인코딩은 계속 조심해야 한다. 잘못 넣으면 정답 누수가 생긴다. 다음 구현에서도 반드시 fold 안에서 맞추고 검증과 테스트에는 변환만 적용해야 한다.
15. 마무리
이번 실험은 퍼블릭 리더보드 점수를 높이는 실험이 아니었다. 오히려 퍼블릭 점수와 OOF가 충돌할 때 무엇을 믿을지 정리하는 실험과 연구에 가까웠다.
CatBoost RealMLP 피처는 단일 모델로 큰 개선을 만들었다. 클래스별 블렌더는 OOF를 올렸지만 클래스별 손익을 만들었다. 폴드 안전 타깃 인코딩은 전체 모델로는 약했지만 반대 신호 패치에서는 강한 신호를 줬다.
이번 연구의 핵심은 좋은 후보는 퍼블릭 점수 하나로 고르면 안 된다. OOF, 클래스별 재현율, 혼동 변화, 전이 방향, 메타 fold 안정성을 같이 봐야 할 거 같다.
'6. 경진 대회 (kaggle, dacon 등) > 6-1 연구 및 개선 기록' 카테고리의 다른 글
| [개인 경진 대회] Kaggle Playground Series S6E6 연구 (6): RealMLP 피처 뱅크 실험 기록 (0) | 2026.06.27 |
|---|---|
| [개인 경진대회] DACON - 성균관대 멀티모달 AI 챌린지 (마무리1) - Private 1등 (0) | 2026.06.25 |
| [개인 경진 대회] Kaggle Playground Series S6E6 연구 (4) 그래프 분석편 (0) | 2026.06.17 |
| [개인 경진 대회] Kaggle Playground Series S6E6 연구 기록 3일차 (0) | 2026.06.16 |
| [개인 경진대회] DACON - 성균관대 멀티모달 AI 챌린지 (6): 채점 구조 역공학과 commit recovery (0) | 2026.06.15 |