반응형
심화 프로젝트 관련
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가 중요도가 높은데 이는 상환이자, 즉 이자율을 반영한 것으로 보임.
반응형
'WIL' 카테고리의 다른 글
내배캠 WIL 11주차 (0) | 2024.03.08 |
---|---|
내배캠 WIL 10주차 (3) | 2024.02.29 |
내배캠 WIL 8주차 (0) | 2024.02.08 |
내배캠 WIL 7주차 (0) | 2024.02.02 |
내배캠 6주차 WIL (0) | 2024.01.26 |