일주일동안 (baseline code와 instruction은 일주일 전에 받아서 총 2주긴 했지만) ML 경진대회를 진행하고 추석이 지나서 결과물을 발표하고 마무리하는 시간을 가졌다. Kaggle과 데이콘 등 여러 경진대회의 소스들을 보고 코드를 공부하는 시간은 예전부터 가졌지만 막상 실질적으로 경진대회를 참여 하는 건 처음이었기 때문에 time management 및 그룹과의 협업등이 얼마나 중요하였는지 막상 끝나고 나서 깨닫게 되었고 강사님 말로는 submit 할 수 있는 12번의 기회는 다른 경연대회보다 훨씬 많은 기회라고 말을 듣자마자 결과 한번 한번이 나올때마다 얼마나 신중하게 냈어야 했는지 고민하게 되었다. (물론 우리 팀은 5명이라 인당 2-3번이 한계였지만)
일단 우리 조는 그래도 다른 조에 비해 연령대가 좀 낮았다고 생각이 들고 (내가 가장 연령대가 높았지만..) 그로 인해 활발한 에너지와 소통이 장점이었다고 생각한다. 경연대회를 준비하기 전 주에는 각자 강의내용을 잘 따라가기가 학습 목표였고 2번정도 회의를 거쳐 각자 어느정도 따라오고 있는지 어려운 점은 없는지 그리고 article,논문 등 느낀점을 서로 공유 하였고 경연대회 주에는 첫날(baseline code를 못 본 팀원들도 있었기에)을 제외한 매일같이 zoom으로 만나서 1시간정도 진행상황과 앞으로의 계획 등을 공유하였다. 이번 조에서도 팀장을 맡았기에 전체적인 인원 관리, 앞으로의 계획 정리, 새로운 baseline code등을 공유했고 노션에도 각자 todo list 및 회의록, 멘토링 진행시에 어떤 내용을 물어보고 피드백 받았는지 전체적으로 요약해놨기 때문에 최소한의 역할은 했다고 생각한다. 우리 조의 노션기록 및 github은 다음과 같다. 노션 및 슬랙, zoom 등으로 공유 및 소통이 활발했던 점이 그래도 이번 경진대회를 진행하면서 마지막까지 포기하지 않고 submit 할 수 있었던 이유였다고 생각한다.
일단 이번 경진대회의 목표는 아파트 실거래가 RMSE 값을 최대한 낮추는 것이었고 regression model의 퍼포먼스를 측정할 수 있는 여러가지 metrics 중 MAE (Mean Abolute Error), MSE(Mean Squared Error), R^2 등 여러가지 다른 metrics도 있었지만 이번 경진대회는 RMSE (Root Mean Squared Error)을 사용하였다. Train set으로 제공되는 2007년부터 2023년 초반 데이터를 이용하여 2023년 7월부터 9월까지 (지금은 2024년 9월이지만)의 데이터를 얼마나 잘 맞추는 모델을 만들 수 있는지가 main task라고 할 수 있겠다. 기본적으로 베이스라인 코드만 submit하였을 때 47000대 점수였기 때문에 경진대회에 참여하는 모든 조들은 이 점수를 최대한 좋은 feature engineering과 모델 및 하이퍼파라미터 최적화로 점수를 최대한 낮추는 게 이 경진대회에서 높은 순위로 마치게 되는 결과로 이어질 수 있는 것이다. 초반에는 우리조가 굉장히 힘들었다고 생각한다. 우리 조가 멘토링 및 여러 정보를 찾아본 결과 좋은 feature enginnering (파생변수)를 찾는게 우선 순위라고 생각했고 기본적으로 제공되는 8:2 (train: test) 비율로 학습 및 random forest에서 모델을 바꾸는 과정은 나중에 해보자고 회의를 통해 결정했고 초반에 파생변수를 이것저것 시도해본 결과 오버피팅 및 RMSE 값이 내려가기는 커녕 오히려 올라가기도 하고 심지어 10만도(overfit: 이게 맨 처음에는 overfit의 결과인지 몰랐다) 넘어가는 결과가 나오기도 했었다.

