Code › ai-engineering-study
자전거 대여량 예측에서 EDA가 먼저였던 이유
Bike Sharing Demand 데이터를 탐색하며 변수의 맥락과 모델 선택의 차이를 확인한 미션 기록
오늘 Codeit 세 번째 미션을 마무리했다. Kaggle Bike Sharing Demand 데이터로 자전거 대여량을 예측하기 위해 EDA부터 전처리, 모델 학습, 리포트 작성까지 진행하는 과제였다. 나름대로 데이터를 살펴보고 여러 모델의 성능도 비교했는데, 강사님 풀이에서는 모델을 학습하기 전에 확인하는 항목이 훨씬 다양하고 인사이트가 좋았다.
나는 예측 성능을 높이는 쪽으로 빠르게 넘어갔고, 강사님은 변수 하나를 사용하거나 제외하기 전에 그 값이 실제로 무엇을 나타내는지 더 깊이 확인하였다.
내가 먼저 진행한 접근
먼저 날짜와 시간에서 연도, 월, 일, 시각, 요일 같은 값을 분리하고, 시간대와 온도, 체감온도, 습도, 풍속, 근무일 여부 등을 입력 변수로 사용했다. 예측할 대상은 자전거 대여량이었다. 시간대별 분포를 평일과 주말로 나눠 보니 평일에는 출근과 퇴근 시간에 대여량이 크게 늘었고, 주말에는 낮 시간대 전반으로 수요가 넓게 퍼졌다. 같은 시각이라도 근무일 여부에 따라 이용 목적이 다르다는 사실을 먼저 확인할 수 있었다.
온도와 체감온도는 대여량과 함께 증가하는 흐름을 보였고, 습도가 높거나 날씨가 나빠질수록 대여량은 줄었다. 전체 상관관계만 확인하고 끝내지 않고, 평일과 주말처럼 성격이 다른 조건을 나눠 그래프를 다시 그려 봤다. 자전거 이용량은 한 변수만으로 결정되지 않고 시간대, 근무일, 계절, 날씨가 함께 작용하기 때문이다.
범주형 변수에는 One Hot Encoding을 적용했고, 오른쪽으로 길게 치우친 대여량에는 log1p 변환을 사용했다. 평가지표는 RMSLE로 지정 되어 있었는데 찾아보니 캐글에 요구사항이 RMSLE였다. 데이터를 보다가 풍속이 조금 이상했는데, 풍속이 0인 값은 실제로 무풍 상태라기 보다는 결측치 일 수 있다는 가정을 세우고 중앙값으로 대체해 보기도 했다.
내 실험에서는 선형회귀와 규제 모델인 Ridge, Lasso의 성능은 비슷했고, 선형 모델의 RMSLE가 약 0.5814이었다. 수치가 높게 나온 이유를 앞의 데이터에서 다시 찾아봤어야 했는데 다른 모델은 어떻게 나오는지부터 찾아봤고, 아직 수업에서 배우지 않은 트리 기반 모델인 RandomForest와 XGBoost를 적용했는데 XGBoost가 약 0.31이 나왔다. 찾아보니 시간대와 근무일, 날씨가 결합해서 만드는 패턴을 하나의 직선 관계로 표현하는 데 한계가 있을 수 있는데 XGBoost는 조건에 따라 데이터를 나누면서 이런 비선형 관계를 반영할 수 있다고 한다. 그래서 조금 솔깃 하면서 해봤는데 본질은 수업 때 배운 선형회귀 방식의 성능을 높여야 했다.
그래프를 보다가 풍속 상위 구간에서 평균 대여량이 갑자기 높아지는 현상도 발견했다. 50m/s 구간이었는데 풍속이 강할수록 자전거를 많이 탄다는 결론은 납득하기 어려워서 해당 행을 직접 필터링했고, 그 구간에는 데이터가 네 건밖에 없었다. 그 중에 300건의 대여가 찍혀있는 row가 있었는데, 아무래도 이건 시속 180km의 속도의 바람이 불어서 차도 뒤집히는 재난상태인데 자전거를 빌린다는게 이해가 안갔다. 그래서 이 값도 별도 처리하기로 했다.
분석 결과를 결국 비즈니스에서 어떤 사후처리를 할 수 있을지 이어봐야 했는데, 평일 출퇴근 전에는 역세권과 주거지의 자전거를 미리 재배치하고, 주말 낮에는 공원과 강변의 보유량을 늘리는 식이다. 비가 오거나 습도가 높아 수요가 낮을 것으로 예상되는 날은 정비 시간을 확보하는 등의 시간효율화를 꾀할 수 있다.
강사님의 미션 풀이에서 본 흐름
강사님 풀이에서는 모델을 만들기 전에 전처리와 EDA를 더 깊게 들어갔다. 평일과 주말의 이용 패턴을 먼저 분리했고, 박스플롯으로 습도와 풍속의 이상치를 확인한 뒤 필터링 전후의 분포도 비교했다. 이상치를 발견했다고 바로 삭제하지 않고, 실제로 잘못 수집된 값인지 드물지만 가능한 상황인지 확인하는 순서였다.
season 값도 이름만 보고 그대로 사용하지 않았다. 각 범주에 들어 있는 날짜의 최솟값과 최댓값을 확인해 보니 하나의 계절로 묶기 애매한 구간이 있었고, 실제 날짜 범위를 기준으로 계절을 다시 정의했다. 데이터에 이미 들어 있는 범주라고 해서 그 의미까지 정확하다고 가정하면 안 된다는 인사이트를 얻었다. 무조건 의심을 한번 해보고 데이터를 직접 확인해보자!
계절이 바뀌는 구간과 날씨 상태가 달라지는 구간의 대여량도 따로 확인했고, 온도와 습도 등 여러 조건을 묶어 대여량이 높은 기후 조건을 찾아봤다. 이 전이 분석은 내가 처음 진행한 내용이 아니라 강사님 풀이에서 본 접근이다. 전체 평균만 보면 사라지는 변화를 조건이 달라지는 시점에 맞춰 다시 살펴본 것이다.
모델링 단계에서도 순서가 달랐다. 입력 변수와 대여량을 정한 뒤 범주형 변수를 One Hot Encoding 인코딩했고, RMSLE를 직접 함수로 구현해 같은 기준으로 모델을 비교했다. 상관관계가 낮은 변수는 제외하는 것이 학습 효율이 좋고, EDA에서 세운 판단을 실제 모델 성능으로 다시 확인하는 과정까지 이어졌다.
결론 및 회고
나는 데이터를 빠르게 모델에 넣어 선형 모델과 트리 모델의 차이를 확인했고, 풍속 그래프에서 이상한 결과가 나오자 데이터를 조금 더 살펴보고 원인을 찾았지만, 강사님은 모델을 학습하기 전에 변수의 분포와 이상치, 범주의 날짜 범위, 조건 전이를 순서대로 확인하며 하나씩 격파해나갔다.
이번 미션에서 부족했다고 느낀 부분은, 그래프를 그린 다음 어떤 조건으로 다시 나눠서 분석 해 볼지, 이상한 값이 나오면 어떤 원본 데이터를 확인할지, 변수를 제거했을 때 성능이 실제로 달라지는지 등의 의문과 고찰이 부족했던 것 같다. 다음 EDA에서는 상관관계 수치나 모델 점수를 바로 결론으로 사용하지 않고, 표본 수와 조건별 분포, 변수 정의를 먼저 확인하려고 한다.