본문 바로가기
머신러닝 대회 풀이

[ML 대회 해설] Dacon 아파트 실거래가 예측 AI 경진대회 2등 풀이 - EDA (1): Numeric Feature EDA

by 미역청 2025. 1. 11.

오늘은 저번 포스트에서 뽑은 Numeric feature 들의 feature 중요도를 기반으로 본격적인 EDA에 들어가겠습니다.

 

지난 글 

https://here-lives-mummy.tistory.com/15

 

[ML 대회 해설] Dacon 아파트 실거래가 예측 AI 경진대회 7등 풀이 - 소개 (2): Numeric Feature 톺아보기

저번 포스트에 이어, 이번 포스트에선 주요 Feature와 Numeric feature의 개요를 간단히 살펴보겠습니다. 지난 글https://here-lives-mummy.tistory.com/10 [ML 대회 튜토리얼] Dacon 아파트 실거래가 예측 AI 경진대

here-lives-mummy.tistory.com


Feature 중요도 분석

XGBoost, CatBoost의 Feature 중요도는 다음과 같았습니다: 

1. exclusive_use_area
2. year_of_completion
3. apartment_id
4. transaction_year_month
5. floor

이전 포스트에서 제가 " 일반적으로 target feature와 높은 상관관계를 갖는 feature가 모델의 성능을 개선할 가능성이 높다" 고 한 적이 있는데요,

같은 원리로

보통 Feature 중요도가 높은 Feature, 상관계수가 높은 Feature 를 활용하면 좋은 파생 Feature를 만들 수 있습니다.

 

따라서 오늘은 Feature 중요도 순서로 EDA를 해보겠습니다.

 

주의: 물론 이렇게 만든 모든 Feature가 좋은 결과를 낳는 것도 아니고 중요도나 상관계수가 낮은 Feature를 engineering하는 것이 무의미 한 것도 아닙니다! 중요도 및 상관계수가 낮은 Feature는 추후에 보겠습니다.

 

Numeric Feature EDA

0. 전체 데이터

이야기에 앞서, 전체 데이터 수와 우리가 궁극적으로 예측하고자하는 target feature의 분포를 보겠습니다.

 

trainset이 약 120만건, testset이 5,463건입니다.

이 정도 사이즈는 CPU로 모델을 학습시킬 시 상당히 오랜 시간이 소요되기 때문에 GPU 사용을 고려해봐야합니다.

LGBM은 현재 GPU 모드가 불안정하여, XGBoost hist mode와 CatBoost에만 GPU 모드를 사용해주겠습니다.

 

1. Target Feature

[표 1] numeric feature 들의 값 분포.

min값은 100이고, max값은 820,000이며, 평균은 38,228 정도 됩니다.

원 단위라기에는 집값치곤 저렴하여 찾아보니 만 원 단위라고 합니다.

 

값 분포를 그래프로 표현해보겠습니다.

target feature 분포와 y = -xe^x 그래프

전체적으로 좌측에 치우쳐있고, 오른쪽으로 길게 꼬리가 남아있는 형태입니다.

잘 보면 약간 y = -xe^x 그래프와도 닮았습니다. 

 

여기서 저는 target feature에그를 씌운다면 정규분포에 더 가깝게 표현할 수 있을 것 이라는 아이디어를 얻었습니다.

 

 

logscale을 씌워 다시 분포를 찍어보겠습니다.

*주의: Target값이 0일 때에 대비해 log가 아닌, log1p ( =log(x+1) ) 함수를 씌워야합니다. prediction값에는 역함수인 expm1 ( = e^(x-1) )를 씌우는 것도 잊지 말아야 하고요. 

target에 log1p를 씌웠을 때의 분포

실제로 정규분포에 가까운 형태를 보입니다.

 

일반적으로 머신러닝 모델의 경우, target의 분포가 고를수록 좋은 성능을 보입니다.

그러므로 target이 편향된 데이터라도, 전처리를 통해 그 분포를 조정한다면 모델의 성능을 대폭 향상하기도 합니다.

 

딥러닝에서는 보통 normalize를 하는데요,

Boosting 계열 모델을 사용한 머신러닝 대회에서는 이런 로그/지수함수 씌우기를 더 많이 사용합니다.

 

따라서, 저는 target에 np.log1p()를 씌워 모델이 log값을 예측하게 한 뒤 그 값에 다시 np.expm1()을 씌워보겠습니다.

 

