티스토리 뷰

반응형

[주제]

개인 특성 데이터를 활용하여 개인 소득 수준을 예측하는 AI 모델 개발

정형 회귀

 

1. 평가

  • 평가산식 : RMSE
  • Public Score: 전체 테스트 데이터 중 30%
  • Private Score: 전체 테스트 데이터 중 70%

 

2. AutoML 패키지

  • 모든 AutoML 패키지 사용 불가능

3. 유의 사항

  • 1일 최대 제출 횟수: 3회
  • 사용 가능 언어: Python, R

그간의 5만 달러 정도로 Classification하여 이진분류하는 소득 예측 모델과 달리, 정형 회귀 문제로서 접근할 수 있는 문제라 시도해보기로 마음먹었다.

 

최종 Public Score는 69위로, 제출한 전체 773팀 중에서 상위 8.9%에 들었다.

 

First Step - EDA

피처 요약표를 살펴 보았을 때, 대부분의 피처가 명목형으로 되어 있다는 점을 알 수 있었다.

 

이 중에서 income은 타깃값, ID는 모델링에 쓸모 없는 값이니, 사실상 숫자로 쓸 수 있는 피처는

Age, Working_Week, Gain,Losses,Dividends 정도였다.

 

그렇기에 해당 피처들은 간단한 단변량 분석을 거친 후에, 일단 피어슨 상관분석부터 해보았다.

 

숫자형 변수

 

예상대로, Income과 working_week은 상관관계가 어느정도 있음을 확인했다.

 

그러나 Gain, Losses, Dividends는 그렇지 않아서, 셋은 하나의 Profit으로 묶어줄 생각을 하고 들어갔다.

 

 

 

결과는 이렇게 나왔다.

그러나 모델링에서 딱히 영향이 있진 않았다.

 

어느정도 고르게 분포가 되어 있는 age와 working week
반면 Gain은 그렇지 않았다. 비슷한 나머지 두 피처도 마찬가지

 

명목형 변수

명목형 변수는 하도 많아서, 아예 그래프를 만들어 주는 게 훨씬 보기 쉬울거라 생각해 그냥 다 묶어주었다.

 

 

보게 되면 딱 봐도 Birth_country와, house hold status, Education status, Industry status 등이 고유값이 유난히 많다는 걸 볼 수 있다.

 

직접 실험해본 결과, 그대로 넣었을 때보다 적절하게 묶어줬을 때가 모델링에 훨씬 좋았다.

 

따라서 Birth_country 3 종류는 소득 별로 11개로 쪼개 나눠주었고, 그 결과가 맨 아래의 country bin 3개 피처이다.

훨씬 깔끔해진 것을 볼 수 있다.

 

다음과 같은 코드로 분산분석도 해 보았으나, 전부 유의미하다고 나와서 딱히 특이점은 발견하지 못했다.

import pandas as pd
import statsmodels.api as sm
from statsmodels.formula.api import ols

train3 =train.rename(columns={'Birth_Country (Father)':'Birth_Country_F',
 'Birth_Country (Mother)':'Birth_Country_M'})
# 범주형 변수를 범주형 데이터 타입으로 변환
for cat in train3.columns:
    if train3[cat].dtype == object and cat!='ID':
        train3[cat] = train3[cat].astype('category')

        # ANOVA 모델 정의
        model = ols(f'Income ~ C({cat})', data=train3).fit()

        # ANOVA 테이블 출력
        anova_table = sm.stats.anova_lm(model, typ=2)
        print(anova_table)
        print('-'*100)

 

p-value가 대부분 0에 가까운 걸 볼 수 있다

추가적으로 숫자형 변수도 구간별로 묶어주었으나, 큰 소득은 없었다.

다만 working_week이 역시 올라갈수록 income도 올라간다는 확실한 결론과, age가 27~54(한창 일할 나이의 구간)이

Income이 높다는 인사이트가 있었다.

 

 

그렇게 education status, age까지 6단계로 최종적으로 묶어주고, 나온 결과적인 피처는 이렇게 되었다.

 

Age_level은 연령대이고, Gains와 Losses, Dividend는 profit으로 해보았으나 결과가 좋게 나오지 않아서 그냥 그대로 가기로 했다.

 

피처 선택 및 전처리

1. box-cox

아무래도 skewness가 좀 있다 보니, 숫자형 변수들에 대해서 box-cox tranform을 적용했다.

from scipy.stats import boxcox

def transform_data(train,test):
    df=train.copy()
    
    df_transformed = df.copy()
    test_transformed = test.copy()
    # 1. 훈련 데이터에서 Box-Cox 변환의 매개변수 계산
    lambda_dict = {}
    for col in df.columns:

        if df[col].dtype != object:
            skewness = df[col].skew()
            if abs(skewness) >= 0.5:
                _, lambda_ = boxcox(df[col])  # +1은 음수 값을 포함하여 Box-Cox 변환을 적용하기 위해
                lambda_dict[col] = lambda_

    # 2. 훈련 데이터 변환
    for col, lambda_ in lambda_dict.items():
        df_transformed[col] = boxcox(df[col], lmbda=lambda_)


    # 3. 테스트 데이터 변환
    for col, lambda_ in lambda_dict.items():
        test_transformed[col] = boxcox(test[col], lmbda=lambda_)
    #데이터 누수 없이 transform을 위해 lambda_를 이용
    
    return df_transformed,test_transformed

 

2. Ordinal Encoder, 및 One-Hot Encoding 적용

 

범주형 변수 중에서 묶어준 녀석들은 당연하게도 Income에 대한 순서가 있으므로, Ordinal Encoder를 적용해주었다.

 

나머지 범주형에 대해서 One-Hot Encoding을 적용하였다.

결과는 (20000, 88)

 

모델링

예상했던 대로 LGBM, 그리고 catBoost가 제일 잘 나왔다.

사진에서는 br,gbr,ridge에 대해서 밀리지만, 하이퍼 파라미터 튜닝을 진행한 결과로는 LGBM과 catboost가 Top1,2였다.

Tree 기반 최신 모델의 힘인 듯 싶다.

 

결과 

Cat+LGBM으로 각각 하이퍼파라미터 튜닝을 진행하여 Stack을 쌓았고,

결과적으로RMSE는 541이 되어 이는 Public score(전체 데이터의 30%)에서 100위권 정도 되었다.

 

하지만 Private(전체 데이터 70%)에서 셰이크업이 일어나서, RMSE 554.30385로 최종 순위는 69위가 되었다.

 

첫 데이콘 10%인 만큼 굉장히 뜻 깊은 결과인 거 같다.

확실히 정형 데이터는 어떻게 처리해야 할지 많이 감이 잡힌것 같다.

반응형