2일동안 전전긍긍하며 어떻게 하면 rmse값을 내릴 수 있을까 계속 submit해보다 다른 팀원이 유의미한 RMSE값의 드롭을 해냈고 여기서 맨 처음 baseline code를 가져가기로 했다. 기본적으로 이 코드는 upstage에서 제공되는 베이스라인에서 큰 차이 없이 x,y좌표값을 카카오 api를 통해 불러오고 좌표값에 따른 버스 지하철 거리에 따른 아파트값, 아파트의 나이(계약연도 - 건축년도) 그리고 구를 one-hot encoding으로 변환하여 모든 구들을 파생변수값으로 불러와서 모델을 학습시킨 값이었다.

나는 팀원이 구를 one-hot encoding했다는 부분에서 주목을 하였고 다시 한번 Feature Importance를 확인해보니 구의 feature importance가 엄청 낮게 반영 되었다는 부분에서 의문이 들었다. 초반에 주어진 베이스라인 코드에서 파생변수가 강남여부가 있고 plot을 찍어봤을때도 그렇고 상식선에서도 강남구, 용산구 등은 당연히 아파트값이 다른 구에 비해 비쌀 수 밖에 없는데 왜 이렇게 낮게 나왔을까 싶어서 구를 어떻게 하면 더 좋게 반영할 수 있을까 싶어서 target의 평균가를 토대로 '구'를 groupby하여 새로운 new_구라고 새로운 파생변수를 만들고 Feature importance를 다시 찍어보았다. 그러고 나니 new_구의 feature importance가 그냥 구에 비해 어느정도 유의미한 변수로 바뀌었고 이 부분에서 '구'보단 '동'이 더 큰 변수가 아닐까라고 생각이 들어서 마찬가리로 제대로 '동'의 feature importance를 제대로 반영 못하는 부분을 같은 방법으로 (target의 평균가를 토대로 '동'을 groupby) new_동을 만들었다. 이 부분에서 mean을 사용했으니 기초 stat에서 가장 중요한 mean, std 가 떠올라서 동마다 target의 표준편차도 계산해서 넣어보았다. 이 과정에서 유의미한 rmse값의 드롭이 있었고 여기서부터 기존 주어진 변수들에서 더 좋은 파생변수가 없을지 찾게 되었다.

여기까지 해본 결과 드는 느낌을 팀원들과 공유했을 때 물론 외부 데이터를 끌고 오면 좋겠지만 일단 주어진 변수들을 기반으로 좀더 만들어보자 라고 결론이 났고 결국 있는 데이터의 전처리(k값 전부날림 및 필요없는 데이터 전부 삭제) 등을 좀더 강화하였고 나는 아파트명에 좀 더 주목하기 시작했다. 맨 처음의 approach는 비싼 아파트 값을 잡기 위해 어떻게 하면 좋을까였다. 멘토링 뿐만 아니라 여러 research를 통해 배운 점은 비싼 아파트, 초고가 아파트 등을 예측 잘하는 모델이 rmse값을 확 낮출 수 있다고 확신했기 때문에 여기서 어떻게 초고가 아파트들을 분별 할 수 있을까에 대해 고민하였다. 이에 대해 target의 평균가를 기준으로 아파트명마다 cluster를 만들어서 (k-means clustering을 사용) 초고가 아파트의 구분을 명확히 지어보면 어떻게 될까 라고 테스트를 해봤는데 여기서 또 유의미한 결과를 얻을 수 있었다.

하지만 결과론적으론 초고가 아파트의 에러값은 전혀 잡히지 않았고 아마도 이부분은 학습데이터셋에서 데이터가 몇개 없기 때문에 어떻게 처리를 해도 (다른 외부데이터값으로 고가 아파트들을 채워넣지 않는 이상) 힘들겠다고 생각했다. 어찌 됐든 유의미한 결과를 얻었으니 정말 주어진 변수들로만 해도 가능하겠다 싶었어서 남은 2일동안은 파생변수에 좀더 집중하자고 생각했다. 전용면적과 계약년월 : 이 2개의 변수가 가장 높은 feature importance였으니 여기서부터 나올 수 있는게 뭐가 있을까 고민하다가 전용면적별 type (area type), 전용면적 대비 거래량 -> 이걸 통해서 거래량에 대해 생각할 수 있게 되었고 거래량 표준편차, 최근 3년동안의 거래량, 3년동안의 가격 변화율 등등 정말로 많은 파생변수들을 만들어 낼 수 있게 되었다. 궁극적으로 이 파생변수들이 엄청나게 모델을 향상된것은 아니었지만 그래도 꽤나 유의미한 결과를 얻을 수 있었고 이 작업을 통해 그룹 자체적으로 베이스라인 코드를 만들어 낼 수 있었다.