Insight 2-1. target에 log를 씌우면 성능이 개선될 수도 있다.
참고 +)
Q. 딥러닝에서 로그/지수 함수를 씌워도 모델의 성능이 향상되는가?
A. 그렇지 않습니다. 딥러닝 모델에서는 일반적으로 로그/지수 함수를 씌우면 성능이 대폭 하락합니다.
이러한 현상은 특히 Vision 분야에서 많이 볼 수 있는데요,
이는 어떠한 값을 기준으로 이진분류를 하는 Boosting 모델과 달리, raw data로부터 predict function을 그려 예측을 수행하는 딥러닝 특성상 노이즈에 민감하기 때문으로 보입니다.

logscale을 씌우면 소숫점 아래의 값들은 더욱 증폭되지만 10, 1000 단위의 큰 숫자는 그만큼 영향력을 잃게 됩니다.
Boosting 모델의 경우 그 덕에 소숫점 n째자리까지 더 디테일한 분류기준값을 정할 수 있게 되지만
딥러닝 모델에선 오히려 중요한 값을 잃고 노이즈만 학습하는 결과로 이어질 수 있는 것입니다.

 

2. Exclusive_use_area

상단의 [표 1]에 따르면

min값은 9.26이고, max값은 424.32이며, 평균은 78.17 정도 됩니다.

단위는 제곱미터로 예상됩니다.

 

unique값은 16,856으로, trainset의 전체건수가 120만건인 것을 감안하면 적은 수가 아닙니다.

 

해당 feature의 값 분포 표와, 값의 변화에 따른 target 값 변화를 표로 그려보겠습니다.

exclusive_use_area의 count distribution 그래프, exclusive_use_area에 따른 target 값 변화 그래프

전체적으로 데이터가 한두 값에 몰려있고, 그 주변으로 비슷한 값들이 조금씩 분포하고 있습니다.

특히 exclusive_use_area값이 조금 변화함에 따라 target 값 역시 크게 변화하는, 이른바 노이즈가 낀 모습을 보입니다.

 

이를 해결하기 위해 exclusive_use_area값에서 소숫점 혹은 일의자리 까지를 반올림해보겠습니다.

exclusive_use_area를 소수점 첫째자리에서 반올림한 그래프

이전보다 노이즈가 정리된 모습을 보입니다.

따라서, 적절한 자리에서 exclusive_use_area 값을 반올림/버림/올림하면 더 좋은 결과를 기대할 수 있을 것입니다.

 

Insight 2-2. exclusive_use_area를 적절한 자리에서 반올림/버림/올림 하여 노이즈를 제거한다.

 

또한, 집값을 exclusive_use_area로 나누어 평당가격 feature를 만들어볼 수도 있을 것입니다.

같은 평수라도 지역, 아파트에 따라 집값이 달라질 수 있으니 성능개선을 기대해볼 수도 있을 것으로 보입니다.

 

Insight 2-3. Target Feature / exclusive_use_area = 평당가격 feature을 만들어볼 수 있을 것이다.

 

3. Year_of_completion

상단의 [표 1]에 따르면

min=1961,  mean=1999, max=2017입니다.

이 데이터셋이 2008~2017년도 거래를 다루는 것을 감안하면 정상적인 범위입니다.

특이하게 완공 전에 판매된 매물이 있는데요, 잘못 기입되었을 수 있으니 해당 주소의 아파트 year_of_completion 값을 모두 찾아보겠습니다.

다른 데이터에서도 모두 2009년으로 표기되어있습니다.

여기서 다음과 같은 가설을 세울 수 있을 것입니다.

1. 이 아파트의 year_of_completion 이 전부 잘못 표기됨

2. transaction_year_month (=판매일)이 잘못 표기됨

3. 완공 이전에 거래된 매물

 

어느 쪽이든, 우리가 가진 데이터 만으로는 확인하기 어려운데다

전체 데이터 중 3건밖에 되지 않으므로 현재로선 넘어가겠습니다.

 

저는 여기서 transaction_year_month에서 transaction_year만 추출한 후, (transaction_year - year_of_completion) 을 수행해 거래 당시의 아파트 연식을 파생 feature로 만들 수 있다고 추측하였습니다.

Insight 2-4. transaction_year - year_of_completion = 아파트연식 을 파생 feature로 만들 수 있을 것이다.

 

4. Apartment_id

각 아파트별로 id를 부여한 것입니다.

 

같은 동네, 같은 아파트지만 id가 다르게 부여된 곳이 있습니다.

확인해보면 도로명주소가 다른데, 이를 통해 단순 아파트 이름이 아닌 도로명주소까지 반영하여 아파트를 위치 별로 엄밀하게 나누어 매긴 번호임을 알 수 있습니다.

 

그런데, 어떤 순서로 번호를 매겼을까요?

 

