WIL

내배캠 TIL 38일차

ColorConeHead 2024. 2. 13. 21:55
반응형

심화 프로젝트 관련

1) 결측치 대치

2) 이상치 제거


4분위수를 사용한 방법은 유실 데이터가 너무 많아 기각.

EDS를 사용한 방법 채택.
def remove_outliers(train_df, col, threshold=3):
    mean = np.mean(train_df[col])
    std_dev = np.std(train_df[col])
    lower_bound = mean - threshold * std_dev
    upper_bound = mean + threshold * std_dev
    train_df= train_df[(train_df[col] >= lower_bound) & (train_df[col] <= upper_bound)]
    return train_df

numeric_col = ['대출금액', '연간소득', '부채_대비_소득_비율', '총계좌수', '최근_2년간_연체_횟수', '총상환원금', '총상환이자', '총연체금액', '연체계좌수', '근로기간']
category_col = ['대출기간', '주택소유상태', '대출목적']

for col in numeric_col:
    df_simple = remove_outliers(df_simple, col, threshold=3)​

 

 

 

3) 스캐일링


numeric_col 컬럼 중에서 히스토그램의 개형을 토대로

sc_col = ['최근_2년간_연체_횟수', '총연체금액', '연체계좌수']
mm_col = ['대출금액', '연간소득', '부채_대비_소득_비율', '총계좌수', '총상환원금', '총상환이자', '근로기간']

위와 같이 스캐일링 방법을 정함.
from sklearn.model_selection import train_test_split

X = df.drop(['ID', '대출등급'], axis=1)
y = df[['대출등급']]

def numeric_scaler(X):
    
    sc_col = ['최근_2년간_연체_횟수', '총연체금액', '연체계좌수']
    mm_col = ['대출금액', '연간소득', '부채_대비_소득_비율', '총계좌수', '총상환원금', '총상환이자', '근로기간']
    
    from sklearn.preprocessing import StandardScaler, MinMaxScaler
    
    sc = StandardScaler()
    mm = MinMaxScaler()
    
    X[sc_col] = sc.fit_transform(X[sc_col])
    X[mm_col] = mm.fit_transform(X[mm_col])
    
    return X

X = numeric_scaler(X)

 

 

4) 인코딩


category_col = ['대출기간', '주택소유상태', '대출목적']
에서 우위를 따질 컬럼은 없어 보이기에 onehot 인코딩으로 통일.

종속변수 y, 대출등급은 Label 인코딩을 사용.
def category_encoder(X:pd.DataFrame):
     X_dummies = pd.get_dummies(X[category_col])
     
     X = pd.concat([X, X_dummies], axis=1)
     
     return X, X_dummies.columns.to_list()

X, dummies_col = category_encoder(X)

from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
le.fit(y['대출등급'])

y['대출등급'] = le.transform(y['대출등급'])​

 

 

5) 오버 샘플링


확인 결과 대출 등급이 낮은 데이터가 현저히 적다.
오버샘플링을 통해 보완한다.

오버샘플링을 위해 인코딩 먼저 하고 스캐일링을 진행.
이후 파생변수를 생성한다.
X = df.drop(['ID', '대출등급'], axis=1)
y = df[['대출등급']]

X, dummies_col = category_encoder(X)
X = X.drop(columns=category_col)

from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
le.fit(y['대출등급'])

y['대출등급'] = le.transform(y['대출등급'])

from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=42)

X, y = sm.fit_resample(X, y)

X = numeric_scaler(X)

### 대출 등급별 category_col 분포 특성을 반영
X['dv_category'] = ((2 * X['대출기간_ 36 months']) + X['주택소유상태_MORTGAGE'] + X['대출목적_부채 통합']) / 4

### 대출금액 대비 총상환원금(0인 값 처리를 위해 +1)
X['dv_ratio'] = (X['총상환원금'] + 1) / (X['대출금액'] + 1)

### 단기상환능력
X['dv_short_ability'] = (X['연간소득'] / 12) - (X['대출금액'] / 36)

### 잔여대출금
X['dv_left_debt'] = X['대출금액'] - X['총상환원금'] - X['총상환이자']

### 대출 금액 대비 총상환금 비율
X['dv_rent_p'] = X['총상환원금'] / X['대출금액']
X['dv_rent_i'] = X['총상환이자'] / X['대출금액']

dummies_col = dummies_col + ['dv_category']
numeric_col = numeric_col + ['dv_ratio', 'dv_short_ability', 'dv_left_debt', 'dv_rent_p', 'dv_rent_i']

 

 