이 결과값을 토대로 다른 팀원들에게 베이스라인 코드로 사용 및 다른 좋은 파생변수가 있으면 추가하고 (다른 팀들도 상위권은 15000대였기 때문에) 다른 모델 (catboost, lightgbm, xgboost 등) 있으면 각자 테스트해보고 공유하기로 결정하였다. 나는 저 rmse값에서 가장 성능이 좋게 나온건 xgboost였고(optuna 라이브러리사용) 앙상블을 시도해봤을 때 오히려 local rmse값이 올라가는 현상을 보았다. 몇일동안 밤을 새가면서 피처 엔지니어링 및 하이퍼파리미터 조절을 하다보니 시간적 여유가 없었는지 일단 그나마 가장 좋은 하이퍼파리미터를 찾은게 xgboost였고 결국 여기서 조정하면서 나온게 최종값중 하나이다.

다른 팀원들의 외부데이터를 끌어온 파생변수는 생각보다 rmse값을 내리는 데는 유효하진 못했고( ex. 기준금리, 공원데이터 등) 개인적인 생각으로는 영향이 분명히 있을텐데 제대로 반영을 못하는건지 나중에 좀더 고민해봐야겠다고 느꼈다.
그러다가 마지막에 정말 최종버전 1의 비슷한 결과를 다른 팀원이 lightgbm으로 이끌어낸 결과가 있었는데 내가 lightgbm의 하이퍼파라미터를 제대로 조절 못하는 것이었는지 꽤나 xgboost랑 비슷한 결과값이 나왔고(최종적으로는 final rmse값은 좀더 낮게 나왔다.) 시간부족으로 인해 그 팀원분의 모델이랑 앙상블 해보지 못한것이 정말로 마지막에 아쉬운 부분이었던 것 같다.

분명 모든 팀원들도 다 열심히 했고 나도 정말 몇일 밤새가면서 진행하면서 재밌기도 했지만 정말 사소한 점수 차이로 등수가 결정되다 보니까 엄청 지친다는 느낌을 받았다. 경연대회를 진행하면서 결론적으로 나온 우리 팀의 feature importance는 다음과 같다. (우리는 permutation importance를 조금더 중요하게 봤다.)

하루 전날에 public score는 2등이었지만 마지막에 public도 4등 > private도 4등으로 마무리 하게 되었다. 딱 중위권이어서 목표했던 상위권보단 약간 아쉬운 결과지만 그래도 처음 해보는 경연대회였기 때문에 정말 많은 부분을 배울 수 있었다고 생각한다. 무엇보다도 Feature engineering에서 정말 많은 시간을 투자해야한다는 것을 느꼈고 모델 테스트를 vpn으로 gpu server에서 돌려본것도 처음이었기에 귀중한 경험이었다고 생각하고 다음 있을 경진대회에서는 조금 더 상위권을 목표로 준비할 것이다. 그리고 마지막 날에는 만날 수 있는 사람들끼리 모여서 ppt를 준비했는데 화상으로밖에 회의를 할 수밖에 없던 부분에서 오프라인을 통해 이번 경연대회에서 느낀점을 공유하기도 하고 조금 더 친해질 수 있었던 기회라고 생각하고 네트워크를 넓힐 수 있었다. (번외로 이번 1등한 팀은 외부데이터를 포함해 엄청난 도메인 지식을 갖춘 사람이 있었고 당연히 1등할수 밖에 없었다라고 생각한다..)

'AI' 카테고리의 다른 글
| <9일차> MLops Project... (2) | 2024.10.11 |
|---|---|
| <8일차> Mlflow, FastApi, Bertmodel, Airflow ... (2) | 2024.09.25 |
| <6일차> LLM Project : 스포츠 규정에 관하여 답하는 QA Engine 개발 (3) | 2024.08.27 |
| <5일차> Statistics (0) | 2024.08.23 |
| <4일차> Git (0) | 2024.08.09 |