apartment_id와 같이, categorical 데이터를 label encoding 해놓은 feature들은 어떠한 기준으로 순서를 매겼는지를 확인해볼 필요가 있습니다.

만약 apartment_id가 다른 feature 기준으로 라벨링되어있다면 (=종속적이라면) 때에 따라선 오히려 학습에 overfitting으로서 작용할 수도 있기 때문입니다.

특히 target의 오름차순/내림차순을 기준으로 라벨링되어있다면, 학습 과정에서 일종의 data leakage로서 작용하여, train/test 중에는 높은 성능을 내는 데에 큰 기여를 하지만 막상 대회에 제출을 해보면 낮은 점수가 나오는, 모델 성능을 갉아먹을 가능성도 있기에 매우 위험합니다. 

 

apartment_id 오름차순으로 데이터를 정렬해보았습니다.

df = train.copy()
df = df.sort_values(by='apartment_id', ascending=True)
df.head(20)

df = train.copy()
df = df.sort_values(by='apartment_id', ascending=True)
df.tail(20)

라벨링에 마땅한 규칙을 발견할 수 없습니다.

그나마 dong을 기준으로 그룹핑 되어있는 형태를 발견할 수는 있으나, 확인해보면 기존 dong 정렬 순서와 완전히 부합하지도 않습니다.

 

실제로 apartment_id 별로 데이터를 그룹핑한 후, 한 apartment_id에 서로 다른 동이 분포한 경우가 있나 살펴보면, 없는 것을 알 수 있습니다.

 

Insight 2-5. apartment_id는 target feature 기준으로 그룹핑된 것이 아니기에 상대적으로 성능을 대폭 하락시킬 확률이 매우 낮다.

 

5. Transaction_year_month

"yyyymm" 형식으로 표현되어있습니다.

 

상단의 [표 1]에 따르면

min=200801,  median=201312, max=201711입니다.

 

해당 feature는 각각 transaction_year, transaction_month로 나누어 별도의 파생 feature로 만들 수 있을 것으로 보입니다.

Insight 2-6. transaction_year_month를 각각 transaction_year, transaction_month로 나눌 수 있을 것이다.


6. Floor

상단의 [표 1]에 따르면

min=-4,  mean=8, max=80입니다.

마이너스값을 갖는 층이 있습니다.

train[train.floor < 1]

floor 가 1 미만인 거래를 출력한 것

궁금해서 이 중 몇몇 매물을 직접 검색해보았는데요,

반지하/지하이거나, 산 중턱에 증축하여 음수층으로 표기되지만 실제로는 지상인 경우도 있었습니다.

이상치는 아닌듯하여 보정할 필요가 없을 것 같습니다.

 

결론

지금까지 numerical feature를 EDA하며 얻은 아이디어를 정리하면 다음과 같습니다: 

Insight 2-1. target에 log를 씌우면 성능이 개선될 수도 있다.
Insight 2-2. exclusive_use_area를 적절한 자리에서 반올림/버림/올림 하여 노이즈를 제거한다.
Insight 2-3. Target Feature / exclusive_use_area = 평당가격 feature을 만들어볼 수 있을 것이다.
Insight 2-4. transaction_year - year_of_completion = 아파트연식 을 파생 feature로 만들 수 있을 것이다.
Insight 2-5. apartment_id는 target feature 기준으로 그룹핑된 것이 아니기에 상대적으로 성능을 대폭 하락시킬 확률이 매우 낮다.
Insight 2-6. transaction_year_month를 각각 transaction_year, transaction_month로 나눌 수 있을 것이다.

 

추후 이 정보들을 사용해 파생 feauture을 만들거나, 이상치/결측치를 보정하는 feature engineering을 수행해 모델의 성능을 높여볼게요.

 

 


 

다음 글에서는 object type feature인 city, dong, jibun, apt, addr_kr, transaction_date 의 EDA를 수행해보겠습니다!

다음 글:

 

[ML 대회 해설] Dacon 아파트 실거래가 예측 AI 경진대회 2등 풀이 - EDA (3): Object type Feature EDA

이번 포스트에선 object type feature의 EDA를 수행해보겠습니다.  지난 글:  [ML 대회 해설] Dacon 아파트 실거래가 예측 AI 경진대회 3등 풀이 - EDA (1): Numeric Feature EDA오늘은 저번 포스트에서 뽑은 Numer

here-lives-mummy.tistory.com

 

 

도움이 되었다면 하트 눌러주세요 :)

구독하시면 더 많은 데이터사이언스 정보와 대회풀이를 보실 수 있습니다!