6) 모델링


여러 모델을 돌려보고 점수가 잘 나오는 모델로 선정.
def get_score(train:pd.DataFrame,  test:pd.DataFrame, x_var_list:list):
    
    X_train = train 
    X_test = test

    X_train = X_train[x_var_list]
    X_test = X_test[x_var_list]
    
    from sklearn.linear_model import LogisticRegression
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
    from xgboost import XGBClassifier
    from lightgbm import LGBMClassifier
    from sklearn.metrics import f1_score, accuracy_score
    
    logit = LogisticRegression()
    decision = DecisionTreeClassifier(random_state=42)
    rfc = RandomForestClassifier(random_state=42)
    gbc = GradientBoostingClassifier(random_state=42)
    xgb = XGBClassifier(random_state=42)
    light = LGBMClassifier(random_state=42)
    
    logit.fit(X_train, y_train)
    decision.fit(X_train, y_train)
    rfc.fit(X_train, y_train)
    gbc.fit(X_train, y_train)
    xgb.fit(X_train, y_train)
    light.fit(X_train, y_train)
    
    y_pred_train = logit.predict(X_train)
    y_pred_test = logit.predict(X_test)
    
    result_logit = pd.DataFrame({'acc' : [accuracy_score(y_train, y_pred_train), accuracy_score(y_val, y_pred_test)],
                            'f1_score' : [f1_score(y_train, y_pred_train, average='macro'), f1_score(y_val, y_pred_test, average='macro')]},
                            index = ['train','test'])
    
    y_pred_train = decision.predict(X_train)
    y_pred_test = decision.predict(X_test)
    
    result_decision = pd.DataFrame({'acc' : [accuracy_score(y_train, y_pred_train), accuracy_score(y_val, y_pred_test)],
                            'f1_score' : [f1_score(y_train, y_pred_train, average='macro'), f1_score(y_val, y_pred_test, average='macro')]},
                            index = ['train','test'])
    
    y_pred_train = rfc.predict(X_train)
    y_pred_test = rfc.predict(X_test)
    
    result_rfc = pd.DataFrame({'acc' : [accuracy_score(y_train, y_pred_train), accuracy_score(y_val, y_pred_test)],
                            'f1_score' : [f1_score(y_train, y_pred_train, average='macro'), f1_score(y_val, y_pred_test, average='macro')]},
                            index = ['train','test'])
    
    y_pred_train = gbc.predict(X_train)
    y_pred_test = gbc.predict(X_test)
    
    result_gbc = pd.DataFrame({'acc' : [accuracy_score(y_train, y_pred_train), accuracy_score(y_val, y_pred_test)],
                            'f1_score' : [f1_score(y_train, y_pred_train, average='macro'), f1_score(y_val, y_pred_test, average='macro')]},
                            index = ['train','test'])
    
    y_pred_train = xgb.predict(X_train)
    y_pred_test = xgb.predict(X_test)
    
    result_xgb = pd.DataFrame({'acc' : [accuracy_score(y_train, y_pred_train), accuracy_score(y_val, y_pred_test)],
                            'f1_score' : [f1_score(y_train, y_pred_train, average='macro'), f1_score(y_val, y_pred_test, average='macro')]},
                            index = ['train','test'])
    
    y_pred_train = light.predict(X_train)
    y_pred_test = light.predict(X_test)
    
    result_light = pd.DataFrame({'acc' : [accuracy_score(y_train, y_pred_train), accuracy_score(y_val, y_pred_test)],
                            'f1_score' : [f1_score(y_train, y_pred_train, average='macro'), f1_score(y_val, y_pred_test, average='macro')]},
                            index = ['train','test'])
    
    print('로지스틱')
    display(result_logit.round(2))
    print()
    print('의사결정나무')
    display(result_decision.round(2))
    print()
    print('랜덤포레스트')
    display(result_rfc.round(2))
    print()
    print('그라디언트 부스팅')
    display(result_gbc.round(2))
    print()
    print('XG 부스팅')
    display(result_xgb.round(2))
    print()
    print('Light GBM')
    display(result_light.round(2))

get_score(X_train, X_val, dummies_col + numeric_col)​
기본 골조는 여기서 바뀌지 않을 듯 하다.

후에 나온 결과들을 가지고 파생변수를 추가한다던지 정도?

지금까지의 결과는 다음과 같다.

1) 중위 등급을 잘 분류하지 못한다.
2) 파생변수 dv_rent_i가 중요도가 높은데 이는 상환이자, 즉 이자율을 반영한 것으로 보임.
반응형