[ECC DS 3์ฃผ์ฐจ] 1. Start Here: A Gentle Introduction
0. Introduction: Home Credit Default Risk Competition
-
๊ณ ๊ฐ์ด ๋์ถ๊ธ์ ์ํํ ๊ฒ์ธ์ง ๋๋ ์ด๋ ค์์ ๊ฒช์ ๊ฒ์ธ์ง๋ฅผ ์์ธกํ๋ ๊ฒ์ ๋งค์ฐ ์ค์ํ ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ์
-
๋ํ ๋ชฉํ: ๊ณผ๊ฑฐ ๋์ถ ์ ์ฒญ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฒญ์๊ฐ ๋์ถ๊ธ์ ์ํํ ์ ์๋์ง ์ฌ๋ถ๋ฅผ ์์ธก
- ์ ํ์ ์ธ ๋ถ๋ฅ(Classification) ๋ฌธ์ ์
-
Supervised
-
label์ train data์ ํฌํจ๋์ด ์์
-
๋ชจ๋ธ์ด feature๋ฅผ ํตํด label์ ์์ธกํ๋๋ก ํ๋ ํ๋ จํ๋ ๊ฒ
-
-
Classification
-
label์ binary ๋ณ์์
-
0(๋์ถ์ ์ ๋ ์ํ) vs 1(๋์ถ์ ์ํํ๋ ๋ฐ ์ด๋ ค์์ด ์์)
-
0-1. Data ๊ตฌ์กฐ ํ์ ํ๊ธฐ
-
๋ฐ์ดํฐ๋ Home Credit์ ์ํด ์ ๊ณต๋จ
- ์ํ์ ๊ฐ์ ํ์ง ์์ ์ฌ๋๋ค์๊ฒ ์ ์ฉ๋์ถ(์ ์ฉ๋์ถ)์ ์ ๊ณตํ๋ ์๋น์ค
a) ๋ฐ์ดํฐ ์์ค
1. application_train/application_test
-
Home Credit์ ๊ฐ ๋์ถ ์ ์ฒญ์ ๋ํ ์ ๋ณด๊ฐ ํฌํจ๋ ์ฃผ์ train/test ๋ฐ์ดํฐ
-
๋ชจ๋ ๋์ถ์๋ ๊ณ ์ ํ ํ์ด ์์ผ๋ฉฐ
SK_ID_CURR
ํผ์ฒ๋ก ์๋ณ๋จ -
train ๋ฐ์ดํฐ์๋
target
์ด ํจ๊ป ์ ๊ณต๋จ-
0: ๋์ถ๊ธ ์ํ
-
1: ๋์ถ๊ธ ๋ฏธ์ํ
-
2. bureau
-
๋ค๋ฅธ ๊ธ์ต ๊ธฐ๊ด์ผ๋ก๋ถํฐ์ ๊ณ ๊ฐ์ ์ด์ ์ ์ฉ์ ๊ดํ ๋ฐ์ดํฐ
-
๊ฐ ์ด์ ํฌ๋ ๋ง์๋ ๊ณ ์ ํ ํ์ด ์ง์ ๋์ด ์์ง๋ง, ์์ฉ ํ๋ก๊ทธ๋จ ๋ฐ์ดํฐ์์ ํ๋์ ๋์ถ์ด ์ฌ๋ฌ ๊ฐ์ ์ด์ ํฌ๋ ๋ง์ ๊ฐ์ง ์ ์์
3. bureau_balance
-
์ฌ๋ฌด๊ตญ์ ์ด์ ํ์ ์ ๋ํ ์๋ณ ๋ฐ์ดํฐ
-
๊ฐ ํ์ ์ด์ ํฌ๋ ๋ง์ ํ ๋ฌ์ด๋ฉฐ, ์ด์ ํฌ๋ ๋ง ํ๋์๋ ํฌ๋ ๋ง ๊ธธ์ด์ ๊ฐ ๋ฌ์ ํ๋์ฉ ์ฌ๋ฌ ํ์ด ์์ ์ ์์
4. previous_application
-
์ ์ฒญ ๋ฐ์ดํฐ์ ๋์ถ์ด ์๋ ๊ณ ๊ฐ์ด Home Credit์์ ๋์ถ์ ์ํด ์ด์ ์ ํ ์ ์ฒญ
-
์ ํ๋ฆฌ์ผ์ด์ ๋ฐ์ดํฐ์ ๊ฐ ํ์ฌ ๋์ถ์๋ ์ฌ๋ฌ ๊ฐ์ ์ด์ ๋์ถ์ด ์์ ์ ์์
-
๊ฐ ์ด์ ์์ฉ ํ๋ก๊ทธ๋จ์๋ ํ๋์ ํ์ด ์์ผ๋ฉฐ
SK_ID_PREV
feature๋ก ์๋ณ๋จ
5. POS_CASH_BALANCE
-
๊ณ ๊ฐ์ด Home Credit์์ ๋ณด์ ํ ์ด์ ํ๋งค ์์ ๋๋ ํ๊ธ ๋์ถ์ ๋ํ ์๋ณ ๋ฐ์ดํฐ
-
๊ฐ ํ์ ์ด์ ํ๋งค ์์ ๋๋ ํ๊ธ ๋์ถ์ ํ ๋ฌ์ด๋ฉฐ, ํ๋์ ์ด์ ๋์ถ์๋ ์ฌ๋ฌ ํ์ด ์์ ์ ์์
6. credit_card_balance
-
๊ณ ๊ฐ๋ค์ด ํ ํฌ๋ ๋ง์ ๊ฐ์ง๊ณ ์๋ ์ด์ ์ ์ฉ์นด๋์ ๋ํ ์๋ณ ๋ฐ์ดํฐ
-
๊ฐ ํ์ ์ ์ฉ์นด๋ ์์ก์ ํ ๋ฌ์ด๋ฉฐ, ํ๋์ ์ ์ฉ์นด๋๋ ์ฌ๋ฌ ํ์ ๊ฐ์ง ์ ์์
7. installments_payment
-
Home Credit์ ์ด์ ๋์ถ์ ๋ํ ์ง๋ถ ๋ด์ญ
-
๊ฒฐ์ ์น์ธ ๋๋ง๋ค ํ๋์ ํ์ด ์๊ณ ๊ฒฐ์ ๋ฏธ์น์ธ ๋๋ง๋ค ํ๋์ ํ์ด ์์
(+)
-
๋ชจ๋ ์ด์ ๋ํ ์ ์๊ฐ ํฌํจ๋
HomeCredit_columns_description.csv
ํ์ผ -
์ ์ถ ํ์ผ ์์
b) ์ด๋ฏธ์ง ๊ตฌ์กฐ๋
0-2. ํ๊ฐ ์งํ: ROC AUC
-
์ผ๋จ ๋ฐ์ดํฐ๋ฅผ ํ์ ํ๋ฉดcolumn descriptions๋ฅผ ์ฝ์ด๋ณด๋ ๊ฒ์ด ๋์๋จ
-
ํด๋น ๋ํ์์๋ ๋ถ๋ฅ ํ๊ฐ ์งํ๋ก ์ ์๋ ค์ง ROC-AUC๋ฅผ ํ์ฉ
-
Receiver Operating Characteristic Area Under the Curve (ROC-AUC/AUROC)
-
TP(True Positive/ ์ง์์ฑ)์ ๋น์จ ๋ FP(False Positive. ์์์ฑ) ๋น์จ์ ๊ทธ๋ํ๋ก ํ์
-
๊ทธ๋ํ์ ๊ฐ ์ ์ ๋จ์ผ ๋ชจํ์ ๋ํ ๊ณก์ ์ ๋ํ๋ด๋ฉฐ, ๊ฐ ์ ์ ๋ฐ๋ผ ์ด๋ํ๋ฉด ์์ ์ธ์คํด์ค(instance)๋ฅผ ๋ถ๋ฅํ๋ ๋ฐ ์ฌ์ฉ๋๋ ์๊ณ๊ฐ์ด ๋ณ๊ฒฝ๋จ์ ๋ํ๋
-
์๊ณ๊ฐ(threshold)์ ์ค๋ฅธ์ชฝ ์๋จ์์ 0์์ ์์ํ์ฌ ์ผ์ชฝ ํ๋จ์ 1๋ก ์ด๋
-
์ผ์ชฝ์ ์๊ณ ๋ค๋ฅธ ๊ณก์ ์์ ์๋ ๊ณก์ ์ ๋ ๋์ ๋ชจํ์ ๋ํ๋
- ํ๋์ ๋ชจ๋ธ์ด ์ด๋ก์ ๋ชจ๋ธ๋ณด๋ค ๋ซ๊ณ , ์ด๋ ๋จ์ํ ๋ฌด์์ ์ถ์ธก ๋ชจ๋ธ์ ๋ํ๋ด๋ ๋นจ๊ฐ์ ๋๊ฐ์ ๋ณด๋ค ๋ซ๋ค.
-
๋จ์ํ ROC ๊ณก์ ์๋์ ๋ฉด์ ์ ์๋ฏธ
- ๊ณก์ ์ ์ ๋ถ๊ฐ์ ์๋ฏธ
-
0 ~ 1์ ๊ฐ์ ๊ฐ์ง๋ฉฐ ๋์์๋ก ๋ ์ข์ ๋ชจ๋ธ์ด๋ผ๊ณ ํ๊ฐ
-
๋๋ค์ผ๋ก ๋จ์ํ ์ถ์ธกํ๋ ๋ชจํ์ ROC-AUC๋ 0.5
-
ROC- AUC์ ๋ฐ๋ผ classifier(๋ถ๋ฅ๊ธฐ)๋ฅผ ์ธก์ ํ ๋ ์์ธก์ 0 ๋๋ 1๋ก ์์ฑํ๋ ๊ฒ์ด ์๋(=> ์ด๋ถ๋ฒ์ ์ผ๋ก ๋ต์ ์ ํ๋ ๊ฒ์ด ์๋) 0๊ณผ 1 ์ฌ์ด์ ํ๋ฅ ์ ์์ฑ
- ํด๋์ค๊ฐ ๋ถ๊ท ํํ(imbalanced) ๋ถํฌ๋ฅผ ๋๋ ๊ฒฝ์ฐ ์ ํ๋(accuracy)๊ฐ ์ต์์ ์ธก์ ๊ธฐ์ค์ด ์๋
-
EX>
99.9999%์ ์ ํ๋๋ก ํ ๋ฌ๋ฆฌ์คํธ๋ฅผ ํ์งํ ์ ์๋ ๋ชจ๋ธ์ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด, ๋ชจ๋ ์ฌ๋์ด ํ ๋ฌ๋ฆฌ์คํธ๊ฐ ์๋๋ผ๊ณ ์์ธกํด ๋ฒ๋ฆฌ๋ฉด ์ผ๋จ ์ ํ๋๋ ๋๊ฒ ๋์จ๋ค.
-
์ด๋ฌํ ์ํฉ์ ๋์ํ๊ธฐ ์ํด ROC- AUC ๋๋ F1 ์ ์์ ๊ฐ์ ๊ณ ๊ธ metric์ ํ์ฉ
- ROC AUC๊ฐ ๋์ ๋ชจ๋ธ๋ ์ ํ๋๊ฐ ๋์ง๋ง ROC AUC๊ฐ ๋ชจ๋ธ ์ฑ๋ฅ์ ๋ ์ ๋ํ๋.
0-3. ์ฐธ๊ณ ํ ๋งํ ๋ ธํธ๋ถ
1. ๋ผ์ด๋ธ๋ฌ๋ฆฌ & ๋ฐ์ดํฐ ์ค๋นํ๊ธฐ
1-1. ๋ผ์ด๋ธ๋ฌ๋ฆฌ & module
### for ๋ฐ์ดํฐ ๊ฐ๊ณต
import numpy as np
import pandas as pd
### ๋ฒ์ฃผํ ๋ณ์ encoder
from sklearn.preprocessing import LabelEncoder
### ํ์ผ ์์คํ
์ ์ด
import os
import warnings
warnings.filterwarnings('ignore')
### ์๊ฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
import matplotlib.pyplot as plt
import seaborn as sns
1-2. ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
-
์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ ๋ฐ์ดํฐ ํ์ผ
-
train์ ์ํ main ํ์ผ(target โญ)
-
test๋ฅผ ์ํ main ํ์ผ(target โ)
-
์ ์ถ์ฉ ์์ ํ์ผ
-
๊ฐ ๋์ถ์ ๋ํ ์ถ๊ฐ ์ ๋ณด๊ฐ ํฌํจ๋ 6๊ฐ์ ๊ธฐํ ํ์ผ
-
from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive
# ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฐ์ดํฐ์ ๋ชฉ๋ก ํ์ธ
print(os.listdir('/content/drive/MyDrive/Colab Notebooks/ECC 48แแ
ต แแ
ฆแแ
ชB/3แแ
ฎแแ
ก/data'))
['HomeCredit_columns_description.csv', 'POS_CASH_balance.csv', 'application_test.csv', 'application_train.csv', 'bureau.csv', 'bureau_balance.csv', 'credit_card_balance.csv', 'installments_payments.csv', 'previous_application.csv', 'sample_submission.csv']
# ํ์ต์ฉ ๋ฐ์ดํฐ
app_train = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/ECC 48แแ
ต แแ
ฆแแ
ชB/3แแ
ฎแแ
ก/data/application_train.csv')
print('Training data shape: ', app_train.shape)
Training data shape: (307511, 122)
app_train.head()
SK_ID_CURR | TARGET | NAME_CONTRACT_TYPE | CODE_GENDER | FLAG_OWN_CAR | FLAG_OWN_REALTY | CNT_CHILDREN | AMT_INCOME_TOTAL | AMT_CREDIT | AMT_ANNUITY | ... | FLAG_DOCUMENT_18 | FLAG_DOCUMENT_19 | FLAG_DOCUMENT_20 | FLAG_DOCUMENT_21 | AMT_REQ_CREDIT_BUREAU_HOUR | AMT_REQ_CREDIT_BUREAU_DAY | AMT_REQ_CREDIT_BUREAU_WEEK | AMT_REQ_CREDIT_BUREAU_MON | AMT_REQ_CREDIT_BUREAU_QRT | AMT_REQ_CREDIT_BUREAU_YEAR | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 100002 | 1 | Cash loans | M | N | Y | 0 | 202500.0 | 406597.5 | 24700.5 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
1 | 100003 | 0 | Cash loans | F | N | N | 0 | 270000.0 | 1293502.5 | 35698.5 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2 | 100004 | 0 | Revolving loans | M | Y | Y | 0 | 67500.0 | 135000.0 | 6750.0 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
3 | 100006 | 0 | Cash loans | F | N | Y | 0 | 135000.0 | 312682.5 | 29686.5 | ... | 0 | 0 | 0 | 0 | NaN | NaN | NaN | NaN | NaN | NaN |
4 | 100007 | 0 | Cash loans | M | N | Y | 0 | 121500.0 | 513000.0 | 21865.5 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
5 rows ร 122 columns
- train ๋ฐ์ดํฐ์๋ 307511๊ฐ์ ๊ด์ธก์น(๊ฐ๊ฐ ๋ณ๋์ ๋์ถ)์ target(์์ธกํ๊ณ ์ ํ๋ ๋ ์ด๋ธ)```์ ํฌํจํ 122๊ฐ์ feature(๋ณ์)๊ฐ ์กด์ฌ
# ํ๊ฐ์ฉ ๋ฐ์ดํฐ
app_test = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/ECC 48แแ
ต แแ
ฆแแ
ชB/3แแ
ฎแแ
ก/data/application_test.csv')
print('Testing data shape: ', app_test.shape)
Testing data shape: (48744, 121)
app_test.head()
SK_ID_CURR | NAME_CONTRACT_TYPE | CODE_GENDER | FLAG_OWN_CAR | FLAG_OWN_REALTY | CNT_CHILDREN | AMT_INCOME_TOTAL | AMT_CREDIT | AMT_ANNUITY | AMT_GOODS_PRICE | ... | FLAG_DOCUMENT_18 | FLAG_DOCUMENT_19 | FLAG_DOCUMENT_20 | FLAG_DOCUMENT_21 | AMT_REQ_CREDIT_BUREAU_HOUR | AMT_REQ_CREDIT_BUREAU_DAY | AMT_REQ_CREDIT_BUREAU_WEEK | AMT_REQ_CREDIT_BUREAU_MON | AMT_REQ_CREDIT_BUREAU_QRT | AMT_REQ_CREDIT_BUREAU_YEAR | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 100001 | Cash loans | F | N | Y | 0 | 135000.0 | 568800.0 | 20560.5 | 450000.0 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1 | 100005 | Cash loans | M | N | Y | 0 | 99000.0 | 222768.0 | 17370.0 | 180000.0 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 3.0 |
2 | 100013 | Cash loans | M | Y | Y | 0 | 202500.0 | 663264.0 | 69777.0 | 630000.0 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 4.0 |
3 | 100028 | Cash loans | F | N | Y | 2 | 315000.0 | 1575000.0 | 49018.5 | 1575000.0 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 3.0 |
4 | 100038 | Cash loans | M | Y | N | 1 | 180000.0 | 625500.0 | 32067.0 | 625500.0 | ... | 0 | 0 | 0 | 0 | NaN | NaN | NaN | NaN | NaN | NaN |
5 rows ร 121 columns
- test data๊ฐ ๋ ์๊ณ , target ๊ฐ์ด ์กด์ฌํ์ง ์๋๋ค.
2. ํ์์ ๋ฐ์ดํฐ ๋ถ์(EDA/ Exploratory Data Analysis)
-
ํต๊ณ๋ฅผ ๊ณ์ฐํ๊ณ ๋ฐ์ดํฐ ๋ด์ ์ถ์ธ, ์ด์ ์งํ, ํจํด ๋๋ ๊ด๊ณ๋ฅผ ์ฐพ๊ธฐ ์ํด ์์น๋ฅผ ๋ง๋๋ ๊ฐ๋ฐฉํ ํ๋ก์ธ์ค
-
๋ชฉํ: ๋ฐ์ดํฐ๊ฐ ์ ๊ณตํ๋ ์ ๋ณด๋ค์ ํ์ ํ๋ ๊ฒ
-
์ผ๋ฐ์ ์ผ๋ก ํฌ๊ด์ ์ธ ์์ค์ ๊ฐ์๋ก ์์ํ ๋ค์ ๋ฐ์ดํฐ์ ํฅ๋ฏธ๋ก์ด ๋ถ๋ถ์ ์ฐพ์์ ๋ฐ๋ผ ํน์ ์์ญ์ผ๋ก ์ขํ๋๊ฐ๋ ๋ฐฉ์
-
์ฐ๊ตฌ ๊ฒฐ๊ณผ๋ ์์ฒด์ ์ผ๋ก ํฅ๋ฏธ๋ก์ธ ์๋ ์๊ณ , ์ฌ์ฉํ feature๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐ ๋์์ ์ฃผ๋ ๋ฑ ๋ชจ๋ธ๋ง ์์ ์ ํ ์ฌํญ์ ์๋ฆฌ๋ ๋ฐ ์ฌ์ฉ๋ ์๋ ์์
2-1. Target ๊ฐ์ ๋ถํฌ ํ์ธํ๊ธฐ
-
๋ชฉํ: 0(๋์ถ๊ธ์ ์ ๋ ์ํ) vs 1(๊ณ ๊ฐ์ด ์ง๋ถ์ ์ด๋ ค์์ ๊ฒช์์) ์ค ํ๋๋ฅผ ์์ธก
-
๊ฐ ๋ฒ์ฃผ์ ์ํ๋ ๋์ถ์ ์๋ฅผ ์กฐ์ฌํ ์ ์์
app_train['TARGET'].value_counts()
0 282686 1 24825 Name: TARGET, dtype: int64
app_train['TARGET'].astype(int).plot.hist()
<Axes: ylabel='Frequency'>
-
๋งค์ฐ ๋ถ๊ท ํํ(imbalanced) ํด๋์ค์์ ํ์ ํ ์ ์์
- ์ ๋ ์ํ๋ ๋์ถ(0)์ด ์ํ๋์ง ์์ ๋์ถ(1)๋ณด๋ค ํจ์ฌ ๋ง์
-
๋ ์ ๊ตํ ๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ๋ง์ ์ ์ฉํ๋ค๋ฉด, ์ด ๋ถ๊ท ํ์ ๋ฐ์ํ๊ธฐ ์ํด ๋ฐ์ดํฐ์์์ ํํ์ผ๋ก ํด๋์ค์ ๊ฐ์ค์น๋ฅผ ๋ถ์ฌํ ์ ์์
2-2. ๊ฒฐ์ธก์น(Missing Value) ํ์ธ
- ๊ฐ ์ด์ ๊ฒฐ์ธก๊ฐ์ ์์ ๋น์จ ํ์
### column# ํจ์๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฒฐ์ธก๊ฐ์ ๊ณ์ฐํ๋ ํจ์
def missing_values_table(df):
# ๋ฐ์ดํฐ ๋ด์์ ๊ฒฐ์ธก์น์ ์ด ๊ฐ์
mis_val = df.isnull().sum()
# ์ ์ฒด ๋ฐ์ดํฐ์ ๋ํ ๊ฒฐ์ธก์น์ ๋น์จ
mis_val_percent = 100 * df.isnull().sum() / len(df)
# ๊ฒฐ๊ณผ ํ
์ด๋ธ ๋ง๋ค๊ธฐ
mis_val_table = pd.concat([mis_val, mis_val_percent], axis = 1) # ์ปฌ๋ผ ๋ฐฉํฅ์ผ๋ก ๊ฒฐํฉ
# ์ปฌ๋ผ๋ช
์ฌ์ ์
mis_val_table_ren_columns = mis_val_table.rename(
columns = {0 : 'Missing Values', 1 : '% of Total Values'})
# ๊ฒฐ์ธก์น์ ๋น์จ์ ๊ธฐ์ค์ผ๋ก ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ
mis_val_table_ren_columns = mis_val_table_ren_columns[
mis_val_table_ren_columns.iloc[:,1] != 0].sort_values(
'% of Total Values', ascending = False).round(1) # ์์ ์ฒซ์งธ์๋ฆฌ์์ ๋ฐ์ฌ๋ฆผ
# ์์ฝ ์ ๋ณด ์ถ๋ ฅ
print ("Your selected dataframe has " + str(df.shape[1]) + " columns.\n"
"There are " + str(mis_val_table_ren_columns.shape[0]) +
" columns that have missing values.")
return mis_val_table_ren_columns
# ๊ฒฐ์ธก์น์ ๋ํ ์์ฝ ์ ๋ณด ํ์ธ
missing_values = missing_values_table(app_train)
missing_values.head(20)
Your selected dataframe has 122 columns. There are 67 columns that have missing values.
Missing Values | % of Total Values | |
---|---|---|
COMMONAREA_MEDI | 214865 | 69.9 |
COMMONAREA_AVG | 214865 | 69.9 |
COMMONAREA_MODE | 214865 | 69.9 |
NONLIVINGAPARTMENTS_MEDI | 213514 | 69.4 |
NONLIVINGAPARTMENTS_MODE | 213514 | 69.4 |
NONLIVINGAPARTMENTS_AVG | 213514 | 69.4 |
FONDKAPREMONT_MODE | 210295 | 68.4 |
LIVINGAPARTMENTS_MODE | 210199 | 68.4 |
LIVINGAPARTMENTS_MEDI | 210199 | 68.4 |
LIVINGAPARTMENTS_AVG | 210199 | 68.4 |
FLOORSMIN_MODE | 208642 | 67.8 |
FLOORSMIN_MEDI | 208642 | 67.8 |
FLOORSMIN_AVG | 208642 | 67.8 |
YEARS_BUILD_MODE | 204488 | 66.5 |
YEARS_BUILD_MEDI | 204488 | 66.5 |
YEARS_BUILD_AVG | 204488 | 66.5 |
OWN_CAR_AGE | 202929 | 66.0 |
LANDAREA_AVG | 182590 | 59.4 |
LANDAREA_MEDI | 182590 | 59.4 |
LANDAREA_MODE | 182590 | 59.4 |
-
๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ์ ๊ตฌ์ถํ ๋๊ฐ ๋๋ฉด ์ด๋ฌํ ๋๋ฝ๋ ๊ฐ์ ์ฑ์์ผ ํจ(๊ฒฐ์ธก์ด๋ผ๊ณ ํจ)
-
์ดํ ์์ ์์๋ XGBoost์ ๊ฐ์ imputation ํ ํ์ ์์ด ๊ฒฐ์ธก๊ฐ์ ๊ณ์ฐํ ์ ์๋ ๋ชจ๋ธ์ ํ์ฉํ ์์
-
๊ฒฐ์ธก๊ฐ์ ๋น์จ์ด ๋์ ์ด์ ์ญ์ ํ๋ ๊ฒ๋ ๋ฐฉ๋ฒ์
-
ํ์ง๋ง ํด๋น ์ด์ด ๋ชจํ์ ๋์์ด ๋๋์ง ์ฌ๋ถ๋ฅผ ๋ฏธ๋ฆฌ ์ ์ X
-
ํ์ฌ ๋ชจ๋ column์ ์ ์ง
-
2-3. Column์ ํํ
-
int64
์float64
๋ ์ซ์ํ ๋ณ์-
์ด์ฐํ ๋๋ ์ฐ์ํ
-
-
object
์ด์ ๋ฌธ์์ด์ ํฌํจํ๋ฉฐ ํต๊ณ์ feature์
# ์ปฌ๋ผ๋ค์ ํ์
๋ณ ๋ถํฌ
app_train.dtypes.value_counts()
float64 65 int64 41 object 16 dtype: int64
- ๊ฐ
objectํ
(๋ฒ์ฃผํ) ์ปฌ๋ผ๋ค์ ๊ณ ์ ํญ๋ชฉ ์
# ๊ฐ object ์ปฌ๋ผ์ ๊ณ ์ ํด๋์ค ์
app_train.select_dtypes('object').apply(pd.Series.nunique, axis = 0)
NAME_CONTRACT_TYPE 2 CODE_GENDER 3 FLAG_OWN_CAR 2 FLAG_OWN_REALTY 2 NAME_TYPE_SUITE 7 NAME_INCOME_TYPE 8 NAME_EDUCATION_TYPE 5 NAME_FAMILY_STATUS 6 NAME_HOUSING_TYPE 6 OCCUPATION_TYPE 18 WEEKDAY_APPR_PROCESS_START 7 ORGANIZATION_TYPE 58 FONDKAPREMONT_MODE 4 HOUSETYPE_MODE 3 WALLSMATERIAL_MODE 7 EMERGENCYSTATE_MODE 2 dtype: int64
- ๋๋ถ๋ถ์ ๋ฒ์ฃผํ ๋ณ์์๋ ๋น๊ต์ ์ ์ ์์ ๊ณ ์ ํญ๋ชฉ์ด ์กด์ฌ
2-4. ๋ฒ์ฃผํ ๋ณ์ Encoding
-
๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ์ ๋ฒ์ฃผํ ๋ณ์๋ฅผ ์ฒ๋ฆฌํ ์ ์์
-
LightGBM ๊ณผ ๊ฐ์ ์ผ๋ถ ๋ชจ๋ธ ์ ์ธ
-
๋ชจ๋ธ์ ์ ์ฉํ๊ธฐ ์ ์ ์ด๋ฌํ ๋ณ์๋ฅผ ์ซ์๋ก ์ธ์ฝ๋ฉ(ํํ) ํด์ฃผ์ด์ผ ํจ
-
1. ๋ ์ด๋ธ ์ธ์ฝ๋ฉ
-
๋ฒ์ฃผํ ๋ณ์์ ๊ฐ ๊ณ ์ ๋ฒ์ฃผ์ ์ ์๋ฅผ ํ ๋น
-
์๋ก์ด column์ด ์์ฑ๋์ง ์์
2. One-hot ์ธ์ฝ๋ฉ
-
๋ฒ์ฃผํ ๋ณ์์ ๊ฐ ๊ณ ์ ๋ฒ์ฃผ์ ๋ํด ์๋ก์ด column์ ์์ฑ
-
๊ฐ ๊ด์ธก์น๋ ํด๋น ๋ฒ์ฃผ์ ๋ํ ์ด์ ๊ฐ์ผ๋ก 1์ ์ ์ฅํ๊ณ ๋ค๋ฅธ ๋ชจ๋ ์๋ก์ด ์ด์๋ 0์ ์ ์ฅ
a) Label Encoding๊ณผ One-Hot Encoding
-
๊ณ ์ ํ ๋ฒ์ฃผ๊ฐ 2๊ฐ์ธ ๋ฒ์ฃผํ ๋ณ์(
dtype == object
)์ ๊ฒฝ์ฐ ๋ ์ด๋ธ ์ธ์ฝ๋ฉ์ ์ฌ์ฉํ๊ณ , ๊ณ ์ ํ ๋ฒ์ฃผ๊ฐ 2๊ฐ ์ด์์ธ ๋ฒ์ฃผํ ๋ณ์์ ๊ฒฝ์ฐ ์-ํซ ์ธ์ฝ๋ฉ์ ์ฌ์ฉ -
๋ ์ด๋ธ ์ธ์ฝ๋ฉ์ ๊ฒฝ์ฐ Scikit-Learn์
LabelEncoder
๋ฅผ ์ฌ์ฉํ๊ณ , ์-ํซ ์ธ์ฝ๋ฉ์ ๊ฒฝ์ฐ pandas์get_dummies(df)
ํจ์๋ฅผ ์ฌ์ฉ
### LabelEncoding ๊ฐ์ฒด ์์ฑ
le = LabelEncoder()
le_count = 0
# ์ด๋ค์ ํ๋์ฉ ํ์ํ๋ฉด์..
for col in app_train:
if app_train[col].dtype == 'object': # ๋ฒ์ฃผํ ๋ณ์์ด๋ฉด
if len(list(app_train[col].unique())) <= 2:
### LabelEncoding
le.fit(app_train[col]) # Encoder ํ์ต
# ๋ฐ์ดํฐ ๋ณํ
app_train[col] = le.transform(app_train[col])
app_test[col] = le.transform(app_test[col])
le_count += 1
print('%d columns were label encoded.' % le_count)
3 columns were label encoded.
# ์ธ์ฝ๋ฉ๋์ง ์์ ๋๋จธ์ง ๋ฒ์ฃผํ ๋ณ์๋ค -> One-hot Encoding
app_train = pd.get_dummies(app_train)
app_test = pd.get_dummies(app_test)
print('Training Features shape: ', app_train.shape)
print('Testing Features shape: ', app_test.shape)
Training Features shape: (307511, 243) Testing Features shape: (48744, 239)
b) Train/ Test ๋ฐ์ดํฐ ์กฐ์
-
train ๋ฐ test ๋ฐ์ดํฐ ๋ชจ๋์ ๋์ผํ ๋ณ์(feature)๊ฐ ์์ด์ผ ํจ
-
test ๋ฐ์ดํฐ์ ๋ฒ์ฃผ๊ฐ ํ์๋์ง ์์ ์ผ๋ถ ๋ฒ์ฃผํ ๋ณ์๊ฐ ์์๊ธฐ ๋๋ฌธ์ one - hot ์ธ์ฝ๋ฉ์ผ๋ก ์ธํด train ๋ฐ์ดํฐ์ ๋ ๋ง์ ์ด์ด ์์ฑ๋์์
-
ํ ์คํธ ๋ฐ์ดํฐ์ ์๋ train ๋ฐ์ดํฐ์ ์ด์ ์ ๊ฑฐํ๋ ค๋ฉด ๋ฐ์ดํฐ ํ๋ ์์ ์ ๋ ฌํด์ผ ํจ
-
๋จผ์ train ๋ฐ์ดํฐ์์ ๋์ ์ด์ ์ถ์ถ
- ํ ์คํธ ๋ฐ์ดํฐ์๋ ์์ง๋ง ํด๋น ์ ๋ณด๋ฅผ ์ ์งํด์ผ ํ๊ธฐ ๋๋ฌธ์
-
์ ๋ ฌ์ ์ํํ ๋ ํ์ด ์๋ ์ด์ ๊ธฐ์ค์ผ๋ก ๋ฐ์ดํฐ ํ๋ ์์ ์ ๋ ฌํ๋๋ก
axis = 1
์ ์ค์ ํด์ผ ํจ
-
train_labels = app_train['TARGET'] # target ๊ฐ
### train/test ๋ฐ์ดํฐ ์ ๋ ฌ
# ์ผ๋จ train/test ๋ด์ ์ด์ ๋ง์ถ๊ธฐ ์ํด test ๋ฐ์ดํฐ์ ์๋ ์ด๋ค ๊ธฐ์ค์ผ๋ก๋ง ๋ง์ถ๊ธฐ
app_train, app_test = app_train.align(app_test, join = 'inner', axis = 1)
# train ๋ฐ์ดํฐ ๋ค์๋ target๊ฐ์ ๋ค์ ๊ฒฐํฉ
app_train['TARGET'] = train_labels
print('Training Features shape: ', app_train.shape)
print('Testing Features shape: ', app_test.shape)
Training Features shape: (307511, 240) Testing Features shape: (48744, 239)
-
train๊ณผ test ๋ฐ์ดํฐ๊ฐ ๋์ผํ feature๋ค์ ๊ฐ์ง๊ฒ ๋จ(target ๋ณ์๋ ์ ์ธ)
-
one - hot ์ธ์ฝ๋ฉ์ผ๋ก ์ธํด feature์ ์๊ฐ ํฌ๊ฒ ์ฆ๊ฐ
- ๋ฐ์ดํฐ ์ธํธ์ ํฌ๊ธฐ๋ฅผ ์ค์ด๊ธฐ ์ํด ์๊ด์ฑ ๊ฐ์(๊ด๋ จ ์๋ ๊ธฐ๋ฅ ๊ฐ์) )๋ฅผ ์๋ํด ๋ณผ ์ ์์
2-5. ๋ถ๊ฐ์ ์ธ EDA ์งํํ๊ธฐ
a) ์ด์์น(anomaly)
-
EDA๋ฅผ ์ํํ ๋ ๋ฐ์ดํฐ ๋ด์ ์ด์์น๋ฅผ ์ฃผ์ํด์ผ ํจ
- ์ซ์๋ฅผ ์๋ชป ์ ๋ ฅํ๊ฑฐ๋ ์ธก์ ์ฅ๋น์ ์ค๋ฅ๊ฐ ์๊ฑฐ๋ ์ ํจํ์ง๋ง ๊ทน๋จ์ ์ธ ์ธก์ ์ผ ์ ์์
-
describe()
ํจ์๋ฅผ ํตํด ํด๋น ์ด์ ํต๊ณ๋ฅผ ์ดํด๋ณด๋ ๊ฒ์ผ๋ก ์ด์์น๋ฅผ ํ์งํ ์ ์์ -
DAYS_BIRTH
์ปฌ๋ผ์ ์๋ ์ซ์๋ ํ์ฌ ๋์ถ ์ ์ฒญ๊ณผ ๊ด๋ จํ์ฌ ๊ธฐ๋ก๋๊ธฐ ๋๋ฌธ์ ์์์- ํต๊ณ๋ฅผ ๋ ๋จ์๋ก ๋ณด๋ ค๋ฉด -1์ ๊ณฑํ๊ณ 1๋ ์ ์ผ ์(365์ผ)๋ก ๋๋ ์ ๊ตฌํ ์ ์์
(app_train['DAYS_BIRTH'] / -365).describe()
count 307511.000000 mean 43.936973 std 11.956133 min 20.517808 25% 34.008219 50% 43.150685 75% 53.923288 max 69.120548 Name: DAYS_BIRTH, dtype: float64
- ์ํ ๋๋ ํํ์ ์ฐ๋ น์ ๋ํ ์ด์์น๊ฐ ์๋ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค.
app_train['DAYS_EMPLOYED'].describe()
count 307511.000000 mean 63815.045904 std 141275.766519 min -17912.000000 25% -2760.000000 50% -1213.000000 75% -289.000000 max 365243.000000 Name: DAYS_EMPLOYED, dtype: float64
-
์ต๋๊ฐ์ ์ฝ 1000๋ ..?!
- ์ด์์น๊ฐ ์กด์ฌํ๋ค.
### ๋ฐ์ดํฐ ๋ถํฌ ํ์ธํ๊ธฐ
app_train['DAYS_EMPLOYED'].plot.hist(title = 'Days Employment Histogram');
plt.xlabel('Days Employment');
- ๋น์ ์์ ์ธ ํด๋ผ์ด์ธํธ์ ํ์ ์งํฉ์ ์ค์ ํ์ฌ ๋ค๋ฅธ ํด๋ผ์ด์ธํธ๋ณด๋ค ๊ธฐ๋ณธ๊ฐ ๋น์จ์ด ๋๊ฑฐ๋ ๋ฎ์ ๊ฒฝํฅ์ด ์๋์ง ํ์ธํด๋ณด์.
anom = app_train[app_train['DAYS_EMPLOYED'] == 365243]
non_anom = app_train[app_train['DAYS_EMPLOYED'] != 365243]
print('The non-anomalies default on %0.2f%% of loans' % (100 * non_anom['TARGET'].mean()))
print('The anomalies default on %0.2f%% of loans' % (100 * anom['TARGET'].mean()))
print('There are %d anomalous days of employment' % len(anom))
The non-anomalies default on 8.66% of loans The anomalies default on 5.40% of loans There are 55374 anomalous days of employment
- ์ด์์น๋ก ์ฌ๊ฒจ์ง๋ ๊ณ ๊ฐ๋ค์ ์ฑ๋ฌด ๋ถ์ดํ ๋น์จ์ด ๋ ๋ฎ์ ๊ฒ์ผ๋ก ๋ํ๋จ
โ ์ด์์น ์ฒ๋ฆฌ
-
๊ฐ์ฅ ์์ ํ ์ ๊ทผ๋ฒ ์ค ํ๋๋ ๊ธฐ๊ณ ํ์ต ์ ์ ์ด์์น๋ฅผ ๊ฒฐ์ธก๊ฐ์ผ๋ก ์ค์ ํ ๋ค์ ๊ฐ์ ์ฑ์๋ฃ๋ ๋ฐฉ๋ฒ์
- ๋ชจ๋ ๊ณตํต์ ์ธ ์ด๋ค ๊ฐ์ผ๋ก ๊ฐ์ ํด ๋์ผํ ๊ฐ์ผ๋ก ํด๋น ๊ฐ์ ์ฑ์
-
์ฌ๊ธฐ์๋ ๋น์ ์์ ์ธ ๊ฐ์ ๊ฐ์ง๋ ๋ฐ์ดํฐ์ ๋ํด
np.nan
์ผ๋ก ๊ฒฐ์ธก์น๋ก ๊ฐ์ ๋ณ๊ฒฝ ํ, ๊ฐ์ ๋น์ ์ ์ ๋ฎค๋ฅผ ๋ํ๋ด๋ bool ์นผ๋ผ์ ์๋ก ์์ฑ
# flag ์ปฌ๋ผ ์์ฑ -> ์ด์์น ์ ๋ฌด ์ ์ฅ
app_train['DAYS_EMPLOYED_ANOM'] = app_train["DAYS_EMPLOYED"] == 365243
# ์ด์์น๋ฅผ np.nan์ผ๋ก
app_train['DAYS_EMPLOYED'].replace({365243: np.nan}, inplace = True)
app_train['DAYS_EMPLOYED'].plot.hist(title = 'Days Employment Histogram');
plt.xlabel('Days Employment');
-
๋ถํฌ๋ ์ฐ๋ฆฌ๊ฐ ์์ํ๋ ๊ฒ๊ณผ ํจ์ฌ ๋ ๋น์ทํ ๊ฒ์ผ๋ก ํ๋จ๋๋ฉฐ, ์ด๋ฌํ ๊ฐ์ด ์๋ ๋น์ ์์์ ๋ชจ๋ธ์ ์๋ ค์ฃผ๋ ์๋ก์ด ์ปฌ๋ผ(
DAYS_EMPLOYED_ANOM
)๋ ์์ฑํจ- NaN ๊ฐ์ ์๋ง column์ ์ค๊ฐ๊ฐ(median)์ผ๋ก ์ฑ์์ผ ํ๊ธฐ ๋๋ฌธ
-
์ด์์น๋ฅผ ์ ์ธํ๊ณ ๋ ๋ฌธ์ ๊ฐ ์์ด ๋ณด์
app_test['DAYS_EMPLOYED_ANOM'] = app_test["DAYS_EMPLOYED"] == 365243
app_test["DAYS_EMPLOYED"].replace({365243: np.nan}, inplace = True)
print('There are %d anomalies in the test data out of %d entries' % (app_test["DAYS_EMPLOYED_ANOM"].sum(), len(app_test)))
There are 9274 anomalies in the test data out of 48744 entries
b) ์๊ด๊ด๊ณ(Correlations)
-
๋ฐ์ดํฐ๋ฅผ ์ดํดํ๊ณ ์ดํดํ๋ ํ ๊ฐ์ง ๋ฐฉ๋ฒ์ feature์ target ์ฌ์ด์ ์๊ด ๊ด๊ณ๋ฅผ ์ฐพ๋ ๊ฒ
-
์๊ด ๊ณ์๋ feature์ ๊ด๋ จ์ฑ์ ๋ํ๋ด๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ์๋์ง๋ง, ๋ฐ์ดํฐ ๋ด์์ ๊ฐ๋ฅํ ๊ด๊ณ์ ๋ํ ๊ฐ๋ ์ ์ ๊ณต
-
์๊ด๊ณ์์ ์ ๋๊ฐ์ ๋ํ ์ผ๋ฐ์ ์ธ ํด์
-
0 ~ 0.19: ๋งค์ฐ ์ฝํ ์๊ด๊ด๊ณ
-
0.20 ~ 0.39: ์ฝํ ์๊ด๊ด๊ณ
-
0.40 ~ 0.59: ์ด๋ ์ ๋์ ์๊ด๊ด๊ณ
-
0.60 ~ 0.79: ๊ฐํ ์๊ด๊ด๊ณ
-
0.80 ~ 1.0: ๋งค์ฐ ๊ฐํ ์๊ด๊ด๊ณ
-
# target๊ณผ์ ์๊ด๊ณ์๋ฅผ ๊ตฌํ ํ ์ ๋ ฌ
correlations = app_train.corr()['TARGET'].sort_values()
print('Most Positive Correlations:\n', correlations.tail(15))
print()
print('\nMost Negative Correlations:\n', correlations.head(15))
Most Positive Correlations: OCCUPATION_TYPE_Laborers 0.043019 FLAG_DOCUMENT_3 0.044346 REG_CITY_NOT_LIVE_CITY 0.044395 FLAG_EMP_PHONE 0.045982 NAME_EDUCATION_TYPE_Secondary / secondary special 0.049824 REG_CITY_NOT_WORK_CITY 0.050994 DAYS_ID_PUBLISH 0.051457 CODE_GENDER_M 0.054713 DAYS_LAST_PHONE_CHANGE 0.055218 NAME_INCOME_TYPE_Working 0.057481 REGION_RATING_CLIENT 0.058899 REGION_RATING_CLIENT_W_CITY 0.060893 DAYS_EMPLOYED 0.074958 DAYS_BIRTH 0.078239 TARGET 1.000000 Name: TARGET, dtype: float64 Most Negative Correlations: EXT_SOURCE_3 -0.178919 EXT_SOURCE_2 -0.160472 EXT_SOURCE_1 -0.155317 NAME_EDUCATION_TYPE_Higher education -0.056593 CODE_GENDER_F -0.054704 NAME_INCOME_TYPE_Pensioner -0.046209 DAYS_EMPLOYED_ANOM -0.045987 ORGANIZATION_TYPE_XNA -0.045987 FLOORSMAX_AVG -0.044003 FLOORSMAX_MEDI -0.043768 FLOORSMAX_MODE -0.043226 EMERGENCYSTATE_MODE_No -0.042201 HOUSETYPE_MODE_block of flats -0.040594 AMT_GOODS_PRICE -0.039645 REGION_POPULATION_RELATIVE -0.037227 Name: TARGET, dtype: float64
-
DAYS_BIRTH
๊ฐ target๊ณผ ๊ฐ์ฅ ๊ฐํ ์์ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์งDAYS_BIRTH
๋ ๋์ถ ๋น์ ๊ณ ๊ฐ์ ๋์ด -> ์์
-
์๊ด๊ณ์๋ ์์์ด์ง๋ง, feature์ ์ค์ ๊ฐ์ ์์์
-
์ฆ, ํด๋ผ์ด์ธํธ๊ฐ ๋์ด๊ฐ ๋ค์๋ก ๋์ถ ๋ถ์ดํ ๊ฐ๋ฅ์ฑ์ด ๋ฎ์์ง(์ฆ, target == 0)
-
feature์ ์ ๋๊ฐ์ ์ทจํด ์๊ด๊ด๊ณ๊ฐ ์์๊ฐ ๋จ
-
c) ๋์ถ ์ํ(Target)์ ๋์ด(Age)๊ฐ ๋ฏธ์น๋ ์ํฅ
app_train['DAYS_BIRTH'] = abs(app_train['DAYS_BIRTH']) # ๋์ด๋ฅผ ๊ตฌํ๊ธฐ ์ํด ์ถ์์ผ๋ก๋ถํฐ ์ง๋ ๋ ์ ๊ตฌํจ
app_train['DAYS_BIRTH'].corr(app_train['TARGET'])
-0.07823930830982694
-
target๊ณผ ์์ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง
- ๊ณ ๊ฐ์ด ๋์ด๊ฐ ๋ค์๋ก ๋์ถ๊ธ์ ์ ๋ ์ํํ๋ ๊ฒฝํฅ์ด ์๋ค๋ ๊ฒ์ ์๋ฏธ
### ํ์คํ ๊ทธ๋จ ๊ทธ๋ฆฌ๊ธฐ
# ๋ ์์ธํ ์ดํด๋ณด๊ธฐ ์ํด ํ์คํ ๊ทธ๋จ์ผ๋ก ์๊ฐํ
# x์ถ์ ์ฐ ๋จ์๋ก ์ง์
# Set the style of plots
plt.style.use('fivethirtyeight')
# ์ฐ ๋จ์๋ก ๋์ด์ ๋ถํฌ ํ์
plt.hist(app_train['DAYS_BIRTH'] / 365, edgecolor = 'k', bins = 25)
plt.title('Age of Client')
plt.xlabel('Age (years)')
plt.ylabel('Count')
Text(0, 0.5, 'Count')
- ์ฐ๋ น ๋ถํฌ๋ ๋ชจ๋ ์ฐ๋ น๋์ ์ด์์น๊ฐ ์๋ค๋ ๊ฒ ์ธ์๋ ๋ณ๋ค๋ฅธ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ง x
### KDE plot ์๊ฐํ
# target์ ๋ํ ์ฐ๋ น์ ์ํฅ์ ์๊ฐํํ๊ธฐ ์ํด kernel density estimate plot(KDE)์ ์๊ฐํ
# KDE๋ ๋จ์ผ ๋ณ์์ ๋ถํฌ๋ฅผ ๋ณด์ฌ์ฃผ๋ฉฐ, ์ข ๋ smoothํ ํ์คํ ๊ทธ๋จ ์ ๋๋ก ์๊ฐํ ์ ์์
plt.figure(figsize = (10, 8))
# target = 0(์ ๋ ๋์ถ ์ํํจ)
sns.kdeplot(app_train.loc[app_train['TARGET'] == 0, 'DAYS_BIRTH'] / 365,
label = 'target == 0')
# target = 1(์ ๋ ๋์ถ ์ํํ์ง ๋ชปํจ)
sns.kdeplot(app_train.loc[app_train['TARGET'] == 1, 'DAYS_BIRTH'] / 365,
label = 'target == 1')
plt.xlabel('Age (years)'); plt.ylabel('Density'); plt.title('Distribution of Ages');
-
target = 1
๊ณก์ ์ ๋์ด ๋ฒ์์ ๋ ์ ์ ์ชฝ์ผ๋ก ์น์ฐ์ฒ์ ธ ์์- ์ ์ํ ์๊ด ๊ด๊ณ(์๊ด ๊ณ์: -0.07)๋ ์๋์ง๋ง, ๋์์ ์ํฅ์ ๋ฏธ์น๊ธฐ ๋๋ฌธ์ ๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ์์ ์ ์ฉํ ์ ์์
### ์ฐ๋ น๋๋ณ ํ๊ท ์ ์ธ ๋์ถ ์ํ ์คํจ ์ ๋ ํ์
ํ๊ธฐ
# ๊ทธ๋ํ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๋จผ์ ์ฐ๋ น ๋ฒ์ฃผ๋ฅผ ๊ฐ๊ฐ 5๋
๋จ์์ ๋น์ผ๋ก ์๋ผ๋ด๊ณ , ๊ฐ ๋น์ ๋ํด ๋ชฉํ๊ฐ์ ํ๊ท ๊ฐ์ ๊ณ์ฐ
# ์ด๋ฅผ ํตํด ๊ฐ ์ฐ๋ น๋๋ณ๋ก ์ํ๋์ง ์์ ๋์ถ์ ๋น์จ์ ํ์
# ๋ค๋ฅธ dataframe์ ์กด์ฌํ๋ ์ ๋ณด๋ค์ ๊ฒฐํฉ
age_data = app_train[['TARGET', 'DAYS_BIRTH']]
age_data['YEARS_BIRTH'] = age_data['DAYS_BIRTH'] / 365
# ๋์ด ๋ฐ์ดํฐ ๋ฒ์ ๋๋๊ธฐ
age_data['YEARS_BINNED'] = pd.cut(age_data['YEARS_BIRTH'],
bins = np.linspace(20, 70, num = 11))
age_data.head(10)
TARGET | DAYS_BIRTH | YEARS_BIRTH | YEARS_BINNED | |
---|---|---|---|---|
0 | 1 | 9461 | 25.920548 | (25.0, 30.0] |
1 | 0 | 16765 | 45.931507 | (45.0, 50.0] |
2 | 0 | 19046 | 52.180822 | (50.0, 55.0] |
3 | 0 | 19005 | 52.068493 | (50.0, 55.0] |
4 | 0 | 19932 | 54.608219 | (50.0, 55.0] |
5 | 0 | 16941 | 46.413699 | (45.0, 50.0] |
6 | 0 | 13778 | 37.747945 | (35.0, 40.0] |
7 | 0 | 18850 | 51.643836 | (50.0, 55.0] |
8 | 0 | 20099 | 55.065753 | (55.0, 60.0] |
9 | 0 | 14469 | 39.641096 | (35.0, 40.0] |
# bins๋ฅผ ๊ธฐ์ค์ผ๋ก groupbyํ์ฌ ์ฐ๋ น๋ ํ๊ท ๊ตฌํ๊ธฐ
age_groups = age_data.groupby('YEARS_BINNED').mean()
age_groups
TARGET | DAYS_BIRTH | YEARS_BIRTH | |
---|---|---|---|
YEARS_BINNED | |||
(20.0, 25.0] | 0.123036 | 8532.795625 | 23.377522 |
(25.0, 30.0] | 0.111436 | 10155.219250 | 27.822518 |
(30.0, 35.0] | 0.102814 | 11854.848377 | 32.479037 |
(35.0, 40.0] | 0.089414 | 13707.908253 | 37.555913 |
(40.0, 45.0] | 0.078491 | 15497.661233 | 42.459346 |
(45.0, 50.0] | 0.074171 | 17323.900441 | 47.462741 |
(50.0, 55.0] | 0.066968 | 19196.494791 | 52.593136 |
(55.0, 60.0] | 0.055314 | 20984.262742 | 57.491131 |
(60.0, 65.0] | 0.052737 | 22780.547460 | 62.412459 |
(65.0, 70.0] | 0.037270 | 24292.614340 | 66.555108 |
### ์๊ฐํ
plt.figure(figsize = (8, 8))
# Graph the age bins and the average of the target as a bar plot
plt.bar(age_groups.index.astype(str), 100 * age_groups['TARGET'])
# Plot labeling
plt.xticks(rotation = 75); plt.xlabel('Age Group (years)'); plt.ylabel('Failure to Repay (%)')
plt.title('Failure to Repay by Age Group');
-
์ ์ ์ง์์๋ค์ ๋์ถ๊ธ์ ์ํํ์ง ๋ชปํ ๊ฐ๋ฅ์ฑ์ด ๋ ๋์
- ๊ฐ์ฅ ์ ์ 3๊ฐ ๊ทธ๋ฃน์ ์ฐ์ฒด์จ์ด 10% ์ด์, ๊ฐ์ฅ ๋์ด๊ฐ ๋ง์ ๊ทธ๋ฃน์ ์ฐ์ฒด์จ์ด 5% ๋ฏธ๋ง์
-
์ ์ ๊ณ ๊ฐ๋ค์ด ๋์ถ๊ธ์ ์ํํ ๊ฐ๋ฅ์ฑ์ด ๋ฎ๊ธฐ ๋๋ฌธ์, ๊ทธ๋ค์๊ฒ ๋ ๋ง์ ๊ฐ์ด๋๋ ์ฌ๋ฌด ๊ด๋ฆฌ ํ์ ์ ๊ณตํ๋ ๊ฒ์ด ๊ถ์ฅ๋๋ค.
d) Exterior Sources
-
target
๊ณผ ๊ฐ์ฅ ๊ฐํ ์์ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง 3๊ฐ์ ๋ณ์๋EXT_SOURCE_1
,EXT_SOURCE_2
, ๊ทธ๋ฆฌ๊ณEXT_SOURCE_3
์ -
์ค๋ช ์ ๋ฐ๋ฅด๋ฉด ํด๋น feature๋ค์ ์ธ๋ถ ๋ฐ์ดํฐ ์์ค์ ์ ๊ทํ๋ ์ ์๋ฅผ ์๋ฏธ
- ์๋ง์ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋ง๋ ์ผ์ข ์ ๋์ ์ ์ฉ ๋ฑ๊ธ์ด๋ผ ์๊ฐํด๋ ok
### ์๊ด๊ณ์ ํ์
ํ๊ธฐ
ext_data = app_train[['TARGET', 'EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH']]
ext_data_corrs = ext_data.corr()
ext_data_corrs
TARGET | EXT_SOURCE_1 | EXT_SOURCE_2 | EXT_SOURCE_3 | DAYS_BIRTH | |
---|---|---|---|---|---|
TARGET | 1.000000 | -0.155317 | -0.160472 | -0.178919 | -0.078239 |
EXT_SOURCE_1 | -0.155317 | 1.000000 | 0.213982 | 0.186846 | 0.600610 |
EXT_SOURCE_2 | -0.160472 | 0.213982 | 1.000000 | 0.109167 | 0.091996 |
EXT_SOURCE_3 | -0.178919 | 0.186846 | 0.109167 | 1.000000 | 0.205478 |
DAYS_BIRTH | -0.078239 | 0.600610 | 0.091996 | 0.205478 | 1.000000 |
### ์๊ฐํ
plt.figure(figsize = (8, 6))
# Heatmap
sns.heatmap(ext_data_corrs, cmap = plt.cm.RdYlBu_r, vmin = -0.25,
annot = True, vmax = 0.6)
plt.title('Correlation Heatmap');
-
์ธ ๊ฐ์ง
EXT_SOURCE
feature๋ค์ ๋ชจ๋ ๋์๊ณผ ์์ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์งEXT_SOURCE
์ ๊ฐ์ด ์ฆ๊ฐํ ์๋ก ํด๋ผ์ด์ธํธ๊ฐ ๋์ถ๊ธ์ ์ํํ ๊ฐ๋ฅ์ฑ์ด ๋์์ง
-
DAYS_BIRTH
๊ฐEXT_SOURCE_1
๊ณผ ์์ ์๊ด๊ด๊ณ๊ฐ ์์์ ์ ์ ์์- ์ด ์ ์์ ์์ธ ์ค ํ๋๊ฐ ํด๋ผ์ด์ธํธ์ ์ฐ๋ น์ผ ์ ์์
### target ๊ฐ ๋ณ๋ก ๊ฐ feature์ ๋ถํฌ๋ฅผ ์๊ฐํ
# ๊ฐ ๋ณ์๋ค์ด target์ ๋ฏธ์น๋ ์ํฅ ํ์
plt.figure(figsize = (10, 12))
# iterate through the sources
for i, source in enumerate(['EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3']):
# create a new subplot for each source
plt.subplot(3, 1, i + 1)
# ์ ๋ ์ํ๋จ(target = 0)
sns.kdeplot(app_train.loc[app_train['TARGET'] == 0, source], label = 'target == 0')
# ์ ๋ ์ํ๋์ง ๋ชปํจ(target = 1)
sns.kdeplot(app_train.loc[app_train['TARGET'] == 1, source], label = 'target == 1')
plt.title('Distribution of %s by Target Value' % source)
plt.xlabel('%s' % source); plt.ylabel('Density');
plt.tight_layout(h_pad = 2.5)
-
EXT_SOURCE_3
์ด ๋์ ๊ฐ ๊ฐ์ ๊ฐ์ฅ ํฐ ์ฐจ์ด๋ฅผ ๋ณด์ -
์๊ฐํ๋ฅผ ํตํด ํด๋น feature๋ค์ด ์ ์ฒญ์๊ฐ ๋์ถ๊ธ์ ์ํํ ๊ฐ๋ฅ์ฑ๊ณผ ์ด๋ ์ ๋ ๊ด๋ จ์ด ์๋ค๋ ๊ฒ์ ๋ถ๋ช ํ ์ ์ ์์
-
๊ฐํ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๋ ๊ฒ์ ์๋
-
์ฌ์ค ๋ชจ๋ ๋งค์ฐ ์ฝํ ๊ฒ์ผ๋ก ํ๋จ๋๋ค.
-
-
์ด๋ฌํ ๋ณ์๋ ์ ์ฒญ์๊ฐ ๋์ถ๊ธ์ ์ ๋ ์ํํ ์ง ์ฌ๋ถ๋ฅผ ์์ธกํ๋ ๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ์ ์ ์ฉํ๊ฒ ํ์ฉ๋ ๊ฐ๋ฅ์ฑ์ด ๋์
2-6. Pairs Plot
-
์ต์ข ํ์ ๊ทธ๋ํ๋ก
EXT_SOURCE
๋ณ์๋ค๊ณผDAYS_BIRTH
๋ณ์์ pairplot์ ๊ทธ๋ฆด ์ ์์ -
๋จ์ผ ๋ณ์์ ๋ถํฌ๋ฟ๋ง ์๋๋ผ ์ฌ๋ฌ ๋ณ์ ๊ฐ์ ์๊ด๊ด๊ณ๋ฅผ ํ์ ํ ์ ์์
# ์๊ฐํ๋ฅผ ์ํด ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌ
plot_data = ext_data.drop(columns = ['DAYS_BIRTH']).copy()
# ์ฐ๋๋ฅผ ๊ธฐ์ค์ผ๋ก ํ ๊ณ ๊ฐ์ ์ฐ๋ ฌ๋ ์ถ๊ฐ
plot_data['YEARS_BIRTH'] = age_data['YEARS_BIRTH']
# ๊ฒฐ์ธก์น ์ ๊ฑฐ, ์ถ๋ ฅ์ 100000๋ฒ์งธ ํ๊น์ง๋ง
plot_data = plot_data.dropna().loc[:100000, :]
### ๋ ๋ณ์ ์ฌ์ด์ ์๊ด๊ณ์๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํ ํจ์
def corr_func(x, y, **kwargs):
r = np.corrcoef(x, y)[0][1] # ์๊ด๊ณ์ ๊ณ์ฐ
ax = plt.gca()
ax.annotate("r = {:.2f}".format(r),
xy=(.2, .8), xycoords = ax.transAxes,
size = 10)
### ์๊ฐํ
# ๊ฐ์ฒด ์์ฑ
grid = sns.PairGrid(data = plot_data, diag_sharey=False,
hue = 'TARGET',
vars = [x for x in list(plot_data.columns) if x != 'TARGET'])
# ์๋ถ๋ถ: scatter plot
grid.map_upper(plt.scatter, alpha = 0.2)
# ์ฃผ๋๊ฐ์ ๋ถ๋ถ: kdeplot
grid.map_diag(sns.kdeplot)
# ์๋ ๋ถ๋ถ: density plot
grid.map_lower(sns.kdeplot, cmap = plt.cm.OrRd_r);
# ์ฐจํธ์ ์ด๋ฆ ์ง์
plt.suptitle('Ext Source and Age Features Pairs Plot', size = 20, y = 1.05);
-
๋นจ๊ฐ์: ์ํ๋์ง ์์ ๋์ถ(target = 1)/ ํ๋์: ์ง๊ธ๋ ๋์ถ(target = 0)
-
EXT_SOURCE_1
์DAYS_BIRTH
(๋๋ ์ด์ ๋๋ฑํYEARS_BIRTH
) ์ฌ์ด์๋ ์ค๊ฐ ์ ๋์ ์์ ์ ํ ๊ด๊ณ๊ฐ ์๋ ๊ฒ์ผ๋ก ๋ํ๋จ- ์ด ๊ธฐ๋ฅ์ด ํด๋ผ์ด์ธํธ์ ์ฐ๋ น์ ๊ณ ๋ คํ ์ ์์์ ๋ํ๋
3. ํน์ฑ ๊ณตํ(Feature Engineering)
-
Kaggle ๋ํ๋ Feature Engineering์ ์ํด ์ฐ์น์ฌ๋ถ๊ฐ ๊ฒฐ์ ๋จ
-
์ด๋ฌํ ๋ํ๋ค์ ๋ฐ์ดํฐ์์ ๊ฐ์ฅ ์ ์ฉํ feature์ ์์ฑํ ์ ์๋ ์ฌ๋์ด ์ฐ์น
-
๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ ๋ชจ๋ ์ฐ์น ๋ชจ๋ธ์ด ๊ทธ๋๋์ธํธ ๋ถ์คํ ์ ๋ณํ์ธ ๊ฒฝํฅ์ด ์๊ธฐ ๋๋ฌธ์ ๋๋ถ๋ถ ๋ง๋ ๋ง์
-
-
๊ทธ๋ฆฌ๊ณ ์ด๋ฌํ ๊ฒ๋ค์ ๋จธ์ ๋ฌ๋์ ํจํด ์ค ํ๋๋ฅผ ๋ํ๋
-
feature engineering์ด ๋ชจ๋ธ ๊ตฌ์ถ ๋ฐ hyperparameter ์กฐ์ ๋ณด๋ค ์ข์ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ
-
-
์ฌ๋ฐ๋ฅธ ๋ชจ๋ธ๊ณผ ์ต์ ์ ์ค์ ์ ์ ํํ๋ ๊ฒ์ด ์ค์ํ์ง๋ง ๋ชจ๋ธ์ ์ฃผ์ด์ง ๋ฐ์ดํฐ๋ฅผ ํตํด์๋ง ํ์ตํ ์ ์์
-
์ด ๋ฐ์ดํฐ๊ฐ ๊ฐ๋ฅํ ํ ์์ ๊ณผ ๊ด๋ จ์ด ์๋์ง ํ์ธํ๋ ๊ฒ์ด ๋ฐ์ดํฐ ๊ณผํ์์ ์ ๋ฌด์
-
-
Feature Engineering์ ์ผ๋ฐ์ ์ธ ํ๋ก์ธ์ค๋ฅผ ๋งํ๋ฉฐ,
feature ๊ตฌ์ฑ
(๊ธฐ์กด ๋ฐ์ดํฐ์์ ์๋ก์ด feature ์ถ๊ฐ)๊ณผfeature ์ ํ
(๊ฐ์ฅ ์ค์ํ feature๋ง ์ ํํ๊ฑฐ๋ ๋ค๋ฅธ ์ฐจ์ ์ถ์ ๋ฐฉ๋ฒ ์ฌ์ฉ ๋ฑ)์ ๋ชจ๋ ํฌํจํจ -
๋ค๋ฅธ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ฌ์ฉํ ๋ ๋ง์ feature engineering์ ์ํํ์ง๋ง ์ด ๋ ธํธ๋ถ์์๋ ๋ ๊ฐ์ง ๊ฐ๋จํ feature ๊ตฌ์ฑ ๋ฐฉ๋ฒ๋ง ์๋:
-
๋คํญ ๋ณ์(Polynomial features)
-
๋๋ฉ์ธ ์ง์ ๊ธฐ๋ฐ ๋ณ์(Domain knowledge features)
-
3-1. ๋คํญ ๋ณ์(Polynomial Features)
-
๊ฐ๋จํ feature ๊ตฌ์ฑ ๋ฐฉ๋ฒ ์ค ํ๋๋ polynomial features๊ฐ ์์
-
๊ธฐ์กด feature์ ์ ๊ณฑ๊ณผ ๊ธฐ์กด feature๋ค ๊ฐ์ ์ํธ ์์ฉ์ ํ๋ feature๋ค์ ์์ฑ
-
์๋ฅผ ๋ค์ด,
EXT_SOURCE_1^2
๋ฐEXT_SOURCE_2^2
๋ณ์์EXT_SOURCE_1 x EXT_SOURCE_2
,EXT_SOURCE_1 x EXT_SOURCE_2^2
,EXT_SOURCE_1^2 x EXT_SOURCE_2^2
๋ฑ๊ณผ ๊ฐ์ ๋ณ์๋ฅผ ์์ฑํ ์ ์์
-
-
์ฌ๋ฌ ๊ฐ๋ณ ๋ณ์์ ์กฐํฉ์ธ feature๋ค์ ๋ณ์ ๊ฐ์ ์ํธ ์์ฉ์ ๋ด๊ธฐ ๋๋ฌธ์ interaction terms๋ผ๊ณ ์นญํจ
- ๋ ๊ฐ์ ๋ณ์๊ฐ ๊ทธ ์์ฒด๋ก๋ target์ ํฐ ์ํฅ์ ๋ฏธ์น์ง ์์ ์ ์์ง๋ง, ์ด๋ค์ ํ๋์ interaction variable๋ก ๊ฒฐํฉํ๋ฉด target๊ณผ ์ ์๋ฏธํ ๊ด๊ณ๋ฅผ ๋ณด์ผ ์ ์์
-
interaction terms์ ์ฌ๋ฌ ๋ณ์๋ค์ ํจ๊ณผ๋ฅผ ๋ด๊ธฐ ์ํด ํต๊ณ ๋ชจ๋ธ์์ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋์ง๋ง, ๋จธ์ ๋ฌ๋์์๋ ์์ฃผ ์ฌ์ฉ๋์ง ์์
- ์ฌ๊ธฐ์๋ ๋ชจ๋ธ์ด ๊ณ ๊ฐ๋ค์ ๋์ถ ์ํ ์ฌ๋ถ๋ฅผ ์์ธกํ๋๋ฐ ๋์์ด ๋ ์ ์๋์ง ์์๋ณด๊ธฐ ์ํด ๋ช ๊ฐ์ง๋ฅผ ์๋ํด ๋ณผ ์์
-
๋ค์ ์ฝ๋์์๋
EXT_SOURCE
๋ณ์์DAYS_BIRTH
๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ polynomial feature๋ฅผ ์์ฑ -
Scikit - learn์๋ ์ง์ ๋ degree๊น์ง ๋คํญ์๊ณผ interaction terms์ ์์ฑํ๋
PolynomialFeatures
๋ผ๋ ์ ์ฉํ ํด๋์ค๊ฐ ์์- ์ฌ๊ธฐ์๋
degree = 3
์ ์ฌ์ฉ
- ์ฌ๊ธฐ์๋
-
polynomial feature์ ์์ฑํ ๋ feature์ ์๊ฐ degree์ ๋ฐ๋ผ ๊ธฐํ๊ธ์์ ์ผ๋ก ํ์ฅ๋๊ณ , overfitting ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๊ธฐ์, ๋๋ฌด ๋์ degree๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅ๋์ง ์์
### polynomial features๋ฅผ ์ํ ์๋ก์ด ์ปฌ๋ผ ์ง์
poly_features = app_train[['EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH', 'TARGET']]
poly_features_test = app_test[['EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH']]
### ๊ฒฐ์ธก์น ์ฒ๋ฆฌ๋ฅผ ์ํ Imputer
# Imputer ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์๋ฌ -> SimpleImputer๋ก ๋ณ๊ฒฝ
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy = 'median') # ๊ฒฐ์ธก์น๋ฅผ ์ค๊ฐ๊ฐ์ผ๋ก ๋์ฒด
### ๋คํญ ๋ณ์๋ค
poly_target = poly_features['TARGET']
poly_features = poly_features.drop(columns = ['TARGET'])
### ๊ฒฐ์ธก์น ์ฒ๋ฆฌ
poly_features = imputer.fit_transform(poly_features) # ํ์ต & ๋ณํ
## test ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ ํ์ต ๋ฐ์ดํฐ๋ก ํ์ต๋ ๋ณํ๊ธฐ๋ก "๋์ผ"ํ๊ฒ ๋ณํํด์ผ ํจ
poly_features_test = imputer.transform(poly_features_test) # ๋ณํ๋ง
### ๋คํญ ๋ณ์ ์์ฑ
from sklearn.preprocessing import PolynomialFeatures
poly_transformer = PolynomialFeatures(degree = 3)
### ๋ชจ๋ธ์ ๋คํญ ๋ณ์๋ค ๋ํ ํ์ต์ํค๊ธฐ
poly_transformer.fit(poly_features)
### feature ๋ณํ
poly_features = poly_transformer.transform(poly_features) # ํ์ต & ๋ณํ
poly_features_test = poly_transformer.transform(poly_features_test) # ๋ณํ๋ง
print('Polynomial Features shape: ', poly_features.shape)
Polynomial Features shape: (307511, 35)
-
๊ฝค ๋ง์ ์๋ก์ด feature๋ค์ด ์๋ก ์์ฑ๋จ
-
feature์ ์ด๋ฆ์ ์ป์ผ๋ ค๋ฉด
get_feature_names_out()
๋ฉ์๋๋ฅผ ์ฌ์ฉ
poly_transformer.get_feature_names_out(input_features = ['EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH'])[:15]
array(['1', 'EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH', 'EXT_SOURCE_1^2', 'EXT_SOURCE_1 EXT_SOURCE_2', 'EXT_SOURCE_1 EXT_SOURCE_3', 'EXT_SOURCE_1 DAYS_BIRTH', 'EXT_SOURCE_2^2', 'EXT_SOURCE_2 EXT_SOURCE_3', 'EXT_SOURCE_2 DAYS_BIRTH', 'EXT_SOURCE_3^2', 'EXT_SOURCE_3 DAYS_BIRTH', 'DAYS_BIRTH^2'], dtype=object)
-
35๊ฐ์ feature์ด ์์ผ๋ฉฐ ๊ฐ๋ณ feature์ ์ฐจ์(degree)๋ ์ต๋ 3๊น์ง ๋์์ง๋ฉฐ(3์ฐจํญ๊น์ง) interaction terms๊ฐ ์์ฑ๋จ
-
์๋ก์ด feature๋ค์ด target๊ณผ ์๊ด ๊ด๊ณ๊ฐ ์๋์ง ํ์ธ
### feature๋ค์ ๋ํ DataFrame ์์ฑ
poly_features = pd.DataFrame(poly_features,
columns = poly_transformer.get_feature_names_out(['EXT_SOURCE_1', 'EXT_SOURCE_2',
'EXT_SOURCE_3', 'DAYS_BIRTH']))
### Target ๊ฐ ์ถ๊ฐ
poly_features['TARGET'] = poly_target
### Target๊ณผ์ ์๊ด๋ ํ์
poly_corrs = poly_features.corr()['TARGET'].sort_values()
### ๊ฐ์ฅ ๊ฐํ ์์ ์๊ด๊ด๊ณ/ ์์ ์๊ด๊ด๊ณ
print(poly_corrs.head(10))
print(poly_corrs.tail(5))
EXT_SOURCE_2 EXT_SOURCE_3 -0.193939 EXT_SOURCE_1 EXT_SOURCE_2 EXT_SOURCE_3 -0.189605 EXT_SOURCE_2 EXT_SOURCE_3 DAYS_BIRTH -0.181283 EXT_SOURCE_2^2 EXT_SOURCE_3 -0.176428 EXT_SOURCE_2 EXT_SOURCE_3^2 -0.172282 EXT_SOURCE_1 EXT_SOURCE_2 -0.166625 EXT_SOURCE_1 EXT_SOURCE_3 -0.164065 EXT_SOURCE_2 -0.160295 EXT_SOURCE_2 DAYS_BIRTH -0.156873 EXT_SOURCE_1 EXT_SOURCE_2^2 -0.156867 Name: TARGET, dtype: float64 DAYS_BIRTH -0.078239 DAYS_BIRTH^2 -0.076672 DAYS_BIRTH^3 -0.074273 TARGET 1.000000 1 NaN Name: TARGET, dtype: float64
-
์๋ก์ด ๋ณ์ ์ค ์ผ๋ถ๋ ์๋ feature๋ณด๋ค target๊ณผ ๋ ํฐ(์ ๋๊ฐ) ์๊ด ๊ด๊ณ๊ฐ ์์
-
์๊ด๋๊ฐ ๋ ๋์์ง
-
๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ๊ตฌ์ถํ ๋ ์ด๋ฌํ feature์ด ์๋ ๊ฒฝ์ฐ์ ์๋ ๊ฒฝ์ฐ๋ฅผ ๋น๊ตํ์ฌ ๋คํญ ๋ณ์๋ค์ด ๋ชจ๋ธ ํ์ต์ ์ค์ ๋ก ๋์์ด ๋๋์ง ํ์ธ ๊ฐ๋ฅ
-
-
์ด๋ฌํ feature์ train, test ๋ฐ์ดํฐ ๋ณต์ฌ๋ณธ์ ์ถ๊ฐํ ๋ค์, ๋คํญ ๋ณ์๋ค์ด ์๋ ๋ชจ๋ธ๊ณผ ์๋ ๋ชจ๋ธ์ ๊ฐ๊ฐ ํ๊ฐ
- ์ผ๋จ ํด๋ด์ผ ์๋ค,,
### ๋ฐ์ดํฐ ํ๋ ์์ test data ์ฝ์
poly_features_test = pd.DataFrame(poly_features_test,
columns = poly_transformer.get_feature_names_out(['EXT_SOURCE_1', 'EXT_SOURCE_2',
'EXT_SOURCE_3', 'DAYS_BIRTH']))
### ํ์ต์ฉ df์ ๋คํญ ๋ณ์ ๋ณํฉ
poly_features['SK_ID_CURR'] = app_train['SK_ID_CURR']
app_train_poly = app_train.merge(poly_features, on = 'SK_ID_CURR', how = 'left')
### ํ๊ฐ์ฉ df์ ๋คํญ ๋ณ์ ๋ณํฉ
poly_features_test['SK_ID_CURR'] = app_test['SK_ID_CURR']
app_test_poly = app_test.merge(poly_features_test, on = 'SK_ID_CURR', how = 'left')
### df ์ ๋ ฌ
app_train_poly, app_test_poly = app_train_poly.align(app_test_poly, join = 'inner', axis = 1)
### ์๋ก ์์ฑ๋ df์ ํํ ์ถ๋ ฅ
print('Training data with polynomial features shape: ', app_train_poly.shape)
print('Testing data with polynomial features shape: ', app_test_poly.shape)
Training data with polynomial features shape: (307511, 275) Testing data with polynomial features shape: (48744, 275)
3-2. Domain Knowledge Features
-
์ ์ฉ ์ ๋ฌธ๊ฐ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ๋๋ฉ์ธ ์ง์์ด๋ผ๊ณ ๋ถ๋ฅด๋ ๊ฒ์ด ์ณ์ง ์์ ์๋ ์์ง๋ง, ์ด๊ฒ์ ์ ํ๋ ๊ธ์ต ์ง์์ ์ ์ฉํ๋ ค๋ ์๋๋ผ๊ณ ๋ถ๋ฅผ ์ ์์
-
๋ฐ๋ผ์, ๊ณ ๊ฐ์ ์ฑ๋ฌด ๋ถ์ดํ ์ฌ๋ถ๋ฅผ ์๋ ค์ฃผ๋ ๋ฐ ์ค์ํ๋ค๊ณ ์๊ฐํ๋ ๊ฒ์ ๋ด์๋ด๋ ๋ช ๊ฐ์ง feature๋ค์ ์์ฑํ ์ ์์
-
CREDIT_INCOME_PERCENT: ๊ณ ๊ฐ์ ์์ ์ ๋ํ ์ ์ฉ ๊ธ์ก์ ๋ฐฑ๋ถ์จ
-
ANNUITY_INCOME_PERCENT: ๊ณ ๊ฐ์ ์๋์ ๋ํ ์ฐ๊ธ ๋์ถ์ ๋น์จ
-
CREDIT_TERM: ์ง๋ถ ๊ธฐ๊ฐ(์ ๋จ์๋ก ์ง๋ถํด์ผ ํ๋ ๊ธฐ๊ฐ, ์ฐ๊ธ์ ๋งค์ ์ง๋ถํด์ผ ํ๋ ๊ธ์ก์ด๋ฏ๋ก)
-
DAYS_EMPLOYED_PERCENT: ๊ณ ๊ฐ์ ๋์ด์ ๋ํ ๊ณ ์ฉ ์ผ์์ ๋ฐฑ๋ถ์จ
-
-
### ๋๋ฉ์ธ ์ง์์ ๊ธฐ๋ฐ์ผ๋ก ์ฌ๋ฌ ๋ณ์๋ค์ ์์ฑ
app_train_domain = app_train.copy()
app_test_domain = app_test.copy()
app_train_domain['CREDIT_INCOME_PERCENT'] = app_train_domain['AMT_CREDIT'] / app_train_domain['AMT_INCOME_TOTAL']
app_train_domain['ANNUITY_INCOME_PERCENT'] = app_train_domain['AMT_ANNUITY'] / app_train_domain['AMT_INCOME_TOTAL']
app_train_domain['CREDIT_TERM'] = app_train_domain['AMT_ANNUITY'] / app_train_domain['AMT_CREDIT']
app_train_domain['DAYS_EMPLOYED_PERCENT'] = app_train_domain['DAYS_EMPLOYED'] / app_train_domain['DAYS_BIRTH']
app_test_domain['CREDIT_INCOME_PERCENT'] = app_test_domain['AMT_CREDIT'] / app_test_domain['AMT_INCOME_TOTAL']
app_test_domain['ANNUITY_INCOME_PERCENT'] = app_test_domain['AMT_ANNUITY'] / app_test_domain['AMT_INCOME_TOTAL']
app_test_domain['CREDIT_TERM'] = app_test_domain['AMT_ANNUITY'] / app_test_domain['AMT_CREDIT']
app_test_domain['DAYS_EMPLOYED_PERCENT'] = app_test_domain['DAYS_EMPLOYED'] / app_test_domain['DAYS_BIRTH']
โบ ์๋ก์ด ๋ณ์๋ค์ ์๊ฐํ
-
๋๋ฉ์ธ ์ง์ ๋ณ์๋ค์ ๊ทธ๋ํ์์ ์๊ฐ์ ์ผ๋ก ํ๊ตฌ
-
Target
๊ฐ์ ๋ฐ๋ผ ์์ ๋ค๋ฅด๊ฒ ์ ์ฉํ kdeplot์ผ๋ก ์๊ฐํ
plt.figure(figsize = (12, 20))
### ์๋ก ์์ฑํ feature๋ค์ ์ํ์ํค๋ฉฐ
for i, feature in enumerate(['CREDIT_INCOME_PERCENT', 'ANNUITY_INCOME_PERCENT', 'CREDIT_TERM', 'DAYS_EMPLOYED_PERCENT']):
# ๊ฐ ๋ณ์๋ค์ ๋ํด subplot ์์ฑ
plt.subplot(4, 1, i + 1)
# ์ ๋ ์ํ๋ ๋์ถ
sns.kdeplot(app_train_domain.loc[app_train_domain['TARGET'] == 0, feature], label = 'target == 0')
# ์ ๋ ์ํ๋์ง ๋ชปํ ๋์ถ
sns.kdeplot(app_train_domain.loc[app_train_domain['TARGET'] == 1, feature], label = 'target == 1')
# Plot Labeling
plt.title('Distribution of %s by Target Value' % feature)
plt.xlabel('%s' % feature); plt.ylabel('Density');
plt.tight_layout(h_pad = 2.5)
-
์์ ๊ทธ๋ํ๋ค์ ๋ณด๋ฉด ์๋ก ๋ง๋ feature๋ค์ด ์ ์ฉํ์ง ๋ถํ์คํจ
- ๋ฐ๋ผ์, ๊ทธ๋ฅ ์ด feature๋ค์ ๊ฐ์ง๊ณ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ํ์ธํด๋ด ๋๋ค.(Just Do it)
(+) ๊ฐ์ธ์ ์ธ ์๊ฐ
-
feature๋ค์ ์๊ณก ์ ๋๊ฐ ๋๋ฌด ์ฌํจ(skewed data)
- ํ๊ท ๋ฌธ์ ์์๋ ์คํ๋ ค ๋ชจ๋ธ์ด overfitting๋๋ ๋ฌธ์ ๋ฅผ ์ด๋ํ ์ ์์
4. Baseline ๋ชจ๋ธ๋ค
-
๋จ์ํ baseline ๋ชจ๋ธ์ ๊ฒฝ์ฐ test set์ ๋ชจ๋ ์์ ์ ๋ํด ๋์ผํ ๊ฐ์ ์ถ์ธกํ ์ ์์
- ๋์ถ๊ธ์ ์ํํ์ง ์์ ํ๋ฅ (target = 1)์ ์์ธกํ๋ผ๋ ์์ฒญ์ ๋ฐ์๊ธฐ ๋๋ฌธ์, ์์ ํ ๋ถํ์คํ ๊ฒฝ์ฐ ๊ฒ์ ์ธํธ์ ๋ชจ๋ ๊ด์ธก์น์ ๋ํด 0.5๋ฅผ ์ถ์ธกํ ์ ์์(
๊ทธ๋ฅ ์ ๋ฐ์ผ๋ก ์ฐ์ด๋ฒ๋ฆฌ๋๊ฑฐ์ง)
- ๋์ถ๊ธ์ ์ํํ์ง ์์ ํ๋ฅ (target = 1)์ ์์ธกํ๋ผ๋ ์์ฒญ์ ๋ฐ์๊ธฐ ๋๋ฌธ์, ์์ ํ ๋ถํ์คํ ๊ฒฝ์ฐ ๊ฒ์ ์ธํธ์ ๋ชจ๋ ๊ด์ธก์น์ ๋ํด 0.5๋ฅผ ์ถ์ธกํ ์ ์์(
-
์ค์ baseline์ ๋นํด ์กฐ๊ธ ๋ ์ ๊ตํ ๋ชจ๋ธ์ธ LogisticRegression์ ํ์ฉ
4-1. Logistic Regression
-
Baseline์ ์ป๊ธฐ ์ํด ๋ฒ์ฃผํ ๋ณ์๋ฅผ ์ธ์ฝ๋ฉ ํ ํ ๋ชจ๋ feature๋ฅผ ํ์ฉ
- ๊ฒฐ์ธก์น๋ฅผ ์ฑ์ฐ๊ณ feature๋ค์ ๋ฒ์๋ฅผ ์ ๊ทํ(normalize)ํ์ฌ ์ ์ฒ๋ฆฌ => Feature Scaling
from sklearn.preprocessing import MinMaxScaler
from sklearn.impute import SimpleImputer
### ์ผ๋จ train data์์ target๊ฐ์ ์ ๊ฑฐ
if 'TARGET' in app_train:
train = app_train.drop(columns = ['TARGET'])
else:
train = app_train.copy()
### ๋ณ์ ๋ชฉ๋ก
features = list(train.columns)
### test data ๋ณต์ฌ
test = app_test.copy()
### ๊ฒฐ์ธก์น: ์ค๊ฐ๊ฐ์ผ๋ก ๋์ฒด
imputer = SimpleImputer(strategy = 'median')
### ๋ฐ์ดํฐ ๋ฒ์๋ฅผ 0 ~ 1๋ก ์กฐ์
scaler = MinMaxScaler(feature_range = (0, 1))
### ๊ฒฐ์ธก์น ์ฒ๋ฆฌ
imputer.fit(train) # imputer๋ฅผ ํ์ต ๋ฐ์ดํฐ๋ก ํ์ต์ํค๊ณ
train = imputer.transform(train) # ๋ณํ!
test = imputer.transform(app_test) # train data๋ฅผ ๋ณํ์ํจ imputer๋ฅผ ๊ฐ์ง๊ณ "๊ทธ๋๋ก" ๋ณํ
### Scaling
scaler.fit(train)
train = scaler.transform(train)
test = scaler.transform(test)
print('Training data shape: ', train.shape)
print('Testing data shape: ', test.shape)
Training data shape: (307511, 240) Testing data shape: (48744, 240)
-
์ฐ๋ฆฌ๋ ์ฒซ ๋ฒ์งธ ๋ชจ๋ธ์ ๋ํด Scikit-Learn์ ```LogisticRegression``์ ์ฌ์ฉํ ๊ฒ์
-
๊ธฐ๋ณธ ๋ชจ๋ธ์์ ์ ์ผํ๊ฒ ๋ณ๊ฒฝํ ํ์ดํผํ๋ผ๋ฏธํฐ๋ overfitting์ ์์ ์ ์ดํ๋ ์ ๊ทํ ๋งค๊ฐ๋ณ์์ธ C๋ฅผ ๋ฎ์ถ๋ ๊ฒ์
- ๋ฎ์ ๊ฐ์ ๊ณผ์ ํฉ์ ์ค์
### ๋ก์ง์คํฑ ํ๊ท ์ ์ฉ
from sklearn.linear_model import LogisticRegression
# ๋ชจ๋ธ ๊ฐ์ฒด ์์ฑ
log_reg = LogisticRegression(C = 0.0001)
# model fitting(ํ์ต)
log_reg.fit(train, train_labels)
LogisticRegression(C=0.0001)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LogisticRegression(C=0.0001)
-
์ด์ ๋ชจ๋ธ์ด ํ์ต๋์์ผ๋ฏ๋ก ์์ธก์ ์ํํ ์ ์์
-
predict_proba()
๋ฉ์๋๋ฅผ ํตํด ๋์ถ์ ๊ฐ์ง ์์(target = 1) ํ๋ฅ ์ ์์ธก-
์ฒซ ๋ฒ์งธ ์ด์ ๋์์ด 0์ผ ํ๋ฅ ์ด๊ณ , ๋ ๋ฒ์งธ ์ด์ ๋์์ด 1์ผ ํ๋ฅ ์
-
๋จ์ผ ํ์ ๊ฒฝ์ฐ ๋ ์ด์ ํฉ์ด 1์ด์ด์ผ ํจ
-
๋์ถ์ด ์ํ๋์ง ์์(target = 1) ํ๋ฅ ์ ์ํ๋ฏ๋ก ๋ ๋ฒ์งธ ์ด์ ์ ํ
-
### ์์ธก
# ๋์ถ์ ์ํํ์ง ์์ ํ๋ฅ ๋ง ์ ํ
log_reg_pred = log_reg.predict_proba(test)[:, 1]
### ์ ์ถ์ฉ DataFrame
submit = app_test[['SK_ID_CURR']]
submit['TARGET'] = log_reg_pred
submit.head()
SK_ID_CURR | TARGET | |
---|---|---|
0 | 100001 | 0.078515 |
1 | 100005 | 0.137926 |
2 | 100013 | 0.082194 |
3 | 100028 | 0.080921 |
4 | 100038 | 0.132618 |
-
์์ธก์ ๋์ถ์ด ์ํ๋์ง ์์(target = 1) ํ๋ฅ ์ด 0๊ณผ 1 ์ฌ์ด์์ ๋ํ๋
- ๋์ถ์ด ์ํํ๋ค๋ ๊ฒ์ ๊ฒฐ์ ํ๊ธฐ ์ํ ํ๋ฅ ์๊ณ๊ฐ์ ์ค์ ํ ์ ์์
# Save the submission to a csv file
submit.to_csv('log_reg_baseline.csv', index = False)
- ์ ์๋ ์ฝ 0.671
4-2. Improved Model: Random Forest
-
๋์ผํ train ๋ฐ์ดํฐ์์ RandomForest๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ์ ํฅ์์์ผ๋ณด์.
-
๋๋ค ํฌ๋ ์คํธ๋ ํนํ ์ฐ๋ฆฌ๊ฐ ์๋ฐฑ ๊ฐ์ ํธ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ํจ์ฌ ๋ ๊ฐ๋ ฅํ ๋ชจ๋ธ์
-
n_estimators = 100
์ผ๋ก ์ค์
from sklearn.ensemble import RandomForestClassifier
### RandomForest ๊ฐ์ฒด ์์ฑ
random_forest = RandomForestClassifier(n_estimators = 100, random_state = 50,
verbose = 1, n_jobs = -1)
### ๋ชจ๋ธ ํ์ต
random_forest.fit(train, train_labels)
### ํผ์ฒ ์ค์๋ ํ์ธ
feature_importance_values = random_forest.feature_importances_
feature_importances = pd.DataFrame({'feature': features, 'importance': feature_importance_values})
### test data๋ฅผ ์ด์ฉํด ์์ธก ์ํ
predictions = random_forest.predict_proba(test)[:, 1]
[Parallel(n_jobs=-1)]: Using backend ThreadingBackend with 2 concurrent workers. [Parallel(n_jobs=-1)]: Done 46 tasks | elapsed: 1.7min [Parallel(n_jobs=-1)]: Done 100 out of 100 | elapsed: 3.5min finished [Parallel(n_jobs=2)]: Using backend ThreadingBackend with 2 concurrent workers. [Parallel(n_jobs=2)]: Done 46 tasks | elapsed: 0.8s [Parallel(n_jobs=2)]: Done 100 out of 100 | elapsed: 2.3s finished
### ๋ํ ์ ์ถ์ฉ ์ฝ๋
submit = app_test[['SK_ID_CURR']]
submit['TARGET'] = predictions
submit.to_csv('random_forest_baseline.csv', index = False)
- ์ ์๋ ์ฝ 0.678
- Engineered Features๋ก ์์ธกํ๊ธฐ
-
Polynomial Features ๋ฐ ๋๋ฉ์ธ ์ง์์ด ๋ชจ๋ธ์ ๊ฐ์ ํ๋์ง ํ์ธํ๋ ์ ์ผํ ๋ฐฉ๋ฒ์ ์ด๋ฌํ feature์ ๋ํ ํ ์คํธ ๋ชจ๋ธ์ ์ง์ ํ๋ จ์ํค๋ ๋ฐฉ๋ฒ๋ฐ์ ์๋ฆ
- ์ด๋ฌํ feature๋ค์ด ์๋ ๋ชจ๋ธ์ performance์ ๋น๊ตํ์ฌ feature engineering์ ํจ๊ณผ๋ฅผ ์ธก์
โบTesting polynomial features
poly_features_names = list(app_train_poly.columns) # Polynomial feature๋ค์ ๋ชฉ๋ก
### ๊ฒฐ์ธก์น๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ ์ค์๊ฐ์ผ๋ก ๋์ฒด
imputer = SimpleImputer(strategy = 'median')
poly_features = imputer.fit_transform(app_train_poly)
poly_features_test = imputer.transform(app_test_poly)
### Scaling
scaler = MinMaxScaler(feature_range = (0, 1))
poly_features = scaler.fit_transform(poly_features)
poly_features_test = scaler.transform(poly_features_test)
### ๋ชจ๋ธ ๊ฐ์ฒด ์์ฑ
random_forest_poly = RandomForestClassifier(n_estimators = 100, random_state = 50,
verbose = 1, n_jobs = -1)
### ๋ชจ๋ธ ํ์ต
random_forest_poly.fit(poly_features, train_labels)
### ์์ธก
predictions = random_forest_poly.predict_proba(poly_features_test)[:, 1]
[Parallel(n_jobs=-1)]: Using backend ThreadingBackend with 2 concurrent workers. [Parallel(n_jobs=-1)]: Done 46 tasks | elapsed: 2.2min [Parallel(n_jobs=-1)]: Done 100 out of 100 | elapsed: 4.9min finished [Parallel(n_jobs=2)]: Using backend ThreadingBackend with 2 concurrent workers. [Parallel(n_jobs=2)]: Done 46 tasks | elapsed: 0.5s [Parallel(n_jobs=2)]: Done 100 out of 100 | elapsed: 1.0s finished
### ์ ์ถ์ฉ ์ฝ๋
submit = app_test[['SK_ID_CURR']]
submit['TARGET'] = predictions
submit.to_csv('random_forest_baseline_engineered.csv', index = False)
-
์ ์: ์ฝ 0.678
- ๋คํญ ๋ณ์๋ค์ ์ ์ฉ์ํค ์์์ ๋์ ์ฑ๋ฅ์ด ๋์ผ
โบ Testing domain features
# ์ผ๋จ target์ ๋นผ๊ณ ๋ฐ์ดํฐ ๊ฐ๊ณต
app_train_domain = app_train_domain.drop(columns = 'TARGET')
domain_features_names = list(app_train_domain.columns)
### ๊ฒฐ์ธก์น๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ "์ค์๊ฐ"์ผ๋ก ๋์ฒด
imputer = SimpleImputer(strategy = 'median')
domain_features = imputer.fit_transform(app_train_domain)
domain_features_test = imputer.transform(app_test_domain)
### Scaling
scaler = MinMaxScaler(feature_range = (0, 1))
domain_features = scaler.fit_transform(domain_features)
domain_features_test = scaler.transform(domain_features_test)
### ๋ชจ๋ธ ๊ฐ์ฒด ์์ฑ
random_forest_domain = RandomForestClassifier(n_estimators = 100, random_state = 50,
verbose = 1, n_jobs = -1)
### ๋ชจ๋ธ ํ์ต
random_forest_domain.fit(domain_features, train_labels)
### feature ์ค์๋ ํ์ธ
feature_importance_values_domain = random_forest_domain.feature_importances_
feature_importances_domain = pd.DataFrame({'feature': domain_features_names,
'importance': feature_importance_values_domain})
### ์์ธก
predictions = random_forest_domain.predict_proba(domain_features_test)[:, 1]
[Parallel(n_jobs=-1)]: Using backend ThreadingBackend with 2 concurrent workers. [Parallel(n_jobs=-1)]: Done 46 tasks | elapsed: 1.4min [Parallel(n_jobs=-1)]: Done 100 out of 100 | elapsed: 3.1min finished [Parallel(n_jobs=2)]: Using backend ThreadingBackend with 2 concurrent workers. [Parallel(n_jobs=2)]: Done 46 tasks | elapsed: 1.3s [Parallel(n_jobs=2)]: Done 100 out of 100 | elapsed: 2.9s finished
### ์ ์ถ์ฉ ์ฝ๋
submit = app_test[['SK_ID_CURR']]
submit['TARGET'] = predictions
submit.to_csv('random_forest_baseline_domain.csv', index = False)
-
์ ์ถํ์ ๋ 0.679์ ์ ์ป์์
- ๊ฐ๊ณต๋ feature๋ค์ด ํด๋น ๋ชจ๋ธ์์๋ ๋์์ด ๋์ง ์๋๋ค๋ ๊ฒ์ ์๋ฏธ
4-3.๋ณ์ ์ค์๋(Feature Importances)
-
์ด๋ค ๋ณ์๊ฐ ๊ฐ์ฅ ๊ด๋ จ์ด ์๋์ง ํ์ธํ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ผ๋ก RandomForest์ feature importances๋ฅผ ํ์ธํ๋ ๋ฐฉ๋ฒ์ด ์์
-
Exploratory Data Analysis(EDA)์์ ๋ณธ ์๊ด ๊ด๊ณ๋ฅผ ๊ณ ๋ คํ ๋ ๊ฐ์ฅ ์ค์ํ feature๋
EXT_SOURCE
๋ฐDAYS_BIRTH
์ผ ๊ฒ์ผ๋ก ์์ํ ์ ์์ -
์ดํ ์ฐจ์ ์ถ์ ์์ ์ด๋ฌํ feature importances๋ฅผ ํ์ฉํ ์ ์์
Feature ์ค์๋ ์๊ฐํ
-
๋ชจํ์์ ๋ฐํ๋ ์ค์๋ ๊ทธ๋ฆผ์ ํ์
- ์ค์๋๊ฐ ๋์์๋ก feature ์ค์๋์ ๋ชจ๋ ์ฒ๋์์ ์๋ํ ์ ์์
-
Arguments>
-
df(๋ฐ์ดํฐ ํ๋ ์):
-
ํผ์ณ ์ค์๋
-
features
์ปฌ๋ผ์ ๋ณ์๋ค์ด ์๊ณimportance
์ปฌ๋ผ์ ์ค์๋๊ฐ ์์
-
-
-
Return>
- ๊ฐ์ฅ ์ค์ํ 15๊ฐ์ง feature๋ค์ ๋ํด ์๊ฐํ
def plot_feature_importances(df):
### ์ค์๋ ์์๋๋ก feature๋ค์ ์ ๋ ฌ
df = df.sort_values('importance', ascending = False).reset_index()
### feature ์ค์๋ ์ ๊ทํ(๋ค ํฉ์ณ์ 1์ด ๋๊ฒ)
df['importance_normalized'] = df['importance'] / df['importance'].sum()
### ๊ฐ๋ก ๋ง๋ ๊ทธ๋ฆฌ๊ธฐ(์ค์๋ โ ๊ธธ์ด)
plt.figure(figsize = (10, 6))
ax = plt.subplot()
ax.barh(list(reversed(list(df.index[:15]))), # ์ค์ํ ๊ฒ๋ถํฐ ํ์ํด์ผ ํ๋ฏ๋ก index๋ฅผ ๊ฑฐ๊พธ๋ก
df['importance_normalized'].head(15),
align = 'center', edgecolor = 'k')
### ์ถ ์ค์
ax.set_yticks(list(reversed(list(df.index[:15]))))
ax.set_yticklabels(df['feature'].head(15))
plt.xlabel('Normalized Importance'); plt.title('Feature Importances')
plt.show()
return df
feature_importances_sorted = plot_feature_importances(feature_importances)
-
์์๋๋ก ๊ฐ์ฅ ์ค์ํ feature๋ค์
EXT_SOURCE
์DAYS_BIRTH
์ -
์์ ๊ทธ๋ํ๋ฅผ ๋ณด๋ฉด ๋ชจ๋ธ์ ๋์ importance์ ์ง๋ feature๋ค์ ์์์ ๋ถ๊ณผํ ๊ฒ์ ํ์ ํ ์ ์์
- ์ฑ๋ฅ ์ ํ ์์ด ๋ง์ feature๋ค์ ์ญ์ ํ ์ ์์์ ์์ฌ(์กฐ๊ธ ๋จ์ด์ง ์๋ ์์)
-
feature importance๋ ๋ชจ๋ธ์ ํด์ํ๊ฑฐ๋ ์ฐจ์ ์ถ์๋ฅผ ํ๋ ๊ฐ์ฅ ์ ๊ตํ ๋ฐฉ๋ฒ์ ์๋์ง๋ง, ์์ธก์ ํ ๋ ๋ชจ๋ธ์ด ๊ณ ๋ คํ๋ ์์๋ฅผ ์ดํดํ ์ ์๊ฒ ํด์ค
feature_importances_domain_sorted = plot_feature_importances(feature_importances_domain)
-
์์ผ๋ก ์์ง๋์ด๋งํ 4๊ฐ์ง feature ๋ชจ๋ feature importances ์์ 15์ ์์ ๋ค์์
CREDIT_TERM
,ANNUITY_INCOME_PERCENT
,CREDIT_INCOME_PERCENT
,DAYS_EMPLOYED_PERCENT
-
๋๋ฉ์ธ ์ง์์ด ๋ชจ๋ธ ์ฑ๋ฅ์ ํจ๊ณผ๊ฐ ์์๋ค.
5. ์ถ๊ฐ ํ์ต_ Light Gradient Boosting Machine
-
Gradient Boosting Machine์ ํ์ฌ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ ์ธํธ์ ๋ํ ํ์ต์ ์ํ ์ ๋์ ์ธ ๋ชจ๋ธ์
(ํนํ Kaggle)
-
๊ต์ฐจ ๊ฒ์ฆ(Cross Validation)์ ์ฌ์ฉํ์ฌ LGBM ๋ชจ๋ธ์ train/test
-
Parameters>
-
features(pd.DataFrame):
-
ํ์ต์ ์ฌ์ฉํ training features
-
๋ฐ๋์
target
์ปฌ๋ผ์ ํฌํจํด์ผ ํจ
-
-
test_features(pd.DataFrame):
- ๋ชจํ์ ์ฌ์ฉํ์ฌ ์์ธกํ๋ ๋ฐ ์ฌ์ฉํ ๊ฒ์ฆ์ฉ ๋ฐ์ดํฐ
-
encoding(str, default = โoheโ):
-
๋ณ์๋ฅผ ์ธ์ฝ๋ฉํ๋ ๋ฐฉ๋ฒ
-
one-hot encoding(-> ๋ฒ์ฃผํ ๋ณ์)์ธ ๊ฒฝ์ฐ
ohe
, label encoding(-> ์ซ์ํ ๋ณ์)์ธ ๊ฒฝ์ฐle
-
-
n_folds(int, default = 5):
- ๊ต์ฐจ ๊ฒ์ฆ์ ์ฌ์ฉํ folds ์
-
-
Return>
-
submission(pd.DataFrame):
- ๋ชจ๋ธ์ ์ํด ์์ธก๋
SK_ID_CURR
๊ฐ๊ณผTARGET
ํ๋ฅ ์ ๊ฐ์ง df
- ๋ชจ๋ธ์ ์ํด ์์ธก๋
-
feature_importances(pd.DataFrame):
- ๋ชจ๋ธ์์ feature๋ค์ ์ค์๋์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํ๊ณ ์๋ df
-
valid_metrics(pd.DataFrame):
- ๊ฐ fold์ ์ ์ฒด์ ์ธ ๋ถ๋ถ์์์ training๊ณผ validation ์ ์(ROC-AUC)๊ฐ ์ ์ฅ๋จ
-
from sklearn.model_selection import KFold
from sklearn.metrics import roc_auc_score
import lightgbm as lgb
import gc
def model(features, test_features, encoding = 'ohe', n_folds = 5):
### ๋ฐ์ดํฐ ์ค๋น
# id ์ถ์ถ
train_ids = features['SK_ID_CURR']
test_ids = test_features['SK_ID_CURR']
# label ์ถ์ถ -> for training
labels = features['TARGET']
# id์ target ์ ๊ฑฐ
features = features.drop(columns = ['SK_ID_CURR', 'TARGET'])
test_features = test_features.drop(columns = ['SK_ID_CURR'])
# --------------------------------------------------------------
### Encoding
## ๋ฒ์ฃผํ ๋ณ์: One-Hot Encoding
if encoding == 'ohe':
features = pd.get_dummies(features)
test_features = pd.get_dummies(test_features)
# ๋ฐ์ดํฐ ํ๋ ์์ column๋ค์ ํต์ผ์ํค๊ธฐ
features, test_features = features.align(test_features, join = 'inner', axis = 1)
# ๋ฐ๋ก ๊ธฐ๋กํ ๋ฒ์ฃผํ ์ธ๋ฑ์ค๋ x
cat_indices = 'auto'
## ์์นํ ๋ณ์: Label Encoding
elif encoding == 'le':
# encoder ๊ฐ์ฒด ์์ฑ
label_encoder = LabelEncoder()
# ๋ฒ์ฃผํ ๋ณ์๋ค์ ์ ์ฅํ๊ธฐ ์ํ list
cat_indices = []
# ๊ฐ ์ปฌ๋ผ๋ง๋ค ๋ฐ๋ณตํ๋ฉฐ
for i, col in enumerate(features):
if features[col].dtype == 'object': # ๋ฒ์ฃผํ ๋ณ์
# ๋ฒ์ฃผํ ๋ณ์๋ฅผ ์ ์(integer)๋ก ๋งคํ
features[col] = label_encoder.fit_transform(np.array(features[col].astype(str)).reshape((-1,)))
test_features[col] = label_encoder.transform(np.array(test_features[col].astype(str)).reshape((-1,)))
# ๋ฒ์ฃผํ ๋ณ์๋ค์ ์ ์ฅ
cat_indices.append(i)
## ์ ํจํ์ง ์์ ์ธ์ฝ๋ฉ ๋ฐฉ์ ์
๋ ฅ ์ ์ค๋ฅ
else:
raise ValueError("Encoding must be either 'ohe' or 'le'")
# --------------------------------------------------------------------------
### ๊ฐ๊ณต๋ ๋ฐ์ดํฐ ํํ ํ์ธํ๊ธฐ
print('Training Data Shape: ', features.shape)
print('Testing Data Shape: ', test_features.shape)
### feature ์ด๋ฆ ์ถ์ถ
feature_names = list(features.columns)
### np array๋ก ๋ณํ
features = np.array(features)
test_features = np.array(test_features)
# -------------------------------------------------------------------------
### ๊ต์ฐจ ๊ฒ์ฆ
# KFold ๊ฐ์ฒด ์์ฑ
k_fold = KFold(n_splits = n_folds, shuffle = True, random_state = 50)
# feature ์ค์๋๋ฅผ ์ ์ฅํ ๋น array ์์ฑ
feature_importance_values = np.zeros(len(feature_names))
# ์์ธก๊ฐ์ ์ ์ฅํ๊ธฐ ์ํ ๋น array ์์ฑ
test_predictions = np.zeros(test_features.shape[0])
# ํ๋ณธ ์ธ(out of fold) ๊ฒ์ฆ ๋ฐ์ดํฐ ์์ธก์ ์ํ arrau
out_of_fold = np.zeros(features.shape[0])
# --------------------------------------------------------------------------
### Modeling
# ๊ฒ์ฆ/ ํ์ต ์ํ ํ ์ ์๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๋ฆฌ์คํธ
valid_scores = []
train_scores = []
# ๊ฐ fold๋ฅผ ๋ฐ๋ณตํ๋ฉฐ
for train_indices, valid_indices in k_fold.split(features):
## ๋ฐ์ดํฐ ์ค๋น
# fold์์์ ํ๋ จ ๋ฐ์ดํฐ
train_features, train_labels = features[train_indices], labels[train_indices]
# fold์์์ ๊ฒ์ฆ ๋ฐ์ดํฐ
valid_features, valid_labels = features[valid_indices], labels[valid_indices]
## ๋ชจ๋ธ ๊ฐ์ฒด ์์ฑ
model = lgb.LGBMClassifier(n_estimators = 10000, objective = 'binary',
class_weight = 'balanced', learning_rate = 0.05,
reg_alpha = 0.1, reg_lambda = 0.1,
subsample = 0.8, n_jobs = -1, random_state = 50)
## ๋ชจ๋ธ ํ์ต
model.fit(train_features, train_labels, eval_metric = 'auc',
eval_set = [(valid_features, valid_labels), (train_features, train_labels)],
eval_names = ['valid', 'train'], categorical_feature = cat_indices,
early_stopping_rounds = 100, verbose = 200)
# ๊ฐ์ฅ ์ฑ๋ฅ์ด ์ข์ iteration ๊ธฐ๋ก
best_iteration = model.best_iteration_
# ํผ์ฒ ์ค์๋ ๊ธฐ๋ก
feature_importance_values += model.feature_importances_ / k_fold.n_splits
## ์์ธก
test_predictions += model.predict_proba(test_features, num_iteration = best_iteration)[:, 1] / k_fold.n_splits
# ํ๋ณธ/์์ธก ์ ์ฅ
out_of_fold[valid_indices] = model.predict_proba(valid_features, num_iteration = best_iteration)[:, 1]
# ๊ฐ์ฅ ์ข์ ์ ์ ๊ธฐ๋ก
valid_score = model.best_score_['valid']['auc']
train_score = model.best_score_['train']['auc']
valid_scores.append(valid_score)
train_scores.append(train_score)
## ๋ฉ๋ชจ๋ฆฌ ์ด๊ธฐํ
gc.enable()
del model, train_features, valid_features
gc.collect()
# --------------------------------------------------------------------------
### ์ ์ถ์ฉ ํ์ผ ๋ง๋ค๊ธฐ
submission = pd.DataFrame({'SK_ID_CURR': test_ids, 'TARGET': test_predictions})
### ํผ์ฒ ์ค์๋ dataframe
feature_importances = pd.DataFrame({'feature': feature_names, 'importance': feature_importance_values})
### ์ ์ฒด ๋ฐ์ดํฐ์ validation score ์ธก์
valid_auc = roc_auc_score(labels, out_of_fold)
### ์ ์ฒด ๋ฐ์ดํฐ์ ๋ํ score๋ฅผ metric์ ์ถ๊ฐ
valid_scores.append(valid_auc)
train_scores.append(np.mean(train_scores))
### validation score๋ฅผ ์ํ ๋ฐ์ดํฐํ๋ ์ ์์ฑ
fold_names = list(range(n_folds))
fold_names.append('overall')
### training ๋ฐ validation score๊ฐ ์ ์ฅ๋ df
metrics = pd.DataFrame({'fold': fold_names,
'train': train_scores,
'valid': valid_scores})
return submission, feature_importances, metrics
โบ ๊ธฐ๋ณธ ๋ฐ์ดํฐ๋ก ํ์ต
### ์ฑ๋ฅ ํ๊ฐ
submission, fi, metrics = model(app_train, app_test)
print('Baseline metrics')
print(metrics)
Training Data Shape: (307511, 239) Testing Data Shape: (48744, 239) [200] train's auc: 0.798723 train's binary_logloss: 0.547797 valid's auc: 0.755039 valid's binary_logloss: 0.563266 [400] train's auc: 0.82838 train's binary_logloss: 0.518334 valid's auc: 0.755107 valid's binary_logloss: 0.545575 [200] train's auc: 0.798409 train's binary_logloss: 0.548179 valid's auc: 0.758332 valid's binary_logloss: 0.563587 [400] train's auc: 0.828244 train's binary_logloss: 0.518308 valid's auc: 0.758563 valid's binary_logloss: 0.545588 [200] train's auc: 0.797648 train's binary_logloss: 0.549331 valid's auc: 0.763246 valid's binary_logloss: 0.564236 [200] train's auc: 0.798855 train's binary_logloss: 0.547952 valid's auc: 0.757131 valid's binary_logloss: 0.562234 [200] train's auc: 0.797918 train's binary_logloss: 0.548584 valid's auc: 0.758065 valid's binary_logloss: 0.564721 Baseline metrics fold train valid 0 0 0.816657 0.755215 1 1 0.816900 0.758754 2 2 0.808111 0.763630 3 3 0.811887 0.757583 4 4 0.811617 0.758344 5 overall 0.813034 0.758705
### feature ์ค์๋ ํ์ธ
fi_sorted = plot_feature_importances(fi)
### ์ ์ถ ํ์ผ ์์ฑ
submission.to_csv('baseline_lgb.csv', index = False)
- ์ ์๋ ์ฝ 0.735
โบ Domain Feature๋ค์ ์ถ๊ฐ
### ์ฑ๋ฅ ํ๊ฐ
app_train_domain['TARGET'] = train_labels
# Test the domain knolwedge features
submission_domain, fi_domain, metrics_domain = model(app_train_domain, app_test_domain)
print('Baseline with domain knowledge features metrics')
print(metrics_domain)
Training Data Shape: (307511, 243) Testing Data Shape: (48744, 243) [200] train's auc: 0.804779 train's binary_logloss: 0.541283 valid's auc: 0.762511 valid's binary_logloss: 0.557227 [200] train's auc: 0.804016 train's binary_logloss: 0.542318 valid's auc: 0.765768 valid's binary_logloss: 0.557819 [200] train's auc: 0.8038 train's binary_logloss: 0.542856 valid's auc: 0.7703 valid's binary_logloss: 0.557925 [400] train's auc: 0.834559 train's binary_logloss: 0.511454 valid's auc: 0.770511 valid's binary_logloss: 0.538558 [200] train's auc: 0.804603 train's binary_logloss: 0.541718 valid's auc: 0.765497 valid's binary_logloss: 0.556274 [200] train's auc: 0.804782 train's binary_logloss: 0.541397 valid's auc: 0.765076 valid's binary_logloss: 0.558641 Baseline with domain knowledge features metrics fold train valid 0 0 0.815523 0.763069 1 1 0.807075 0.766062 2 2 0.832138 0.770730 3 3 0.811100 0.765884 4 4 0.819404 0.765249 5 overall 0.817048 0.766186
### ํผ์ณ ์ค์๋
fi_sorted = plot_feature_importances(fi_domain)
-
์ฐ๋ฆฌ๊ฐ ๋ง๋ feature๋ค ์ค ์ผ๋ถ๊ฐ ์ค์ํ ๋ณ์๋ก ์ฑํ๋์์์ ํ์ธํ ์ ์์
- ์ถ๊ฐ์ ์ธ ๋ค๋ฅธ ๋๋ฉ์ธ ์ง์์ ์ ์ฉํ๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณผ ์ ์์
submission_domain.to_csv('baseline_lgb_domain_features.csv', index = False)
- ์ ์๋ ์ฝ 0.754 ์ ๋
6. Conclusions
6-1. ๋ชจ๋ธ๋ณ ์ฑ๋ฅ ๋น๊ต
- feature engineering ์ ์ฉ x
-
LogisticRegressor: 0.671
-
RandomForest: 0.678
-
LGBM: 0.735
- feature engineering ์ ์ฉ O
-
RandomForest: 0.678(๋คํฅ ๋ณ์), 0.679(๋๋ฉ์ธ feature)
- ๋ณ๋ค๋ฅธ ์ฑ๋ฅ ๊ฐ์ ์ด ์์์
-
LGBM: 0.754
- ์ฝ๊ฐ์ ์ฑ๋ฅ ๊ฐ์ ์ด ์์์
6-2. ์ ์ฒด์ ์ธ ํ๋ก์ธ์ค ์ ๋ฆฌ
-
๋จผ์ ๋ฐ์ดํฐ, ์ฌ๋ฌ๊ฐ์ง ์์ , ์ ์ถ๋ฌผ์ ํ๋จํ๋ ๊ธฐ์ค์ ํ์คํ ์ดํด
-
๋ชจ๋ธ๋ง์ ๋์์ด ๋ ์ ์๋ ๊ด๊ณ, ์ถ์ธ ๋๋ ์ด์์น๋ฅผ ์๋ณํ๊ธฐ ์ํด ๊ฐ๋จํ EDA๋ฅผ ์ํ
- ๊ทธ ๊ณผ์ ์์ ๋ฒ์ฃผํ ๋ณ์ ์ธ์ฝ๋ฉ, ๊ฒฐ์ธก๊ฐ ๋์น, ๋ฒ์ฃผํ ๋ณ์ ์ธ์ฝ๋ฉ ๊ฐ์ ํ์ํ ์ ์ฒ๋ฆฌ ๋จ๊ณ๋ฅผ ์ํ
-
๊ธฐ์กด ๋ฐ์ดํฐ์์ ์๋ก์ด feature๋ค์ ๊ตฌ์ฑํ์ฌ ๊ทธ๋ ๊ฒ ํ๋ ๊ฒ์ด ๋ชจ๋ธ์ ๋์์ด ๋ ์ ์๋์ง ํ์ธ
-
๋ฐ์ดํฐ ํ์, ๋ฐ์ดํฐ ์ค๋น ๋ฐ feature engineering์ ์๋ฃ
-
๋ชจ๋ธ ๊ตฌํ
-
LogisticRegression, RandomForest
-
Engineered๋ ๋ณ์ ํ์ต -> ์ฑ๋ฅ ์ฒดํฌ
๐ ๋จธ์ ๋ฌ๋ ํ๋ก์ ํธ์ ์ผ๋ฐ์ ์ธ ๊ฐ์
-
๋ฌธ์ ์ ๋ฐ์ดํฐ ์ดํด
-
๋ฐ์ดํฐ ์ ๋ฆฌ ๋ฐ formatting(์ ๋ณด ๊ตฌ์ฑ)
- ํด๋น ๋ํ์ ๊ฒฝ์ฐ ๋๋ถ๋ถ ์ํ๋์ด ์์์
-
EDA
-
๊ธฐ๋ณธ ๋ชจ๋ธ ์์ฑ & ํ์ต & ์์ธก
-
๋ชจ๋ธ ๊ฐ์
-
๊ฒฐ๊ณผ ํด์