[ECC DS 4์ฃผ์ฐจ] 1. A Complete Introduction Walkthrough
๐ข ์ปดํจํฐ ๋ฆฌ์์ค ๋ฌธ์ ์ ์๋ฌ ํด๊ฒฐ์ ํ์ง ๋ชปํด ์คํ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋ ์ง์ด ์ํ์ ๋๋ค. ๊ฐ ์ ์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๋ ค๋ฉด ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
0. ๋ํ ์๊ฐ
-
๐ ๋ชฉ์
- ๊ฐ์ธ๊ณผ ๊ฐ๊ตฌ ํน์ฑ์ ๋ชจ๋ ์ฌ์ฉํ์ฌ ๊ฐ๊ตฌ์ ๋น๊ณค ์์ค์ ์์ธกํ ์ ์๋ ๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ์ ๊ฐ๋ฐํ๋ ๊ฒ
-
๐ ๋ ธํธ๋ถ ๊ฐ์
-
๋ฌธ์ ์ ์
-
๋ฐ์ดํฐ ์ธํธ์ ๋ํ EDA
-
์ฌ๋ฌ ๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ ํ ์คํธ/์ ํ/์ต์ ํ
-
๋ชจ๋ธ์ ์ถ๋ ฅ ๊ฒ์ฌ, ๊ฒฐ๋ก ๋์ถ
-
0-1. ๋ฐ์ดํฐ ์ค๋ช
-
๋ฐ์ดํฐ๋ train.csv์ test.csv ๋ ํ์ผ๋ก ์ ๊ณต๋จ
-
train ์ธํธ: 9557๊ฐ์ ํ(row) * 143๊ฐ์ ์ด(column)
-
test ์ธํธ: 23856๊ฐ์ ํ(row) * 142๊ฐ์ ์ด(column)
-
-
๊ฐ ํ์
ํ ๋ช ์ ๊ฐ์ธ ๋๋ ํ ๊ฐ๊ตฌ
๋ฅผ ๋ํ๋ด๋ฉฐ, ๊ฐ ์ด์ ์ด๋ค์ ๊ณ ์ ํํน์ฑ
์ ๋ํ๋
-
Target ๊ตฌ์ฑ(ํด๋์ค ๊ตฌ์ฑ)
- 4๊ฐ์ง ๋น๊ณค ์์ค
1 = ๊ทน์ฌํ ๋น๊ณค ๊ฐ๊ตฌ 2 = ์ ๋นํ ๋น๊ณค ๊ฐ๊ตฌ 3 = ์ทจ์ฝ ๊ฐ๊ตฌ 4 = ๋น์ทจ์ฝ๊ฐ๊ตฌ
-
Columns
-
์ด 143๊ฐ์ ์ปฌ๋ผ์ผ๋ก ๊ตฌ์ฑ๋จ
-
ID
: ๊ฐ ๊ฐ์ธ์ ๊ณ ์ ์๋ณ์ -> ํ์ฉ x -
idhogar
: ๊ฐ ๊ฐ๊ตฌ์ ๊ณ ์ ์๋ณ์ -> ๊ฐ๊ตฌ๋ณ๋ก ๊ฐ์ธ์ ๊ทธ๋ฃนํํ๋ ๋ฐ ์ฌ์ฉ -
parentesco1
: ๊ฐ์ฅ์ธ์ง ์ฌ๋ถ(์ผ์ข ์ flag ๋ณ์)
-
0-2. ๋ชฉํ
-
๊ฐ๊ตฌ ์์ค์์ ๋น๊ณค ์ ๋๋ฅผ ์์ธกํ๋ ๊ฒ
- ๊ฐ์ธ ์์ค์ ๋ํ ๋ฐ์ดํฐ๊ฐ ์ ๊ณต๋๋ฉฐ, ๊ฐ ๊ฐ์ธ์ ๊ณ ์ ํ ํน์ง์ ๊ฐ์ง๊ณ ์์ ๋ฟ๋ง ์๋๋ผ ๊ฐ๊ตฌ์ ๋ํ ์ ๋ณด๋ ๊ฐ์ง๊ณ ์์
-
๋ฐ์ดํฐ ์ธํธ๋ฅผ ๊ฐ๊ณตํ๊ธฐ ์ํด ๊ฐ ๊ฐ์ ์ ๊ฐ๋ณ ๋ฐ์ดํฐ ์ง๊ณ๊ฐ ์๊ตฌ๋จ
-
test set์ ๋ชจ๋ ๊ฐ์ธ์ ๋ํ ์์ธก์ ์ํ
-
โONLY the heads of household are used in scoringโ
-
๊ฐ๊ตฌ ๋จ์๋ก ๋น๊ณค์ ์์ธก
-
โญ ์ค์
-
ํ ๊ฐ๊ตฌ์ ๋ชจ๋ ๊ตฌ์ฑ์์ด train ๋ฐ์ดํฐ์์ ๋์ผํ ๋ ์ด๋ธ์ ๊ฐ์ ธ์ผ ํจ
- ๋ง์ฝ ๋ค๋ฅธ ๊ฒฝ์ฐ
parentesco1 == 1.0
ํ์ผ๋ก ๊ตฌ๋ถํ ์ ์๋ ๊ฐ ๊ฐ๊ตฌ์ ๊ฐ์ฅ์ ๋ํ ๋ผ๋ฒจ์ ์ฌ์ฉ
- ๋ง์ฝ ๋ค๋ฅธ ๊ฒฝ์ฐ
-
๋ชจ๋ธ ํ๋ จ ์ ๊ฐ์ฅ์ ๋น๊ณค ์์ค์ด๋ผ๋ ๋ผ๋ฒจ์ ๊ฐ ๊ฐ๊ตฌ์ ๋ถ์ฌ์ ๊ฐ์ ๋จ์๋ก ํ๋ จ์ํฌ ์์
-
์๋ณธ ๋ฐ์ดํฐ์๋ ๊ฐ๊ตฌ ๋ฐ ๊ฐ์ธ์ ํน์ฑ์ด ํผํฉ๋์ด ์์ โ ๊ฐ๋ณ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ ๊ฐ ๊ฐ๊ตฌ์ ๋ํด ์ด๋ฅผ ์ง๊ณํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์์ผ ํจ
-
๊ฐ์ธ ์ค ์ผ๋ถ๋ ๊ฐ์ฅ์ด ์๋ ๊ฐ๊ตฌ์ ์ํจ โ ํ๋ จ ๋ฐ์ดํฐ๋ก ์ฌ์ฉ ๋ถ๊ฐ
-
0-3. ํ๊ฐ ์งํ(metric) - Macro F1 Score
-
๊ถ๊ทน์ ์ผ๋ก ์ฐ๋ฆฌ๋ ๊ฐ๊ตฌ์ ๋น๊ณค ์์ค(์ ์๋ก ๊ตฌ๋ถ๋จ)์ ์์ธกํ ์ ์๋ ๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ์ ๊ตฌ์ถํ๊ณ ์ ํจ
-
ํ๊ฐ ์งํ๋ก
Macro F1 Score
์ ํ์ฉํ ์์ - ์ ๋ฐ๋์ ์ฌํ์จ์ ์กฐํ ํ๊ท
-
ํ์ค F1 ์ ์
-
๋ค์ค ๋ถ๋ฅ ๋ฌธ์ ์ ๊ฒฝ์ฐ ๊ฐ ํด๋์ค ๋ณ F1 score์ ํ๊ท ๋ด์ด ํ์ฉ
-
Macro F1 score
-
label์ ๋ถ๊ท ํ์ ๊ณ ๋ คํ์ง ์๊ณ ๊ฐ ํด๋์ค์ F1 ์ ์๋ฅผ ํ๊ท
- ๊ฐ ๋ ์ด๋ธ์ ๋ฐ์ ๋น๋๋ ๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํ ๋ ๊ณ์ฐ์ ๋ฐ์๋์ง ์์(์ฌ์ฉํ๋ ค๋ฉด
weighted
์ต์ ์ ํ์ฉ)
- ๊ฐ ๋ ์ด๋ธ์ ๋ฐ์ ๋น๋๋ ๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํ ๋ ๊ณ์ฐ์ ๋ฐ์๋์ง ์์(์ฌ์ฉํ๋ ค๋ฉด
-
์ฝ๋
from sklearn.metrics import f1_score f1_score(y_true, y_predicted, average = 'macro')
-
0-4. ๋ก๋๋งต(์ ๋ฐ์ ์ธ ์งํ process)
-
๋ฌธ์ ์ดํด
-
ํ์์ ๋ฐ์ดํฐ ๋ถ์(EDA)
-
ํน์ฑ ๊ณตํ(Feature Engineering)
-
Baseline ML ํ์ต ๋ชจ๋ธ ๋น๊ต
-
์ข ๋ ๋ณต์กํ ๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ ์๋
-
์ ํํ ๋ชจ๋ธ ์ต์ ํ
-
์์ธก ์ํ / ํ์ธ
-
๊ฒฐ๋ก ๋์ถ, ๋ค์ ๋จ๊ณ ์ ์
1. ์ค๋น(Getting Started)
1-1. ๋ผ์ด๋ธ๋ฌ๋ฆฌ import
### ๋ฐ์ดํฐ ๋ณํ(๊ฐ๊ณต)
import pandas as pd
import numpy as np
### ์๊ฐํ
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('fivethirtyeight')
plt.rcParams['font.size'] = 18
plt.rcParams['patch.edgecolor'] = 'k'
1-2. ๋ฐ์ดํฐ ์ค๋นํ๊ธฐ
from google.colab import drive
drive.mount('/content/drive')
pd.options.display.max_columns = 150 # ์ต๋ 150 ์ปฌ๋ผ๋ง ํ์
train = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/ECC 48แแ
ต แแ
ฆแแ
ชB/4แแ
ฎแแ
ก/Costa Rica/data/train.csv')
test = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/ECC 48แแ
ต แแ
ฆแแ
ชB/4แแ
ฎแแ
ก/Costa Rica/data/test.csv')
train.head()
- ์ปฌ๋ผ๋ค ๊ฐ์ ์์๋ ์กด์ฌํ์ง ์๋ ๊ฒ์ผ๋ก ํ๋จ๋๋ค.
2. EDA(Exploratory Data Analysis) & ์ ์ฒ๋ฆฌ
2-1. ๋ฐ์ดํฐ ์ ๋ณด ํ์ธ
### ํ์ต์ฉ ๋ฐ์ดํฐ
train.info()
-
130๊ฐ์ integerํ ์ปฌ๋ผ, 8๊ฐ์ floatํ ์ปฌ๋ผ ๋ฐ 5๊ฐ์ object ์ปฌ๋ผ์ด ์กด์ฌ
-
integer ์ปฌ๋ผ์ ๊ฒฝ์ฐ 0 ๋๋ 1์ ์ฌ์ฉํ๋ bool ๋ณ์ ๋๋ ์์ํ(ordinal) ๋ณ์๋ฅผ ๋ํ๋ผ ์ ์์
-
object ์ปฌ๋ผ์ ๊ฒฝ์ฐ ๊ธฐ๊ณ ํ์ต ๋ชจ๋ธ์ ์ง์ ๊ณต๊ธ๋ ์ ์์ -> ์ ์ฒ๋ฆฌ ํ์
### ํ
์คํธ์ฉ ๋ฐ์ดํฐ
test.info()
a) ์ ์ํ(Integer) Columns
- ๊ฐ ์ด์ ๋ํด ๊ณ ์ ํ ๊ฐ์ ์๋ฅผ ์ธ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ ๊ทธ๋ํ๋ก ํ์
train.select_dtypes(np.int64).nunique().value_counts().sort_index().plot.bar(color = 'blue',
figsize = (8, 6),
edgecolor = 'k',
linewidth = 2)
plt.xlabel('Number of Unique Values')
plt.ylabel('Count')
plt.title('Count of Unique Values in Integer Columns')
-
๊ณ ์ ํ ๊ฐ์ด 2๊ฐ๋ง ์๋ ์ปฌ๋ผ์ boolean(0 ๋๋ 1)์ ๋ํ๋
-
๋๋ถ๋ถ์ boolean ์ ๋ณด๋ค์ ๋๋ถ๋ถ ๊ฐ๊ตฌ ๋จ์๋ก ์ง๊ณ๋์ด ์์
-
ex>
refrig
์ปฌ๋ผ- ๊ฐ์ ์ ๋์ฅ๊ณ ๊ฐ ์๋์ง ์๋์ง 0๊ณผ 1๋ก ํ์
-
-
๊ฐ์ธ ์์ค์ผ๋ก ์กด์ฌํ๋ ์ปฌ๋ผ๋ค์ ์ง๊ฒจ ํ์
b) Float Columns
-
floatํ ๋ณ์๋ค์ ๊ฒฝ์ฐ ์ฃผ๋ก ์ฐ์ํ ๋ณ์๋ฅผ ๋ํ๋
-
๋ถํฌ๋ plot(dist plot)์ ํตํด float ๋ณ์๋ค์ ๋ถํฌ๋ฅผ ํ์ธํ ์ ์์
- โOrderedDictโ ๋ฅผ ์ฌ์ฉํ์ฌ ๋น๊ณค ์์ค์ ์์์ ๋งคํ
-
์๋ ๊ทธ๋ํ๋
target
๊ฐ์ผ๋ก ํ์๋float
์ด์ ๋ถํฌ๋ฅผ ๋ณด์ฌ์ค๊ฐ๊ตฌ์ ๋น๊ณค ์์ค์ ๋ฐ๋ผ ๋ณ์๋ค์ ๋ถํฌ์ ์ ์ํ ์ฐจ์ด๊ฐ ์๋์ง ํ์ธํ ์ ์์
from collections import OrderedDict # ์์๋ฅผ ๊ฐ์ง๋ ๋์
๋๋ฆฌ
### ์๊ฐํ format ์ค์
plt.figure(figsize = (20, 16))
plt.style.use('fivethirtyeight')
### Color ์ค์
colors = OrderedDict({1: 'red', 2: 'orange', 3: 'blue', 4: 'green'})
poverty_mapping = OrderedDict({1: 'extreme', 2: 'moderate',
3: 'vulnerable', 4: 'non vulnerable'})
### floatํ ๋ณ์๋ค ๊ฐ๊ฐ์ ๋ํด...
for i, col in enumerate(train.select_dtypes('float')):
ax = plt.subplot(4, 2, i + 1) # plotting ์์น ์ค์
# ๊ฐ ๊ฐ๊ตฌ๋ณ ๋น๊ณค ์์ค๋ณ๋ก
for poverty_level, color in colors.items():
# ๊ฐ๊ฐ ๋ค๋ฅธ ์์์ ์ ์ผ๋ก ์๊ฐํ
sns.kdeplot(train.loc[train['Target'] == poverty_level, col].dropna(),
ax = ax, color = color, label = poverty_mapping[poverty_level])
plt.title(f'{col.capitalize()} Distribution')
plt.xlabel(f'{col}')
plt.ylabel('Density')
plt.subplots_adjust(top = 2)
-
์๊ฐํ๋ฅผ ํตํด ์ด๋ค ๋ณ์๊ฐ ๋ชจํ๊ณผ ๊ฐ์ฅ ๊ด๋ จ์ด ์์์ง๋ฅผ ๋๋ต์ ์ผ๋ก ํ์ ํ ์ ์์
-
ex>
-
meaneduc
(๊ฐ๊ตฌ ๋ด ์ฑ์ธ์ ํ๊ท ๊ต์ก์ ๋ํ๋)์ ๋น๊ณค ์์ค๊ณผ ๊ด๋ จ์ด ์๋ ๊ฒ์ผ๋ก ๋ณด์ -
meaneduc
์ด ๋์์๋ก ๋น๊ณค ์์ค์ด ๋ฎ์ ๊ฐ๊ตฌ๊ฐ ์ ์
-
-
c) Object Columns
train.select_dtypes('object').head()
-
id
,idhogar
: ๋ณ์ ์๋ณ์ ํ์ฉ -
dependency
: ์ข ์๋ฅ , (19์ธ ๋ฏธ๋ง ๋๋ 64์ธ ์ด์ ๊ฐ๊ตฌ์ ์)/(19์ธ ์ด์ 64์ธ ๋ฏธ๋ง ๊ฐ๊ตฌ์ ์) -
edjeefe
: ๋จ์ฑ ๊ฐ์ฅ์ ์๋ ๊ฐ ๊ต์ก, ์์ค์ฝ๋ผ๋ฆฌ(๊ต์ก์ฐ์), ๊ฐ์ฅ๊ณผ ์ฑ๋ณ์ ๊ธฐ๋ฐ์ผ๋ก yes = 1, no = 0๋ก ํ์ -
edjefa
: ์ฌ์ฑ ๊ฐ์ฅ์ ์๋ ๊ฐ ๊ต์ก, ์์ค์ฝ๋ผ๋ฆฌ(๊ต์ก์ฐ์), ๊ฐ์ฅ๊ณผ ์ฑ๋ณ์ ๊ธฐ๋ฐ์ผ๋ก yes = 1 ๋ฐ no = 0 -
์ธ ๋ณ์์ ๋ํด yes = 1, no = 0์ ๊ฒฝ์ฐ ๋งคํ์ ํ์ฉํ์ฌ ๋ณ์๋ฅผ ์์ ํ๊ณ ๋ถ๋ ์์์ ์ผ๋ก ๋ณํ
mapping = {"yes": 1, "no": 0}
### train, test์ ๋ํด ๋ชจ๋ ๊ฐ์ ์์
์ํ
for df in [train, test]:
# mapping์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ ํ๊ฒ ๋ณํ
df['dependency'] = df['dependency'].replace(mapping).astype(np.float64)
df['edjefa'] = df['edjefa'].replace(mapping).astype(np.float64)
df['edjefe'] = df['edjefe'].replace(mapping).astype(np.float64)
train[['dependency', 'edjefa', 'edjefe']].describe()
- ์ ๋๋ก ๋ณํ๋์์์ ํ์ธํ ์ ์๋ค.
### ์๊ฐํ
plt.figure(figsize = (16, 12))
### ๊ฐ ๋ณ์๋ค ๋ณ๋ก..
for i, col in enumerate(['dependency', 'edjefa', 'edjefe']):
ax = plt.subplot(3, 1, i + 1)
# ๊ฐ ๊ฐ๊ตฌ๋ณ ๋น๊ณค ์์ค๋ณ๋ก
for poverty_level, color in colors.items():
# ๋น๊ณค ์์ค๋ณ๋ก ๊ฐ๊ฐ ๋ค๋ฅธ ์์ผ๋ก ํ์
sns.kdeplot(train.loc[train['Target'] == poverty_level, col].dropna(),
ax = ax, color = color, label = poverty_mapping[poverty_level])
plt.title(f'{col.capitalize()} Distribution')
plt.xlabel(f'{col}')
plt.ylabel('Density')
plt.subplots_adjust(top = 2)
-
ํด๋น ๋ณ์๋ค์ด ์ซ์๋ก ์ฌ๋ฐ๋ฅด๊ฒ ํํ๋จ
- ML ํ์ต ๋ชจ๋ธ์ ์ ๋ ฅ๋ ์ ์์
### test ๋ฐ์ดํฐ์ target ๊ฐ์ ์ผ๋จ null๋ก ์ด๊ธฐํ
test['Target'] = np.nan
data = train.append(test, ignore_index = True)
2-2. ๋ผ๋ฒจ(target) ๋ถํฌ ํ์ธ
-
๊ต์ฅํ ๋ถ๊ท ํํ(imbalanced) ๋ถํฌ๋ฅผ ๊ฐ์ง์ ํ์ธํ ์ ์์
-
์ ์(1~4)๋ก ๊ฐ ํด๋์ค๊ฐ ๊ตฌ๋ถ๋์ด ์์
-
๋ผ๋ฒจ์ ์ ํํ๊ฒ ํ์ธํ๊ธฐ ์ํด
parentesco1 == 1
๋ก ํ์๋(๊ฐ ๊ฐ์ ์ ๊ฐ์ฅ์ ํ์) ์ด๋ง ๊ณ ๋ ค
# ๊ฐ์ฅ
heads = data.loc[data['parentesco1'] == 1].copy()
# ํ์ต์ ์ํ ๋ผ๋ฒจ(target)
train_labels = data.loc[(data['Target'].notnull()) & (data['parentesco1'] == 1), ['Target', 'idhogar']]
# target ์ง๊ณ(๋ถํฌ ํ์ธ)
label_counts = train_labels['Target'].value_counts().sort_index()
# ๊ฐ label์ ๋ถํฌ์ ๋ํ ๋ง๋ ๊ทธ๋ํ
label_counts.plot.bar(figsize = (8, 6),
color = colors.values(),
edgecolor = 'k', linewidth = 2)
# ์ถ, ์ ๋ชฉ ์ค์
plt.xlabel('Poverty Level'); plt.ylabel('Count');
plt.xticks([x - 1 for x in poverty_mapping.keys()],
list(poverty_mapping.values()), rotation = 60)
plt.title('Poverty Level Breakdown');
label_counts
-
target์ ๋ถํฌ๊ฐ ๋งค์ฐ ๋ถ๊ท ํํจ
-
non_vernerable
์ผ๋ก ๋ถ๋ฅ๋๋ ๊ฐ๊ตฌ์ ์๊ฐ ๋ค๋ฅธ ํด๋์ค์ ๋นํด ํ์ ํ ๋ง์ -
extreme
์ ๋งค์ฐ ์ ์
-
-
๋ถ๊ท ํ ํด๋์ค ๋ถ๋ฅ ๋ฌธ์ ์ ๊ฒฝ์ฐ ML ๋ชจ๋ธ์ด ํจ์ฌ ์ ์ ์์ ๋ฅผ ๋ณด๊ธฐ ๋๋ฌธ์ ์์ ํด๋์ค๋ฅผ ์์ธกํ๋ ๋ฐ ์ด๋ ค์์ ๊ฒช์ ์ ์์
-
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Oversampling์ ์ ์ฉํ ์ ์์
2-3. ์๋ชป๋ label ์ฒ๋ฆฌ
-
์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ดํฐ ๊ณผํ ํ๋ก์ ํธ์์ 80%์ ์๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฆฌํ๊ณ ์ด์ ์งํ/์ค๋ฅ๋ฅผ ์์ ํ๋ ๋ฐ ํ ์
-
์ฌ๋์ ์ ๋ ฅ ์ค๋ฅ, ์ธก์ ์ค๋ฅ ๋๋ ์ ํํ์ง๋ง ๋์ ๋๋ ๊ทน๋จ๊ฐ ๋ฑ
-
๊ฐ์ ๊ฐ๊ตฌ์์๋ ๊ฐ์ธ์ ๋น๊ณค ์์ค์ด ๋ค๋ฅธ, ์๋ชป๋ ๋ผ๋ฒจ๋ค์ด ์กด์ฌํจ
- ๊ฐ์ฅ์ ๋ผ๋ฒจ์ ์ง์ ํ(true) ๋ผ๋ฒจ๋ก ํ์ฉ
-
์๋ชป๋ label์ ์ฐพ์๋ด๊ธฐ ์ํด ๊ฐ๊ตฌ๋ณ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฅํ ๋ค์,
target
์ ๊ณ ์ ๊ฐ์ด ํ๋๋ง ์๋์ง ํ์ธ
# ๊ฐ๊ตฌ๋ณ๋ก ๊ทธ๋ฃนํํ๊ณ ๊ณ ์ ๊ฐ์ ์ ํ์
all_equal = train.groupby('idhogar')['Target'].apply(lambda x: x.nunique() == 1)
# target ๊ฐ์ด ๋ชจ๋ ๊ฐ์ง ์์ ๊ฐ๊ตฌ
not_equal = all_equal[all_equal != True]
print('๊ฐ์กฑ ๊ตฌ์ฑ์์ด ๋ชจ๋ ๋์ผํ ๋์์ด ์๋ ๊ฐ๊ตฌ๋ {}๊ฐ๊ตฌ์
๋๋ค.'.format(len(not_equal)))
- ์์๋ฅผ ํ์ธํด๋ณด์.
train[train['idhogar'] == not_equal.index[0]][['idhogar', 'parentesco1', 'Target']]
-
parentesco1 == 1
๋ก ํ์ธ ๊ฒฐ๊ณผ, ํด๋น ๊ฐ๊ตฌ์ ๊ฒฝ์ฐ ๋ชจ๋ ๊ตฌ์ฑ์์ ๋ํ ์ฌ๋ฐ๋ฅธ ๋ ์ด๋ธ์ 3(vulnerable)์ด๋ค. -
ํด๋น ๊ฐ๊ตฌ์ ๋ชจ๋ ๊ตฌ์ฑ์์์ ์ฌ๋ฐ๋ฅธ ๋น๊ณค ์์ค(target, label)์ ์ฌํ ๋น
cf> ๊ฐ์ฅ์ด ์๋ ๊ฒฝ์ฐ
households_leader = train.groupby('idhogar')['parentesco1'].sum()
# ๊ฐ์ฅ์ด ์๋ ๊ฐ๊ตฌ
households_no_head = train.loc[train['idhogar'].isin(households_leader[households_leader == 0].index), :]
print('There are {} households without a head.'.format(households_no_head['idhogar'].nunique()))
# ๊ฐ์ฅ์ด ์๋ ๊ฐ๊ตฌ๋ค ์ค ๊ตฌ์ฑ์๋ค ๊ฐ์ ๋ ์ด๋ธ์ด ๋ค๋ฅธ ๊ฐ๊ตฌ ์ฐพ๊ธฐ
households_no_head_equal = households_no_head.groupby('idhogar')['Target'].apply(lambda x: x.nunique() == 1)
print('{} Households with no head have different labels.'.format(sum(households_no_head_equal == False)))
- ๋คํํ ์ด๋ฌํ ๋ฐ์ดํฐ๋ ์กด์ฌํ์ง ์๋๋ค.
์๋ชป๋ label ์ฒ๋ฆฌ
### ๋ผ๋ฒจ๊ฐ์ด ๊ฐ์ง ์์ ๊ฐ ๊ฐ๊ตฌ๋ณ๋ก..
for household in not_equal.index:
# ๊ฐ์ฅ์ ํตํด ์ ๋๋ก ๋ label๊ฐ ์ฐพ๊ธฐ
true_target = int(train[(train['idhogar'] == household) & (train['parentesco1'] == 1.0)]['Target'])
# ์ ๋๋ก ๋ ๊ฐ์ผ๋ก ์ฌํ ๋น
train.loc[train['idhogar'] == household, 'Target'] = true_target
# ๊ฐ๊ตฌ๋ณ๋ก ๊ทธ๋ฃนํํ๊ณ ๊ณ ์ ๊ฐ์ ์ ํ์
all_equal = train.groupby('idhogar')['Target'].apply(lambda x: x.nunique() == 1)
# target ๊ฐ์ด ํต์ผ๋์ง ์์ ๊ฐ๊ตฌ
not_equal = all_equal[all_equal != True]
print('There are {} households where the family members do not all have the same target.'.format(len(not_equal)))
- ์ ๋๋ก ์ฒ๋ฆฌ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
2-4. ๊ฒฐ์ธก์น(Missing Value) ์ฒ๋ฆฌ
- ๋๋ฝ๋ ๊ฐ์ ML ๋ชจ๋ธ์ ์ฌ์ฉํ๊ธฐ ์ ์ ์ ๋ ฅํด์ผ ํ๋ฉฐ, ๋ณ์์ ๋ฐ๋ผ ์ ๋ ฅํ๋ ์ต์ ์ ์ ๋ต์ ์๊ฐํด์ผ ํฉ
# ์ปฌ๋ผ(๋ณ์)๋ณ๋ก ๊ฒฐ์ธก์น ๊ฐ์ ํ์ธ
missing = pd.DataFrame(data.isnull().sum()).rename(columns = {0: 'total'})
# ๊ฒฐ์ธก์น์ ๋น์จ ํ์ธ
missing['percent'] = missing['total'] / len(data)
missing.sort_values('percent', ascending = False).head(10).drop('Target')
-
๊ฒฐ์ธก๊ฐ์ ๋น์จ์ด ๋์ ์ธ ๊ฐ์ ์ปฌ๋ผ์ ์ฒ๋ฆฌํ์.
-
v18q1
: ๊ฐ์กฑ๋ณ๋ก ์์ ํ ํ๋ธ๋ฆฟ ์-
๊ฐ๊ตฌ ์ฐจ์์ผ๋ก ๋ณด๋ ๊ฒ์ด ํ๋นํจ
-
๊ฐ์ฅ์ ๋ํด์๋ง ํ์ ์ ํ
-
-
v2a1
: ์์ธ -
rez_esc
: ๋ค๋จ์ด์ง ํ๋ ์ ์ฐ ์
๐ Value Counts ์๊ฐํ ํจ์
-
ํ ์ด์ ์นด์ดํธ ๊ฐ์ ์๊ฐํ
-
์ ํ์ ์ผ๋ก ๊ฐ์ฅ๋ง ํ์
def plot_value_counts(df, col, heads_only = False):
# ๊ฐ์ฅ๋ง ์ ํ
if heads_only:
df = df.loc[df['parentesco1'] == 1].copy()
plt.figure(figsize = (8, 6))
df[col].value_counts().sort_index().plot.bar(color = 'blue',
edgecolor = 'k',
linewidth = 2)
plt.xlabel(f'{col}')
plt.ylabel('Count')
plt.title(f'{col} Value Counts')
plt.show()
a) v18q1
plot_value_counts(heads, 'v18q1')
-
์ผ๋จ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ผ๋ก ์์ ํ ์ ์๋ ํ๋ธ๋ฆฟ์ ์๋ 1์ธ ๊ฒ ๊ฐ์
-
ํ์ง๋ง, ๊ฒฐ์ธก ๋ฐ์ดํฐ์ ๋ํด์๋ ์๊ฐํ ํ์๊ฐ ์์
-
ํด๋น ๋ฒ์ฃผ๊ฐ
NaN
์ธ ๊ฐ๊ตฌ๋ ํ๋ธ๋ฆฟ์ ์์ ํ์ง ์์ ์๋ ์์
-
-
v18q
๊ฐ์ ๊ธฐ์ค์ผ๋ก ๊ทธ๋ฃนํ ํ ๋ค์v18q1
์ ๋ํ null ๊ฐ์ ์๋ฅผ ๊ณ์ฐ- null ๊ฐ์ด ๊ฐ์กฑ์ด ํ๋ธ๋ฆฟ์ ์์ ํ์ง ์์์ ๋ํ๋ด๋ ๊ฒ์ธ์ง๋ฅผ ํ์ธ ๊ฐ๋ฅ
heads.groupby('v18q')['v18q1'].apply(lambda x: x.isnull().sum())
-
v18q1
์์ ๊ฒฐ์ธก์น๋ฅผ ๊ฐ์ง๋ ๊ฐ๊ตฌ์ ๊ฒฝ์ฐ ํ๋ธ๋ฆฟ์ ์์ ํ์ง ์์ ๊ฐ๊ตฌ๋ผ๋ ์ ์ ํ์ธํ ์ ์์- ํด๋น ๊ฐ์ ๊ฒฐ์ธก์น๋ฅผ 0์ผ๋ก ์ฑ์ธ ์ ์์
### ๊ฒฐ์ธก์น ์ฒ๋ฆฌ
data['v18q1'] = data['v18q1'].fillna(0)
b) v2a1
-
์์ธ ๋ฉ๋ถ์ ๋๋ฝ๋ ๊ฐ์ ์ดํด๋ณด๋ ๊ฒ ์ธ์๋ ์ฃผํ์ ์์ /์๋ ์ํ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ด์ ์๋
tipovivi
์ ๋ถํฌ๋ฅผ ์ดํด๋ณด๋ ๊ฒ๋ ํฅ๋ฏธ๋ก์ธ ๊ฒ์- ์์ธ ์ง๋ถ์ ๋ํด ๊ฒฐ์ธก์น๊ฐ ์๋ ์ฃผํ๋ค์ ์์ ํํฉ์ ํ์ ํ์.
# ์ฃผํ ์์ ๋ฅผ ๋ํ๋ด๋ ๋ณ์
own_variables = [x for x in data if x.startswith('tipo')]
# ์ฃผํ ์๋๋ฃ ์ง๊ธ(๊ฒฐ์ธก์น O) vs ์ฃผํ ์์ (Plottinh)
data.loc[data['v2a1'].isnull(), own_variables].sum().plot.bar(figsize = (10, 8),
color = 'green',
edgecolor = 'k',
linewidth = 2)
plt.xticks([0, 1, 2, 3, 4],
['Owns and Paid Off', 'Owns and Paying', 'Rented', 'Precarious', 'Other'],
rotation = 60)
plt.title('Home Ownership Status for Households Missing Rent Payments', size = 18);
- ์ฃผํ ์์ ๋ณ์ ์ค๋ช :
tipovivi1 = 1: ์ ์ก์ ์ง๋ถํ ๋ณธ์ธ ์์ ์ ์ง
tipovivi2 = 1: ์์ , ํ ๋ถ๋ก ์ง๋ถ
tipovivi3 = 1: ์๋ ์ฃผํ
tipovivi4 = 1: ๋ถํ์ค
tipovivi5 = 1: ๊ธฐํ(๋์ฌ)
-
๋๋ถ๋ถ ์์ธ๋ฅผ ๋ด์ง ์๋ ๊ฐ๊ตฌ๋ค์ ์ผ๋ฐ์ ์ผ๋ก ์์ ์ ์ง์ ์์ ํ๊ณ ์์
-
์ผ๋ถ ์ํฉ์์๋ ๊ฒฐ์ธก์น๊ฐ ๋ฐ์ํ ์ด์ ๋ฅผ ์ ์ ์์
-
์์ ํ๊ณ ์๊ณ ์์ธ๊ฐ ๋๋ฝ๋ ์ฃผํ์ ๊ฒฝ์ฐ ์๋๋ฃ ์ง๊ธ์ก์ 0์ผ๋ก ์ค์ ํ ์ ์์
-
๋ค๋ฅธ ์ฃผํ์ ๊ฒฝ์ฐ ๊ฒฐ์ธก๊ฐ์ ๋ ๋ ์ ์์ง๋ง ํด๋น ๊ฐ๊ตฌ์ ๊ฒฐ์ธก๊ฐ์ด ์์์ ๋ํ๋ด๋ ํ๋๊ทธ(๋ถ์ธ) ์ด์ ์ถ๊ฐ
# ์ง์ ์์ ํ ๊ฐ๊ตฌ์ ๊ฒฝ์ฐ ์์ธ ๋ฉ๋ถ์ก ๊ฒฐ์ธก์น๋ฅผ 0์ผ๋ก ํ๊ธฐ
data.loc[(data['tipovivi1'] == 1), 'v2a1'] = 0
# ๋๋ฝ๋ ์๋๋ฃ ์ง๊ธ์ ํ๊ธฐํ๋ ์ปฌ๋ผ ์์ฑ
data['v2a1-missing'] = data['v2a1'].isnull()
data['v2a1-missing'].value_counts()
c) rez_esc
-
๊ฒฐ์ธก์น์ ๊ฒฝ์ฐ ๊ฐ๊ตฌ์์ ํ์ฌ ํ๊ต์ ๋ค๋๋ ์๋ ๊ฐ ์์ ์ ์์
- ํด๋น ์ด์ ๊ฒฐ์ธก๊ฐ์ด ์๋ ์ฌ๋์ ๋์ด์ ๊ฒฐ์ธก๊ฐ์ด ์๋ ์ฌ๋์ ๋์ด๋ฅผ ์ฐพ์ ์ด๋ฅผ ํ์ธํ์.
### ๊ฒฐ์ธก์น๊ฐ ์๋ ์ฌ๋๋ค์ ๋์ด
data.loc[data['rez_esc'].notnull()]['age'].describe()
-
๊ฒฐ์ธก์น๊ฐ ๊ฐ์ฅ ๋ง์ ๋์ด๋ 17์ธ์
- ์ด๊ฒ๋ณด๋ค ๋์ด๊ฐ ๋ง์ ์ฌ๋์ด๋ผ๋ฉด, ์ฐ๋ฆฌ๋ ๋จ์ํ ์ด ์ฌ๋๋ค์ด ํ๊ต์ ๋ค๋์ง ์๋๋ค๊ณ ๊ฐ์ ํ ์๋ ์์
### ๋ฐ์ดํฐ๊ฐ ๊ฒฐ์ธก์ธ ์ฌ๋๋ค์ ๋์ด
data.loc[data['rez_esc'].isnull()]['age'].describe()
-
๋ํ ์ ๋ณด์ ์ํ๋ฉด ํด๋น ๋ณ์๋ 7์ธ์์ 19์ธ ์ฌ์ด์ ๊ฐ์ธ์๊ฒ๋ง ์ ์๋จ
-
ํด๋น ๋ฒ์๋ณด๋ค ๋์ด๊ฐ ์ด๋ฆฐ ์ฌ๋์ด๋ ๋์ด๊ฐ ๋ง์ ์ฌ๋์ ๊ฐ์ 0์ผ๋ก ์ค์ ํ๋ฉด ๋จ
-
๋ค๋ฅธ ์ฌ๋์ ๊ฒฝ์ฐ ๊ฒฐ์ธก์น๋ฅผ ์ฒ๋ฆฌํ๊ณ , bool flag๋ฅผ ์ถ๊ฐ
-
# 19์ธ ์ด์์ด๊ฑฐ๋ 7์ธ ๋ฏธ๋ง์ธ ์ฌ๋ -> 0์ผ๋ก ๊ฒฐ์ธก์น ์ฒ๋ฆฌ
data.loc[((data['age'] > 19) | (data['age'] < 7)) & (data['rez_esc'].isnull()), 'rez_esc'] = 0
# 7์ธ์์ 19์ธ ์ฌ์ด์ธ ์ฌ๋ ์ค ๊ฒฐ์ธก์น์ธ ๊ฒฝ์ฐ flag ๋ณ์๋ก ํ์
data['rez_esc-missing'] = data['rez_esc'].isnull()
-
rez_esc
์ ์ด์์น๊ฐ ํ๋ ์กด์ฌํจ-
๋ํ ์ค๋ช ์ ์ํ๋ฉด, ํด๋น ๋ณ์์ ์ต๋๊ฐ์ 5
-
5๋ณด๋ค ํฐ ๊ฐ๋ค์ 5๋ก ์ฌํ ๋น
-
### ์ด์์น ์ฒ๋ฆฌ
data.loc[data['rez_esc'] > 5, 'rez_esc'] = 5
2-5. ๋ฒ์ฃผํ ๋ณ์ ์๊ฐํ
-
๋ ๋ฒ์ฃผํ ๋ณ์๊ฐ ์๋ก ์ํธ์์ฉํ๋ ๋ฐฉ์์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์ฐ์ ๋,๋์ ๋ง๋๊ทธ๋ฆผ, ์์๊ทธ๋ฆผ ๋ฑ ์ฌ๋ฌ ๊ฐ์ง ํ์ ์ต์ ์ด ์์
-
๊ฐ๊ฐ์ x ๊ฐ์ ๋ํ y๊ฐ์ ๋ฐฑ๋ถ์จ์ ์ ์ ํฌ๊ธฐ๋ก ํํํ๋ ์ฐ์ ๋ ๊ทธ๋ฆผ์ผ๋ก ์๊ฐํ ์งํ
### ์ฐ์ ๋ ์๊ฐํ๋ฅผ ์ํ ํจ์ ์ ์
def plot_categoricals(x, y, data, annotate = True):
"""
- ๋ ๋ฒ์ฃผํ์ ์นด์ดํธ๋ฅผ ํ์ํฉ๋๋ค.
- size: ๊ฐ ๊ทธ๋ฃน์ ์นด์ดํธ ์
- percentage: y์ ์ฃผ์ด์ง ๊ฐ์ ๋ํ ๊ฒ
"""
# Raw counts
raw_counts = pd.DataFrame(data.groupby(y)[x].value_counts(normalize = False))
raw_counts = raw_counts.rename(columns = {x: 'raw_count'})
# x ๋ฐ y์ ๊ฐ ๊ทธ๋ฃน์ ๋ํ ์นด์ดํธ ๊ณ์ฐ
counts = pd.DataFrame(data.groupby(y)[x].value_counts(normalize = True)) # ์ ๊ทํ ์ํ
# ์ด ์ด๋ฆ ๋ณ๊ฒฝ ๋ฐ ์ธ๋ฑ์ค ์ฌ์ค์
counts = counts.rename(columns = {x: 'normalized_count'}).reset_index()
counts['percent'] = 100 * counts['normalized_count']
# Add the raw count
counts['raw_count'] = list(raw_counts['raw_count'])
# ๋ฐฑ๋ถ์จ๋ก ํฌ๊ธฐ๊ฐ ์กฐ์ ๋ ์ฐ์ ๋
plt.figure(figsize = (14, 10))
plt.scatter(counts[x], counts[y], edgecolor = 'k', color = 'lightgreen',
s = 100 * np.sqrt(counts['raw_count']), marker = 'o',
alpha = 0.6, linewidth = 1.5)
if annotate:
# ํ
์คํธ๋ก ํ๋กฏ์ ์ฃผ์ ๋ฌ๊ธฐ
for i, row in counts.iterrows():
plt.annotate(xy = (row[x] - (1 / counts[x].nunique()),
row[y] - (0.15 / counts[y].nunique())),
color = 'navy',
text = f"{round(row['percent'], 1)}%")
# ์ถ ์ค์
plt.yticks(counts[y].unique())
plt.xticks(counts[x].unique())
# ์ ๊ณฑ๊ทผ ์์ญ์์ ์ต์ ๋ฐ ์ต๋๋ฅผ ๊ท ๋ฑํ ๊ณต๊ฐ์ผ๋ก ๋ณํ
sqr_min = int(np.sqrt(raw_counts['raw_count'].min()))
sqr_max = int(np.sqrt(raw_counts['raw_count'].max()))
# 5 sizes for legend
msizes = list(range(sqr_min, sqr_max,
int(( sqr_max - sqr_min) / 5)))
markers = []
# Markers for legend
for size in msizes:
markers.append(plt.scatter([], [], s = 100 * size,
label = f'{int(round(np.square(size) / 100) * 100)}',
color = 'lightgreen',
alpha = 0.6, edgecolor = 'k', linewidth = 1.5))
# Legend and formatting
plt.legend(handles = markers, title = 'Counts',
labelspacing = 3, handletextpad = 2,
fontsize = 16,
loc = (1.10, 0.19))
plt.annotate(f'* Size represents raw count while % is for a given y value.',
xy = (0, 1), xycoords = 'figure points', size = 10)
# Adjust axes limits
plt.xlim((counts[x].min() - (6 / counts[x].nunique()),
counts[x].max() + (6 / counts[x].nunique())))
plt.ylim((counts[y].min() - (4 / counts[y].nunique()),
counts[y].max() + (4 / counts[y].nunique())))
plt.grid(None)
plt.xlabel(f"{x}"); plt.ylabel(f"{y}"); plt.title(f"{y} vs {x}");
plot_categoricals('rez_esc', 'Target', data)
-
๋ง์ปค์ ํฌ๊ธฐ: raw count
-
ํด์
= ์ง์ ๋ y ๊ฐ์ ์ ํํ ๋ค์ ํ ์ ์ฒด๋ฅผ ์ฝ๊ธฐ
- ์์: ๋น๊ณค ์์ค์ด 1์ธ ๊ฒฝ์ฐ, 93%์ ๊ฐ์ธ์ด 1๋ ์ด์ ๋ค์ฒ์ง์ง ์๊ณ ์ด 800๋ช ์ ๋์ ๊ฐ์ธ์ด ์์ผ๋ฉฐ, ์ฝ 0.4%์ ๊ฐ์ธ์ด 5๋ ๋ค์ณ์ ธ ์์ผ๋ฉฐ, ์ด ๋ฒ์ฃผ์ ์ํ๋ ์ด 50๋ช ์ ๋์ ๊ฐ์ธ์ด ์์
-
ํด๋น ๊ทธ๋ฆผ์ ์ ์ฒด ์นด์ดํธ์ ๋ฒ์ฃผ ๋ด ๋น์จ์ ๋ชจ๋ ํ์
plot_categoricals('escolari', 'Target', data, annotate = False)
-
๊ฒฐ์ธก์น ์ค ๋จ์ ๊ฐ์ ์ค๊ฐ๊ฐ์ผ๋ก ์ฑ์ฐ์.
-
target ๊ฐ ๋ถํฌ๋ฅผ ์๊ฐํํ์ฌ ๊ฒฐ์ธก๊ฐ์ ํ์ธํ ์ ์์
plot_value_counts(data[(data['rez_esc-missing'] == 1)], 'Target')
- ํด๋น ๋ถํฌ๋ ์ ์ฒด ๋ฐ์ดํฐ์ ๋ํ ๋ถํฌ์ ์ผ์นํ๋ ๊ฒ์ผ๋ก ๋ณด์
plot_value_counts(data[(data['v2a1-missing'] == 1)], 'Target')
-
target = 2(moderate)์ ๋น์จ์ด ๋์
- ๋ ๋ง์ ๋น๊ณค์ ์งํ๊ฐ ๋ ์ ์์
3. ํน์ฑ ๊ณตํ(Feature Engineering)
-
ํ์ต์ ์ํด์๋ ๊ฐ ๊ฐ๊ตฌ์ ๋ํด ์์ฝ๋ ๋ชจ๋ ์ ๋ณด๊ฐ ํ์ํจ
- ๊ฐ๊ตฌ ๋ด์ ๊ฐ์ธ์
groupby()
ํ๊ณ ๊ฐ๋ณ ๋ณ์์agg()
๋ฅผ ์ํํ๋ ๊ฒ์ ์๋ฏธ
- ๊ฐ๊ตฌ ๋ด์ ๊ฐ์ธ์
-
์ดํ ํน์ฑ ๊ณตํ์ ์๋ํ์ํค๋ ๋ฐฉ๋ฒ๋ ์์
3-1. ์ปฌ๋ผ(๋ณ์) ์ ์ํ๊ธฐ
-
data descriptions ๋ฅผ ํตํด ๊ฐ์ธ ์์ค๊ณผ ๊ฐ๊ตฌ ์์ค์ ์๋ ์ด์ ์ ์ํด์ผ ํจ
- ๋ณ์ ์์ฒด๋ฅผ ๊ฒํ
-
์ผ๋ถ ๋ณ์๋ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๋ณ์๋ฅผ ์ ์
- ๊ฐ ์์ค์์ ์ ์๋ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด ํ์์ ๋ฐ๋ผ ๋ณ์๋ฅผ ์ง๊ณํ ์ ์์
-
์งํ ํ๋ก์ธ์ค
-
๋ณ์๋ฅผ ๊ฐ๊ตฌ ์์ค๊ณผ ๊ฐ์ธ ์์ค์ผ๋ก ๋๋๊ธฐ
-
๊ฐ์ธ ์์ค์ ๋ฐ์ดํฐ์ ์ ํฉํ ์ง๊ณ ์ฐพ๊ธฐ
-
์์ํ(ordinal) ๋ณ์: ํต๊ณ์ ์ง๊ณ ํ์ฉ
-
๋ ผ๋ฆฌํ(bool)๋ณ์: ์ง๊ณํ ์๋ ์์ง๋ง, ํต๊ณ์น์ ์ข ๋ฅ๋ ์ ์
- ๊ฐ์ธ ์์ค์ ์ง๊ณ๋ฅผ ๊ฐ๊ตฌ ์์ค ๋ฐ์ดํฐ์ ๊ฒฐํฉ
๐ ๋ณ์๋ค์ ๋ฒ์ฃผ ์ ์ํ๊ธฐ
- ๋ณ์์๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฒ์ฃผ๊ฐ ์์
- Individual Variables: ๊ฐ์ธ๋ณ ํน์ฑ
-
boolean: yes or no(0 ๋๋ 1)
-
ordered discrete: ์์๊ฐ ์๋ ์ ์
- Household variables
-
boolean: Yes or No
-
ordered discrete: ์์๊ฐ ์๋ ์ ์
-
์ฐ์ํ ์์น
-
Squared Variables: ๋ฐ์ดํฐ์ (๋ณ์)^2์์ ํ์
-
Id variables: ๋ฐ์ดํฐ๋ฅผ ์๋ณ์ฉ, ํผ์ณ๋ก ์ฌ์ฉ x
### Id variables
id_ = ['Id', 'idhogar', 'Target']
### Individual Variables
ind_bool = ['v18q', 'dis', 'male', 'female', 'estadocivil1', 'estadocivil2', 'estadocivil3',
'estadocivil4', 'estadocivil5', 'estadocivil6', 'estadocivil7',
'parentesco1', 'parentesco2', 'parentesco3', 'parentesco4', 'parentesco5',
'parentesco6', 'parentesco7', 'parentesco8', 'parentesco9', 'parentesco10',
'parentesco11', 'parentesco12', 'instlevel1', 'instlevel2', 'instlevel3',
'instlevel4', 'instlevel5', 'instlevel6', 'instlevel7', 'instlevel8',
'instlevel9', 'mobilephone', 'rez_esc-missing']
ind_ordered = ['rez_esc', 'escolari', 'age']
### Household variables
hh_bool = ['hacdor', 'hacapo', 'v14a', 'refrig', 'paredblolad', 'paredzocalo',
'paredpreb','pisocemento', 'pareddes', 'paredmad',
'paredzinc', 'paredfibras', 'paredother', 'pisomoscer', 'pisoother',
'pisonatur', 'pisonotiene', 'pisomadera',
'techozinc', 'techoentrepiso', 'techocane', 'techootro', 'cielorazo',
'abastaguadentro', 'abastaguafuera', 'abastaguano',
'public', 'planpri', 'noelec', 'coopele', 'sanitario1',
'sanitario2', 'sanitario3', 'sanitario5', 'sanitario6',
'energcocinar1', 'energcocinar2', 'energcocinar3', 'energcocinar4',
'elimbasu1', 'elimbasu2', 'elimbasu3', 'elimbasu4',
'elimbasu5', 'elimbasu6', 'epared1', 'epared2', 'epared3',
'etecho1', 'etecho2', 'etecho3', 'eviv1', 'eviv2', 'eviv3',
'tipovivi1', 'tipovivi2', 'tipovivi3', 'tipovivi4', 'tipovivi5',
'computer', 'television', 'lugar1', 'lugar2', 'lugar3',
'lugar4', 'lugar5', 'lugar6', 'area1', 'area2', 'v2a1-missing']
hh_ordered = [ 'rooms', 'r4h1', 'r4h2', 'r4h3', 'r4m1','r4m2','r4m3', 'r4t1', 'r4t2',
'r4t3', 'v18q1', 'tamhog','tamviv','hhsize','hogar_nin',
'hogar_adul','hogar_mayor','hogar_total', 'bedrooms', 'qmobilephone']
hh_cont = ['v2a1', 'dependency', 'edjefe', 'edjefa', 'meaneduc', 'overcrowding']
sqr_ = ['SQBescolari', 'SQBage', 'SQBhogar_total', 'SQBedjefe',
'SQBhogar_nin', 'SQBovercrowding', 'SQBdependency', 'SQBmeaned', 'agesq']
- ์ค๋ณต ์ฌ๋ถ/ ๋น ์ง ๋ณ์ ํ์ธ
x = ind_bool + ind_ordered + id_ + hh_bool + hh_ordered + hh_cont + sqr_
from collections import Counter
print('There are no repeats: ', np.all(np.array(list(Counter(x).values())) == 1))
print('We covered every variable: ', len(x) == data.shape[1]) # ์ด์ ๊ฐ์์ ๋์ผํ์ง ํ์ธ
โบ Squared Variables
-
์ ํ ๋ชจํ์ด ๋น์ ํ ๊ด๊ณ๋ฅผ ํ์ตํ๋ ๋ฐ ๋์์ด ๋ ์ ์๊ธฐ ๋๋ฌธ์, ๋ณ์๊ฐ ํผ์ณ ์์ง๋์ด๋ง์ ์ผ๋ถ๋ก ์ ๊ณฑ๋๊ฑฐ๋ ๋ณํ๋๋ ๊ฒฝ์ฐ๊ฐ ์กด์ฌ
-
๋ ๋ณต์กํ ๋ชจ๋ธ์ ์ฌ์ฉํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ squared feature๋ค์ด ์ค๋ณต๋จ
-
์ ๊ณฑ๋์ง ์์ feature๋ค๊ณผ ๋์ ์๊ด๊ด๊ณ -> ๊ด๋ จ ์๋ ์ ๋ณด๋ฅผ ์ถ๊ฐํ๊ณ ํ์ต์ ๋๋ฆฌ๊ฒ ํจ์ผ๋ก์จ ๋ชจ๋ธ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น ์ ์์
-
ex>
SQBage
vsage
sns.lmplot(x = 'age', y = 'SQBage', data = data, fit_reg = False);
plt.title('Squared Age versus Age');
-
๋ ๋ณ์์ ์๊ด๊ณ์๊ฐ ๋งค์ฐ ํฌ๋ค.
- ๋ฐ์ดํฐ์ ๋ ๋ณ์ ๋ชจ๋๋ค ์ ์ฅํ ํ์๊ฐ x
# ์ ๊ณฑํ ๋ณ์ ์ ๊ฑฐํ๊ธฐ
data = data.drop(columns = sqr_)
data.shape
โบ Id Variables
- ๋ฐ์ดํฐ ์๋ณ์ ํ์ -> ์ ์ง
โบ Household Variables
heads = data.loc[data['parentesco1'] == 1, :]
heads = heads[id_ + hh_bool + hh_cont + hh_ordered]
heads.shape
-
๋๋ถ๋ถ์ ๊ฐ๊ตฌ ์์ค ๋ณ์์ ๊ฒฝ์ฐ ๊ทธ๋๋ก ์ ์งํ ์๋ ์์
-
์ผ๋ถ ์ค๋ณต ๋ณ์๋ฅผ ์ ๊ฑฐํ๊ณ ๊ธฐ์กด ๋ฐ์ดํฐ์์ ํ์๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์๋ ์์
์ค๋ณต๋ Household Variables
- ์๊ด ๊ด๊ณ๊ฐ ๋๋ฌด ๋์ ๋ณ์๊ฐ ์์ผ๋ฉด ์๊ด ๊ด๊ณ๊ฐ ๋์ ๋ณ์ ์ ์ค ํ๋๋ฅผ ์ ๊ฑฐํ ์ ์์
# ์๊ด๊ณ์ ํ๋ ฌ
corr_matrix = heads.corr()
# ์์ผ๊ฐํ๋ ฌ๋ง ๋จ๊ธฐ๊ธฐ
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))
# ์๊ด ๊ด๊ณ๊ฐ 0.95๋ณด๋ค ํฐ feeature column์ ์ธ๋ฑ์ค ์ฐพ๊ธฐ
to_drop = [column for column in upper.columns if any(abs(upper[column]) > 0.95)]
to_drop
corr_matrix.loc[corr_matrix['tamhog'].abs() > 0.9, corr_matrix['tamhog'].abs() > 0.9]
sns.heatmap(corr_matrix.loc[corr_matrix['tamhog'].abs() > 0.9, corr_matrix['tamhog'].abs() > 0.9],
annot=True, cmap = plt.cm.autumn_r, fmt='.3f');
-
์ง์ ํฌ๊ธฐ์ ๊ด๋ จ๋ ๋ช ๊ฐ์ง ๋ณ์๊ฐ ์์
-
r4t3
: ๊ฐ๊ตฌ ๋ด ์ด ์ธ์์ -
tamhog
: ๊ฐ๊ตฌ ํฌ๊ธฐ -
tamviv
: ๊ฐ๊ตฌ์ ์ฌ๋ ์ฌ๋๋ค์ ์ -
hhsize
: ๊ฐ๊ตฌ ํฌ๊ธฐ -
hogar_total
: ๊ฐ๊ตฌ ๊ตฌ์ฑ์ ์
-
-
์ด ๋ณ์๋ค์ ๋ชจ๋ ์๋ก ๋์ ์๊ด ๊ด๊ณ๋ฅผ ๊ฐ์ง
-
hhsize
๋tamhog
์hogar_total
๊ณผ ์๋ฒฝํ ์์ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง -
rt4t3
๊ณผhhsize
๋ ๊ฑฐ์ ์๋ฒฝํ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง
๋ ๋ณ์ ์ค ํ๋๋ฅผ ์ ๊ฑฐํ ์ ์์
-
heads = heads.drop(columns = ['tamhog', 'hogar_total', 'r4t3'])
- hhsize vs tamviv
sns.lmplot(x = 'tamviv', y = 'hhsize', data = data, fit_reg = False);
plt.title('Household size vs number of persons living in the household');
- ๊ฐ์กฑ๋ณด๋ค ๊ฐ๊ตฌ์ ๋ ๋ง์ ์ฌ๋๋ค์ด ์ด๊ณ ์์..?
~(๋ฌด์จ ์๋ฏธ์ธ์ง..)~
heads['hhsize-diff'] = heads['tamviv'] - heads['hhsize']
plot_categoricals('hhsize-diff', 'Target', heads)
- ๋๋ถ๋ถ์ ๊ฐ๊ตฌ๋ ์ฐจ์ด๊ฐ ์์ง๋ง ๊ฐ๊ตฌ ๊ตฌ์ฑ์๋ณด๋ค ๊ฐ๊ตฌ์ ์ด๊ณ ์๋ ์ฌ๋์ ์๊ฐ ๋ง์ ๊ฒฝ์ฐ๊ฐ ์ ์ง๋ง ์กด์ฌํจ
- coopele ๋ณ์
corr_matrix.loc[corr_matrix['coopele'].abs() > 0.9, corr_matrix['coopele'].abs() > 0.9]
-
coopele
: ๊ฐ์ ์ ์ ๊ธฐ๊ฐ ์ด๋์์ ์ค๋์ง๋ฅผ ๋ํ๋ -
๋ค ๊ฐ์ง ์ ํ์ง๊ฐ ์๋๋ฐ, ์ด ๋ ๊ฐ์ง ์ ํ์ง ์ค ํ๋๊ฐ ์๋ ๊ฐ์ ์ ์ ๊ธฐ๊ฐ ์๊ฑฐ๋(
noelec
) ๊ฐ์ธ ๋ฐ์ ์์์ ๊ณต๊ธ๋ฐ์(planpri
)
0: No electricity
1: Electricity from cooperative
2: Electricity from CNFL, ICA, ESPH/JASEC
3: Electricity from private plant
-
์ ๋ ฌ๋ ๋ณ์์๋ ๊ณ ์ ํ ์์๊ฐ ์์ผ๋ฉฐ, ๋๋ฉ์ธ ์ง์์ ๊ธฐ๋ฐํ์ฌ ์ ํ
-
์๋ก์ด ์์ํ ๋ณ์๋ฅผ ์์ฑํ ๋ค์, ๊ธฐ์กด์ ๋ณ์๋ค์ ์ญ์ ํด๋ ok
-
๊ฒฐ์ธก์น์ธ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ
NaN
์ ์ ๋ ฅํ๊ณ boolean ์ปฌ๋ผ์ผ๋ก ํด๋น ๋ณ์์ ๋ํ ์ ๋ณด๊ฐ ์์์ ํ์
elec = []
# ๊ฐ ํ ๋น(mapping)
for i, row in heads.iterrows():
if row['noelec'] == 1:
elec.append(0)
elif row['coopele'] == 1:
elec.append(1)
elif row['public'] == 1:
elec.append(2)
elif row['planpri'] == 1:
elec.append(3)
else:
elec.append(np.nan)
# ๊ฒฐ์ธก์น ์ฒ๋ฆฌ
heads['elec'] = elec
heads['elec-missing'] = heads['elec'].isnull()
# ๊ธฐ์กด ์ปฌ๋ผ ์ ๊ฑฐ
# heads = heads.drop(columns = ['noelec', 'coopele', 'public', 'planpri'])
plot_categoricals('elec', 'Target', heads)
- target์ ๋ชจ๋ ๊ฐ์ ๋ํด ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ ๊ธฐ ๊ณต๊ธ์์ด ๋์ด๋ ๊ณต๊ธ์ ์ฒด ์ค ํ๋์์ ์ ์ ์์
-
area2 ๋ณ์
-
์ง์ด ์๊ณจ ์ง์ญ์ ์๋ค๋ ๊ฒ์ ์๋ฏธ
- ์ง์ด ๋์ ์ง์ญ์ ์๋์ง๋ฅผ ๋ํ๋ด๋ ์ด(area1)์ด ์๊ธฐ ๋๋ฌธ์ ์ค๋ณต๋ฉ
ํด๋น ์ด ์ญ์
heads = heads.drop(columns = 'area2')
heads.groupby('area1')['Target'].value_counts(normalize = True)
- ๋์ ์ง์ญ์ ๊ฐ๊ตฌ(value = 1)๋ ๋์ด ์ง์ญ์ ๊ฐ๊ตฌ(value = 0)๋ณด๋ค ๋น๊ณค ์์ค์ด ๋ฎ์ ๊ฐ๋ฅ์ฑ์ด ๋ ๋์ ๊ฒ์ผ๋ก ํ๋จ๋จ
โบ Ordinal Variables
-
์ง์ ๋ฒฝ, ์ง๋ถ, ๋ฐ๋ฅ์๋ ๊ฐ๊ฐ 3๊ฐ์ column์ด ์กด์ฌํจ
- โbadโ, โregularโ, โgoodโ
-
๋ณ์๋ฅผ boolean ํ์ผ๋ก ๋ ๋ ์๋ ์์ง๋ง, bad < regular < good์ด๋ผ๋ ๋ช ํํ ์์๊ฐ ์กด์ฌํจ
-
์์ํ ๋ณ์๋ก ๋ฐ๊พธ๋ ๊ฒ์ด ๋ ์ข์ ๋ณด์
-
np.argmax()
๋ฅผ ํตํด ๊ฐ ๊ฐ๊ตฌ์ ๋ํด 0์ด ์๋ ์ด์ ์ฝ๊ฒ ์ฐพ์ ์ ์์
-
### Wall ordinal variable
heads['walls'] = np.argmax(np.array(heads[['epared1', 'epared2', 'epared3']]),
axis = 1)
# heads = heads.drop(columns = ['epared1', 'epared2', 'epared3'])
plot_categoricals('walls', 'Target', heads)
### Roof ordinal variable
heads['roof'] = np.argmax(np.array(heads[['etecho1', 'etecho2', 'etecho3']]),
axis = 1)
heads = heads.drop(columns = ['etecho1', 'etecho2', 'etecho3'])
### Floor ordinal variable
heads['floor'] = np.argmax(np.array(heads[['eviv1', 'eviv2', 'eviv3']]),
axis = 1)
# heads = heads.drop(columns = ['eviv1', 'eviv2', 'eviv3'])
3-2. ๋ณ์(feature) ๊ตฌ์ฑํ๊ธฐ
-
๋ณ์๋ฅผ ์์ํ ํผ์ฒ์ ๋งคํํ๋ ๊ฒ ์ธ์๋ ๊ธฐ์กด ๋ฐ์ดํฐ์์ ์์ ํ ์๋ก์ด ํผ์ฒ๋ฅผ ์์ฑํ ์๋ ์์
- ์์> ์ด์ ์ ์ธ ๊ฐ์ง ํน์ง(wall, roof, floor)์ ํฉ์ฐํ์ฌ ์ง ๊ตฌ์กฐ์ ์ ๋ฐ์ ์ธ ํ์ง์ ์ธก์ ํ ์ ์์
-
walls + roof + floor
# ์๋ก์ด feature ์์ฑํ๊ธฐ
heads['walls+roof+floor'] = heads['walls'] + heads['roof'] + heads['floor']
plot_categoricals('walls+roof+floor', 'Target', heads, annotate = False)
- ์๋ก์ด feature๋ target = 4(the lowest poverty level)์์
house quality
๋ณ์์ ๊ฐ์ด ๋ ๋์ ๊ฒฝํฅ์ด ์๋ ๊ฒ์ฒ๋ผ ๋ณด์
counts = pd.DataFrame(heads.groupby(['walls+roof+floor'])['Target'].value_counts(normalize = True)).rename(columns = {'Target': 'Normalized Count'}).reset_index()
counts.head()
-
warning
-
์ง์ ์ง์ ๋ํ ๊ฒฝ๊ณ
-
ํ์ฅ์ค, ์ ๊ธฐ, ๋ฐ๋ฅ, ์๋, ์ฒ์ฅ์ด ์๋ ๊ฒฝ์ฐ ๊ฐ๊ฐ -1์ ์ ๋ง์ด๋์ค ๊ฐ
# No toilet, no electricity, no floor, no water service, no ceiling
heads['warning'] = 1 * (heads['sanitario1'] +
(heads['elec'] == 0) +
heads['pisonotiene'] +
heads['abastaguano'] +
(heads['cielorazo'] == 0))
### seaborn์ violin plot์ผ๋ก ์๊ฐํ
plt.figure(figsize = (10, 6))
sns.violinplot(x = 'warning', y = 'Target', data = heads)
plt.title('Target vs Warning Variable');
-
๋ฐ์ด์ฌ๋ฆฐ ํ๋กฏ์ ๋์์ด ์ค์ ๋ณด๋ค ๋ ์๊ณ ๋ ํฐ ๊ฐ์ ๊ฐ์ง ์ ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ ํจ๊ณผ๋ก ๋ฒ์ฃผํ ๋ณ์๋ฅผ ํํ(smoothing)ํ๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์๋ ์ ํฉํ์ง ์์ ๊ฒ์ผ๋ก ํ๋จ๋จ
- ํ์ง๋ง, ๊ฒฝ๊ณ ์ ํธ๊ฐ ์๋ ๊ฐ๊ตฌ ๊ทธ๋ฃน์ ๋น๊ณค ์์ค์ด ๊ฐ์ฅ ๋ฎ์ ๊ฐ๊ตฌ๋ค์ด ์ง์ค๋ ๊ฒ์ ํ์ธํ ์ ์์
plot_categoricals('warning', 'Target', data = heads)
-
bonus
-
๋์ฅ๊ณ , ์ปดํจํฐ, ํ๋ธ๋ฆฟ, ํ ๋ ๋น์ ์ ๊ฐ์ง๊ณ ์์ผ๋ฉด ์ ์๊ฐ ์ฌ๋ผ๊ฐ๋ ๋ณ์
# Owns a refrigerator, computer, tablet, and television
heads['bonus'] = 1 * (heads['refrig'] +
heads['computer'] +
(heads['v18q1'] > 0) +
heads['television'])
sns.violinplot(x = 'bonus', y = 'Target',
data = heads, figsize = (10, 6))
plt.title('Target vs Bonus Variable');
3-3. Per Capita Features
-
๊ฐ๊ตฌ์ ๋ณ๋ก ํน์ ์ธก์ ๊ฐ์ ์๋ฅผ ๊ณ์ฐ
-
ํน์ ๊ฐ / ๊ฐ๊ตฌ ๊ตฌ์ฑ์ ์
heads['phones-per-capita'] = heads['qmobilephone'] / heads['tamviv']
heads['tablets-per-capita'] = heads['v18q1'] / heads['tamviv']
heads['rooms-per-capita'] = heads['rooms'] / heads['tamviv']
heads['rent-per-capita'] = heads['v2a1'] / heads['tamviv']
3-4. Household Variables ์ดํด๋ณด๊ธฐ
- ๊ด๊ณ๋ฅผ ์ ๋ํ
a) ์๊ด๊ด๊ณ ํ์ธํ๊ธฐ
- ๋ ๋ณ์ ์ฌ์ด์ ๊ด๊ณ๋ฅผ ์ธก์ ํ๋ ๋ฐ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์
1. Pearson Correlation
-
-1๋ถํฐ 1๊น์ง ๋ ๋ณ์ ์ฌ์ด์ ์ ํ ๊ด๊ณ ์ธก์
-
์ฆ๊ฐ ์ถ์ธ๊ฐ ์ ํํ๊ฒ ์ ํ์ธ ๊ฒฝ์ฐ์๋ง ํ๋๊ฐ ๋ ์ ์์
2. Spearman Correlation
-
-1์์ 1๊น์ง ๋ ๋ณ์์ ๋จ์กฐ๋ก์ด ๊ด๊ณ๋ฅผ ์ธก์
-
ํ ๋ณ์๊ฐ ์ฆ๊ฐํจ์ ๋ฐ๋ผ ๊ด๊ณ๊ฐ ์ ํ์ ์ด์ง ์๋๋ผ๋ ๋ค๋ฅธ ๋ณ์๋ ์ฆ๊ฐํ๋ ๊ฒฝ์ฐ ์๊ด๊ณ์๊ฐ 1์
-
์คํผ์ด๋ง ์๊ด๊ณ์ ๊ณ์ฐ์๋ ๊ด๊ณ์ ์ค์์ฑ ์์ค์ ๋ํ๋ด๋
p-value
๋ ํจ๊ป ์ฐ์ถ๋จp-value
๊ฐ 0.05 ๋ฏธ๋ง์ด๋ฉด ์ผ๋ฐ์ ์ผ๋ก ์ ์ํ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋จ
- ์๊ด๊ณ์ ํด์
- 0.00 ~ 0.19: "๋งค์ฐ ์ฝํ ์๊ด๊ด๊ณ"
- 0.20 ~ 0.39: "์ฝํ ์๊ด๊ด๊ณ"
- 0.40 ~ 0.59: "์ด๋ ์ ๋์ ์๊ด๊ด๊ณ"
- 0.60 ~ 0.79: "๊ฐํ ์๊ด๊ด๊ณ"
- 0.80 ~ 1.0: "๋งค์ฐ ๊ฐํ ์๊ด๊ด๊ณ"
-
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๋ ์๊ด๊ด๊ณ๋ ๋น์ทํจ
-
์คํผ์ด๋ง ์๊ด๊ด๊ณ๋ ์ข ์ข ์์ํ ๋ณ์์ ๋ํด ๋ ๋์ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ํ๋จ๋จ
-
์ค์ ์ธ๊ณ์์ ๋๋ถ๋ถ์ ๊ด๊ณ๋ ์ ํ์ ์ด์ง ์์
-
Pearson ์๊ด๊ด๊ณ๋ ๋ ๋ณ์๊ฐ ์ผ๋ง๋ ๊ด๋ จ๋์ด ์๋์ง์ ๋ํ ๊ทผ์ฌ์น์ผ ์ ์์ง๋ง, ์ ํํ์ง ์๊ณ ๊ฐ์ฅ ์ข์ ๋น๊ต ๋ฐฉ๋ฒ ๋ํ ์๋
-
from scipy.stats import spearmanr
### ์๊ด๊ณ์ ์๊ฐํ
def plot_corrs(x, y):
# ์๊ด๊ณ์ ๊ณ์ฐ
spr = spearmanr(x, y).correlation
pcr = np.corrcoef(x, y)[0, 1]
# ์ฐ์ ๋ plot
data = pd.DataFrame({'x': x, 'y': y})
plt.figure( figsize = (6, 4))
sns.regplot(data = data, x = 'x', y = 'y', fit_reg = False)
plt.title(f'Spearman: {round(spr, 2)}; Pearson: {round(pcr, 2)}')
- Example
x = np.array(range(100))
y = x ** 2
plot_corrs(x, y)
x = np.array([1, 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 9])
y = np.array([1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 3, 3, 2, 4, 2, 2, 4])
plot_corrs(x, y)
x = np.array(range(-19, 20))
y = 2 * np.sin(x)
plot_corrs(x, y)
๐ Pearson ์๊ด ๊ด๊ณ
### ํ์ต(train) ๋ฐ์ดํฐ๋ง ์ฌ์ฉ
train_heads = heads.loc[heads['Target'].notnull(), :].copy()
pcorrs = pd.DataFrame(train_heads.corr()['Target'].sort_values()).rename(columns = {'Target': 'pcorr'}).reset_index()
pcorrs = pcorrs.rename(columns = {'index': 'feature'})
print('Most negatively correlated variables:')
print(pcorrs.head())
print('\nMost positively correlated variables:')
print(pcorrs.dropna().tail())
-
์์ ์๊ด๊ด๊ณ์ ๊ฒฝ์ฐ ๋ณ์์ ๊ฐ์ด ์ฆ๊ฐํ ์๋ก target๊ฐ์ด ๊ฐ์ํจ์ ์๋ฏธ
- ๋น๊ณค ์ฌ๊ฐ๋๊ฐ ์ฆ๊ฐํจ์ ์๋ฏธ
-
warning
์ด ์ฆ๊ฐํจ์ ๋ฐ๋ผ ๋น๊ณค ์์ค๋ ์ฆ๊ฐ- ์ด๋ ์ง์ ๋ํ ์ ์ฌ์ ์ธ ๋์ ์งํ๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ํ๋นํจ
-
hogar_nin
-
์ด๋ ๊ฐ์กฑ ๋ด 0~19๋ช ์ ์์ด๋ค์ ์ซ์๋ก, ๋ ์ด๋ฆฐ ์์ด๋ค์ด ๋ ๋์ ์์ค์ ๋น๊ณค์ผ๋ก ์ด์ด์ง๋ ๊ฐ์กฑ์๊ฒ ์คํธ๋ ์ค์ ์ฌ์ ์ ์ธ ์์ธ์ด ๋ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธ
-
์ฌํ ๊ฒฝ์ ์ ์ง์๊ฐ ๋ฎ์ ๊ฐ์ ๋ค์ ๊ทธ๋ค ์ค ํ ๋ช ์ด ์ฑ๊ณตํ ์ ์๊ธฐ๋ฅผ ๋ฐ๋ผ๋ ๋ง์์ผ๋ก ๋ ๋ง์ ์์ด๋ค์ ๊ฐ์ง๋ ๊ฒฝํฅ์ด ์์
๊ฐ์กฑ ๊ท๋ชจ์ ๋น๊ณค ์ฌ์ด์๋ ์ค์ง์ ์ธ ์ฐ๊ด์ฑ์ด ์๋ค.
-
-
์์ ์๊ด๊ด๊ณ์ ๊ฒฝ์ฐ, ๋ณ์์ ๊ฐ์ด ์ฆ๊ฐํ ์๋ก Target๊ฐ์ด ์ฆ๊ฐํจ์ ์๋ฏธ
- ๋น๊ณค ์ฌ๊ฐ๋๊ฐ ๊ฐ์ํจ์ ์๋ฏธ
-
meaneduc
-
๊ฐ๊ตฌ ๋ด ์ฑ์ธ์ ํ๊ท ๊ต์ก ์์ค์ ๋ํ๋ด๋ ๊ฐ๊ตฌ ์์ค์ ๋ณ์
-
target๊ณผ ๊ฐ์ฅ ๋์ ์์ ์๊ด๊ด๊ณ๋ฅผ ๋ณด์
๊ต์ก์ ๋ฎ์ ์์ค์ ์ผ๋ฐ์ ์ผ๋ก ๋น๊ณค์ ๋ฎ์ ์์ค๊ณผ ์๊ด๊ด๊ณ๊ฐ ์๋ค.
-
-
๋ณ์์ target ๊ฐ์ ์ฝํ ์๊ด๊ด๊ณ๊ฐ ์กด์ฌํจ์ ํ์ธํ ์ ์์
๐ ์คํผ์ด๋ง ์๊ด ๊ด๊ณ
import warnings
warnings.filterwarnings('ignore', category = RuntimeWarning)
feats = [] # features
scorr = [] # scores
pvalues = [] # p-value
# ๊ฐ ์ปฌ๋ผ(๋ณ์)๋ณ๋ก
for c in heads:
# ์ซ์ํ ๋ณ์๋ค์ ๋ํด..
if heads[c].dtype != 'object':
feats.append(c)
# ์คํผ์ด๋ง ์๊ด๊ณ์ ๊ณ์ฐ
scorr.append(spearmanr(train_heads[c], train_heads['Target']).correlation)
pvalues.append(spearmanr(train_heads[c], train_heads['Target']).pvalue)
scorrs = pd.DataFrame({'feature': feats, 'scorr': scorr, 'pvalue': pvalues}).sort_values('scorr')
-
p-value๊ฐ 0.05 ๋ฏธ๋ง์ด๋ฉด ์ผ๋ฐ์ ์ผ๋ก ์ ์ํ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋จ
- ์ฐ๋ฆฌ๋ ๋ค์ค ๋น๊ต๋ฅผ ์ํํ๊ธฐ ๋๋ฌธ์ p-value๋ฅผ ๋น๊ต ํ์๋ก ๋๋๊ณ ์ ํจ
Bonferroni ์์ ์ด๋ผ ํจ
print('Most negative Spearman correlations:')
print(scorrs.head())
print()
print('\nMost positive Spearman correlations:')
print(scorrs.dropna().tail())
- ์๊ด๊ด๊ณ๋ฅผ ์ธก์ ํ๋ ๋ ๊ณ์ ๋ชจ๋ ๋น์ทํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ด๊ณ ์๋ค.
corrs = pcorrs.merge(scorrs, on = 'feature')
corrs['diff'] = corrs['pcorr'] - corrs['scorr'] # p-value - ์๊ด๊ณ์
corrs.sort_values('diff').head()
corrs.sort_values('diff').dropna().tail()
dependency
๋ณ์๊ฐ ๊ฐ์ฅ ํฐ ์ฐจ์ด๋ฅผ ๋ณด์
### ์๊ฐํ
# ๋ ๋ณ์ ๋ชจ๋ ์ด์ฐํ ๋ณ์์ด๊ธฐ์, plot์ ์ฝ๊ฐ์ jitter๋ฅผ ์ถ๊ฐํจ
sns.lmplot(x = 'dependency', y = 'Target', fit_reg = True, data = train_heads,
x_jitter = 0.05, y_jitter = 0.05)
plt.title('Target vs Dependency')
-
์ฝํ ์์ ์๊ด๊ด๊ณ๋ฅผ ๋ณด์
-
dependency
๊ฐ ์ฆ๊ฐํ ์๋กtarget
๊ฐ์ด ๊ฐ์ํจ -
dependency
๊ฐ (dependent)/(non-dependent)๋ฅผ ๋ํ๋์ ์๋ฏธ -
ํด๋น ๊ฐ์ด ์ฆ๊ฐํ๋ฉด, ๋น๊ณค์ ์ฌ๊ฐ์ฑ์ด ์ฆ๊ฐํ๋ ๊ฒฝํฅ์ด ์์
-
(๋ณดํต ์ผ์ ํ์ง ์๋) ์์กด์ ์ธ ๊ฐ์กฑ ๊ตฌ์ฑ์์ ๋น์์กด์ ์ธ ๊ฐ์กฑ ๊ตฌ์ฑ์์ ์ง์์ ๋ฐ์์ผ ํจ => ๋ ๋์ ์์ค์ ๋น๊ณค์ผ๋ก ์ด์ด์ง
sns.lmplot(x = 'rooms-per-capita', y = 'Target', fit_reg = True, data = train_heads,
x_jitter = 0.05, y_jitter = 0.05)
plt.title('Target vs Rooms Per Capita')
- ์ฝํ ์์ ์๊ด๊ด๊ณ๋ฅผ ๋ณด์
๐์๊ด๊ณ์ heatmap
- ์๊ด๊ณ์ ์๊ฐํ
# Household Variables
variables = ['Target', 'dependency', 'warning', 'walls+roof+floor', 'meaneduc',
'floor', 'r4m1', 'overcrowding']
# ์๊ด๊ณ์ ๊ณ์ฐ
corr_mat = train_heads[variables].corr().round(2)
# heatmap ์์ฑ
plt.rcParams['font.size'] = 18
plt.figure(figsize = (12, 12))
sns.heatmap(corr_mat, vmin = -0.5, vmax = 0.8, center = 0,
cmap = plt.cm.RdYlGn_r, annot = True);
-
target๊ณผ ์ฝํ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๋ ๋ณ์๋ค์ด ์๋น์ ์กด์ฌํจ์ ๋ณด์ฌ์ค
-
์ผ๋ถ ๋ณ์๋ค์ ๊ฒฝ์ฐ ๋ณ์๋ค ๊ฐ์ ์๊ด๋๊ฐ ๋์
-
floor
vswalls+roof+floor
-
๋ค์ค๊ณต์ ์ฑ(multicollinearity) ๋ฌธ์
-
b) ๋ณ์ ์๊ฐํ
- ์์ชฝ ์ผ๊ฐํ์๋ ์ฐ์ ๋(scatterplot), ๋๊ฐ์ ์๋ ์ปค๋ ๋ฐ๋ plot(KDE), ์๋์ชฝ ์ผ๊ฐํ์๋ 2์ฐจ์ KDE ๊ทธ๋ฆผ์ ํ์ํด๋ณด์!
import warnings
warnings.filterwarnings('ignore')
# ์๊ฐํ ํ ๋ณ์ ์ ํ
plot_data = train_heads[['Target', 'dependency', 'walls+roof+floor',
'meaneduc', 'overcrowding']]
# ์์ญ ๋๋๊ธฐ -> pairgrid
grid = sns.PairGrid(data = plot_data, diag_sharey = False,
hue = 'Target', hue_order = [4, 3, 2, 1],
vars = [x for x in list(plot_data.columns) if x != 'Target'])
# Upper: scatter plot
grid.map_upper(plt.scatter, alpha = 0.8, s = 20)
# Diagonal: kdeplot
grid.map_diag(sns.kdeplot)
# Bottom: 2์ฐจ์ kdeplot
grid.map_lower(sns.kdeplot, cmap = plt.cm.OrRd_r)
grid = grid.add_legend()
plt.suptitle('Feature Plots Colored By Target', size = 32, y = 1.05)
household_feats = list(heads.columns) # ๊ฐ๊ตฌ ์์ค์์์ ๋ณ์๋ค์ ์ต์ข
์ ์ผ๋ก ์ ์ฅ
3-5. Individual Level Variables
-
๋ ๊ฐ์ง ์ ํ์ด ์กด์ฌํจ
-
booleanํ ๋ณ์(1 or 0)
-
์์ํ(ordinal) ๋ณ์(์๋ฏธ ์๋ ์์๊ฐ ์ง์ ๋ ๊ฐ๋ณ ๊ฐ)
-
ind = data[id_ + ind_bool + ind_ordered]
ind.shape
a) ์ค๋ณต ๋ณ์ ์ ๊ฑฐํ๊ธฐ
- ์๊ด ๊ณ์์ ์ ๋๊ฐ์ด 0.95๋ณด๋ค ํฐ ๋ณ์์ ์ฃผ๋ชฉํ์.
# ์๊ด๊ณ์ ํ๋ ฌ ์์ฑ
corr_matrix = ind.corr()
# ์์ผ๊ฐํ๋ ฌ๋ง ๋จ๊ธฐ๊ธฐ
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k = 1).astype(np.bool))
# ์๊ด๊ณ์๊ฐ 0.95 ์ด์์ธ ๋ณ์๋ค
to_drop = [column for column in upper.columns if any(abs(upper[column]) > 0.95)]
to_drop
-
์ด๋ ๋จ์ํ ๋จ์ฑ์ ๋ฐ๋๋ฅผ ์๋ฏธ
- ๋จ์ฑ flag ๋ณ์๋ฅผ ์ ๊ฑฐ
ind = ind.drop(columns = 'male')
b) ์์ํ ๋ณ์ ์์ฑํ๊ธฐ
-
๊ธฐ์กด์ ๋ณ์๋ค์ ์์ํ ๋ณ์๋ก ๋งคํ ๊ฐ๋ฅ
- ๊ฐ์ธ์ ๊ต์ก ์์ค์ ๋ํ๋ด๋
instlevel_
๋ณ์๋ฅผ ์ค์ฌ์ผ๋ก 1(๊ต์ก ์์ค์ด x)๋ถํฐ 9(๋ํ์)๊น์ง mapping
- ๊ฐ์ธ์ ๊ต์ก ์์ค์ ๋ํ๋ด๋
ind[[c for c in ind if c.startswith('instl')]].head()
ind['inst'] = np.argmax(np.array(ind[[c for c in ind if c.startswith('instl')]]), axis = 1)
plot_categoricals('inst', 'Target', ind, annotate = False);
- ๋ ๋์ ์์ค์ ๊ต์ก์ ๋ฐ์์๋ก ๋ ๊ทน๋จ์ ์ธ ์์ค์ ๋น๊ณค์ ํด๋นํ๋ ๊ฒ์ผ๋ก ๋ณด์
plt.figure(figsize = (10, 8))
sns.violinplot(x = 'Target', y = 'inst', data = ind)
plt.title('Education Distribution by Target');
# Drop the education columns
# ind = ind.drop(columns = [c for c in ind if c.startswith('instlevel')])
ind.shape
c) ์๋ก์ด ๋ณ์ ์์ฑํ๊ธฐ
- ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ช ๊ฐ์ง ๋ณ์๋ค์ ๋ง๋ค ์ ์์
ind['escolari/age'] = ind['escolari'] / ind['age']
plt.figure(figsize = (10, 8))
sns.violinplot(x = 'Target', y = 'escolari/age', data = ind)
ind['inst/age'] = ind['inst'] / ind['age']
ind['tech'] = ind['v18q'] + ind['mobilephone']
ind['tech'].describe()
3-6. ๋ณ์ ์ง๊ณ
-
๊ฐ๋ณ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ตฌ ๋ฐ์ดํฐ์ ํตํฉํ๊ธฐ ์ํด์๋ ๊ฐ๊ตฌ๋ณ ์ง๊ณ๊ฐ ํ์
- ๊ฐ์กฑ ID์ธ
idhogar
๋ก ๊ทธ๋ฃนํ ํ ๋ฐ์ดํฐ๋ฅผagg
๋ก ๊ทธ๋ฃนํ
- ๊ฐ์กฑ ID์ธ
### ์ง๊ณ(aggregation)๋ฅผ ์ํ ์ฌ์ฉ์ ์ ์ ํจ์
range_ = lambda x: x.max() - x.min() # ํ ์ค์ง๋ฆฌ ํจ์๋ ์ฃผ๋ก lambda ์์ผ๋ก ๊ตฌํ
range_.__name__ = 'range_'
# ๊ทธ๋ฃนํ & ์ง๊ณ
ind_agg = ind.drop(columns = ['Target','Id']).groupby('idhogar').agg(['min', 'max', 'sum', 'count', 'std', range_])
ind_agg.head()
- ๋ณ์๊ฐ 30๊ฐ์์ 180๊ฐ๊ฐ ๋์๋ค..
### ๋ณ์ ์ด๋ฆ ์ฌ์ ์
new_col = []
for c in ind_agg.columns.levels[0]:
for stat in ind_agg.columns.levels[1]:
new_col.append(f'{c}-{stat}')
ind_agg.columns = new_col
ind_agg.head()
ind_agg.iloc[:, [0, 1, 2, 3, 6, 7, 8, 9]].head()
3-7. ๋ณ์ ์ ํ
- ์๊ด ๊ด๊ณ๊ฐ 0.95๋ณด๋ค ํฐ ๋ณ์๋ค์ ์ ์ค ํ๋๋ฅผ ์ ๊ฑฐ
# Create correlation matrix
corr_matrix = ind_agg.corr()
# Select upper triangle of correlation matrix
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))
# Find index of feature columns with correlation greater than 0.95
to_drop = [column for column in upper.columns if any(abs(upper[column]) > 0.95)]
print(f'There are {len(to_drop)} correlated columns to remove.')
- ๋ณ์๋ฅผ ์ ๊ฑฐํ๊ณ ,
head
๋ฐ์ดํฐ์ ๋ณํฉํ์ฌ ์ต์ข ๋ฐ์ดํฐํ๋ ์์ ์์ฑ
ind_agg = ind_agg.drop(columns = to_drop)
ind_feats = list(ind_agg.columns)
# Merge on the household id
final = heads.merge(ind_agg, on = 'idhogar', how = 'left')
print('Final features shape: ', final.shape)
final.head()
3-8. ์ต์ข ์ ์ธ ๋ฐ์ดํฐ ํ์
a) ์๊ด๊ณ์ ํ์ธ
corrs = final.corr()['Target']
corrs.sort_values().head()
corrs.sort_values().dropna().tail()
-
์์ฑ๋ ๋ณ์ ์ค ์ผ๋ถ๊ฐ target ๋ณ์์ ๋์ ์๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ ๊ฒ์ ํ์ธํ ์ ์์
-
ํด๋น ๋ณ์๊ฐ ์ค์ ๋ก ์ ์ฉํ์ง๋ ๋ชจ๋ธ๋ง ๋จ๊ณ์์ ํ๋จํ ์์
b) escolari ๋ณ์
plot_categoricals('escolari-max', 'Target', final, annotate = False)
plt.figure(figsize = (10, 6))
sns.violinplot(x = 'Target', y = 'escolari-max', data = final)
plt.title('Max Schooling by Target')
plt.figure(figsize = (10, 6))
sns.boxplot(x = 'Target', y = 'escolari-max', data = final)
plt.title('Max Schooling by Target')
c) meaneduc ๋ณ์
plt.figure(figsize = (10, 6))
sns.boxplot(x = 'Target', y = 'meaneduc', data = final)
plt.xticks([0, 1, 2, 3], poverty_mapping.values())
plt.title('Average Schooling by Target')
d) Overcrowing ๋ณ์
plt.figure(figsize = (10, 6))
sns.boxplot(x = 'Target', y = 'overcrowding', data = final)
plt.xticks([0, 1, 2, 3], poverty_mapping.values())
plt.title('Overcrowding by Target')
e) ๊ฐ์ฅ์ ์ฑ๋ณ
head_gender = ind.loc[ind['parentesco1'] == 1, ['idhogar', 'female']]
final = final.merge(head_gender, on = 'idhogar', how = 'left').rename(columns = {'female': 'female-head'})
final.groupby('female-head')['Target'].value_counts(normalize=True)
- ๊ฐ์ฅ์ด ์ฌ์ฑ์ธ ๊ฐ๊ตฌ๋ ๋น๊ณค ์์ค์ ์ฌ๊ฐํ ๊ฐ๋ฅ์ฑ์ด ์ฝ๊ฐ ๋ ๋์ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค.
sns.violinplot(x = 'female-head', y = 'Target', data = final)
plt.title('Target by Female Head of Household');
๊ฐ์ฅ์ ์ฑ๋ณ์ ๋ฐ๋ฅธ ํ๊ท ๊ต์ก ์์ค ์ฐจ์ด
plt.figure(figsize = (8, 8))
sns.boxplot(x = 'Target', y = 'meaneduc', hue = 'female-head', data = final)
plt.title('Average Education by Target and Female Head of Household', size = 16)
-
์ฌ์ฑ ๊ฐ์ฅ์ ๋ ๊ฐ๊ตฌ์ผ์๋ก ๊ต์ก ์์ค์ด ๋์ ๊ฒ์ผ๋ก ๋ณด์
-
๊ทธ๋ฌ๋ ์ ์ฒด์ ์ผ๋ก ์ฌ์ฑ์ด ๊ฐ์ฅ์ธ ๊ฐ๊ตฌ๋ ์ฌ๊ฐํ ๋น๊ณค์ ๊ฒช์ ๊ฐ๋ฅ์ฑ์ด ๋ ๋๋ค๋ ๊ฒ์ ์ ์ ์์
final.groupby('female-head')['meaneduc'].agg(['mean', 'count'])
- ์ ์ฒด์ ์ผ๋ก ์ฌ์ฑ ๊ฐ์ฅ์ด ์๋ ๊ฐ๊ตฌ์ ํ๊ท ๊ต์ก ์์ค์ ๋จ์ฑ ๊ฐ์ฅ์ด ์๋ ๊ฐ๊ตฌ๋ณด๋ค ์ฝ๊ฐ ๋์
4. Baseline Model
-
๋ชจ๋ ๋ฐ์ดํฐ(train/test)๋ ๊ฐ ๊ฐ๊ตฌ์ ๋ํด ์ง๊ณ๋๋ฏ๋ก ๋ชจ๋ธ์ ์ง์ ์ฌ์ฉํ ์ ์์
-
sklearn์
RandomForest
๋ฅผ ํ์ฉํ์ฌ ๋ชจ๋ธ๋ง ๊ธฐ์ค ์ฐพ๊ธฐ -
๋ชจ๋ธ์ ํ๊ฐํ๊ธฐ ์ํด train ๋ฐ์ดํฐ์
10-fold ๊ต์ฐจ ๊ฒ์ฆ
์ ํ์ฉ- ๋ฐ์ดํฐ๋ฅผ ์๋ก ๋ค๋ฅธ ๋ฐ์ดํฐ ์งํฉ์ผ๋ก ๋ถํ ํ์ฌ ๋ชจ๋ธ์ ์ด 10๋ฒ ํ๋ จ
-
๊ต์ฐจ ๊ฒ์ฆ์ ํ๊ท ์ฑ๋ฅ๊ณผ ํ์ค ํธ์ฐจ๋ฅผ ์กฐ์ฌํ์ฌ fold ๊ฐ์ ์ ์๊ฐ ์ผ๋ง๋ ๋ณํ๋์ง ํ์ธ
Fl Macro Score
๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ ํ๊ฐ
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import f1_score, make_scorer
from sklearn.model_selection import cross_val_score
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline
# ๊ต์ฐจ ๊ฒ์ฆ์ ์ํด ์ฌ์ฉ์ ์ ์ ํจ์ ๋ง๋ค๊ธฐ
scorer = make_scorer(f1_score, greater_is_better=True, average = 'macro')
# ํ์ต์ ์ํ label(target) ๊ฐ
train_labels = np.array(list(final[final['Target'].notnull()]['Target'].astype(np.uint8)))
# train/ test set ์ค๋น
train_set = final[final['Target'].notnull()].drop(columns = ['Id', 'idhogar', 'Target'])
test_set = final[final['Target'].isnull()].drop(columns = ['Id', 'idhogar', 'Target'])
# ์ ์ถ์ฉ ์์ ๋ง๋ค๊ธฐ
submission_base = test[['Id', 'idhogar']].copy()
4-1. Pipelining
-
์ฌ๋ฌ ๋ชจํ์ ๋น๊ตํ๊ธฐ ์ํด feature๋ค ๊ฐ์ ์ค์ผ์ผ์ ์กฐ์
-
๊ฐ ์ปฌ๋ผ(๋ณ์)์ ๋ฒ์๋ฅผ
0๊ณผ 1 ์ฌ์ด
๋ก ์ ํ -
๋ง์ ์์๋ธ ๋ชจ๋ธ์ ๊ฒฝ์ฐ ๋ถํ์ํ์ง๋ง, KNearest Neighbors ๋๋ Support Vector Machine๊ณผ ๊ฐ์ด ๊ฑฐ๋ฆฌ ๋ฉํธ๋ฆญ์ ์์กดํ๋ ๋ชจ๋ธ์ ์ฌ์ฉํ ๊ฒฝ์ฐ
feature scaling
์ด์ ๋์ ์ผ๋ก ํ์ -
๊ฒฐ์ธก์น์ ๊ฒฝ์ฐ feature์ ์ค์๊ฐ์ผ๋ก ๋์ฒด
-
-
๊ฒฐ์ธก์น๋ฅผ ์ฒ๋ฆฌํ๊ณ feature๋ค์ ํ ๋ฒ์ scaling ํ๊ธฐ ์ํด
Pipeline
์ ๋ง๋ค ์ ์์- train ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ธ์ ์ ํฉํ๊ณ train ๋ฐ test ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๋ ๋ฐ ์ฌ์ฉ
features = list(train_set.columns)
pipeline = Pipeline([('imputer', SimpleImputer(strategy = 'median')),
('scaler', MinMaxScaler())])
# ๋ฐ์ดํธ๋ฅผ ์๋ง๊ฒ ๋ณํ(์ ์ฒ๋ฆฌ)
train_set = pipeline.fit_transform(train_set)
test_set = pipeline.transform(test_set)
-
๋ฐ์ดํฐ์๋ ๊ฒฐ์ธก๊ฐ์ด ์์ผ๋ฉฐ, 0๊ณผ 1 ์ฌ์ด ๋ฒ์๋ก scaling ๋จ
- scikit-Learn ๋ชจ๋ธ์์ ์ง์ ์ฌ์ฉํ ์ ์์
### ๋ชจ๋ธ ํ์ต
model = RandomForestClassifier(n_estimators = 100, random_state = 10, n_jobs = -1)
# 10 fold cross validation
cv_score = cross_val_score(model, train_set, train_labels, cv = 10, scoring = scorer)
print(f'10 Fold Cross Validation F1 Score = {round(cv_score.mean(), 4)} with std = {round(cv_score.std(), 4)}')
- ํ์ฌ๋ ์ฑ๋ฅ์ด ๊ทธ๋ค์ง ์ข์ง๋ ์์
4-2. ํผ์ณ ์ค์๋ ํ์ธ
-
ํธ๋ฆฌ ๊ธฐ๋ฐ ๋ชจ๋ธ์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ธ์ ๊ธฐ๋ฅ ์ ์ฉ์ฑ์ ๋ํ ์๋์ ์์๋ฅผ ๋ณด์ฌ์ฃผ๋
๊ธฐ๋ฅ ์ค์๋(feature importances)
๋ฅผ ์ดํด๋ณผ ์ ์์-
๋ถํ ์ ์ํด ๋ณ์๋ฅผ ์ฌ์ฉํ ๋ ธ๋์ ๋ถ์๋ฌผ ๊ฐ์์ ํฉ์ ์๋ฏธ
-
์๋ ์ ์์ ์ด์
-
-
feature importances
๋ฅผ ๋ณด๊ธฐ ์ํด์ ์ ์ฒด train ๋ฐ์ดํฐ์ ๋ํด ๋ชจ๋ธ์ train์์ผ์ผ ํจ -
๊ต์ฐจ ๊ฒ์ฆ์ ๊ฒฝ์ฐ feature importance๋ฅผ ๋ฐํํ์ง x
model.fit(train_set, train_labels) # ์ ์ฒด ๋ฐ์ดํฐ์ ๋ํด ํ์ต
# Feature importances ํ์ธ
feature_importances = pd.DataFrame({'feature': features, 'importance': model.feature_importances_})
feature_importances.head()
๐ ๊ธฐ๋ฅ ์ค์๋ ์๊ฐํ ํจ์
-
์ค์ํ ์์๋๋ก n๊ฐ์ ํผ์ณ ์๊ฐํ
-
์๊ณ๊ฐ(threshold)์ด ์ง์ ๋ ๊ฒฝ์ฐ ๋์ ์ค์๋๋ฅผ ํ์ํ๊ณ , ๋์ ์ค์๋๊ฐ ์๊ณ๊ฐ์ ๋๋ฌํ๋ ๋ฐ ํ์ํ ํผ์ณ ์๋ฅผ print
-
ํธ๋ฆฌ ๊ธฐ๋ฐ ๊ธฐ๋ฅ ์ค์๋์ ํจ๊ป ์ฌ์ฉํ๋๋ก ์ค๊ณ๋จ
-
Arguments>
-
df(dataframe)
-
ํผ์ฒ ์ค์๋์ ๋ฐ์ดํฐ ํ๋ ์
-
์ด์ ๊ธฐ๋ฅ ๋ฐ ์ค์๋์ฌ์ผ ํจ
-
-
n(int)
-
์ค์๋ ์์ผ๋ก ํ์ํ ํผ์ณ ์
-
default = 15
-
-
threshold(float)
-
๋์ ์ค์๋ plot์ ์๊ณ๊ฐ
-
์๊ณ๊ฐ์ด ์ ๊ณต๋์ง ์์ผ๋ฉด plot์ด ์์ฑ๋์ง x
-
default: None
-
-
-
Returns>
-
df(dataframe)
- ์ ๊ทํ๋ ์ปฌ๋ผ(ํฉ๊ณ = 1)๊ณผ ๋์ ์ค์๋ ์ปฌ๋ผ์ ์ฌ์ฉํ์ฌ ํผ์ณ ์ค์๋ ์์ผ๋ก ์ ๋ ฌ๋ ๋ฐ์ดํฐ ํ๋ ์
-
(Note)
-
์ด ๊ฒฝ์ฐ ์ ๊ทํ๋ ํฉ์ด 1์ด๋ผ๋ ๊ฒ์ ์๋ฏธ
-
๋์ ์ค์๋๋ ๊ฐ์ฅ ์ค์ํ์ง ์์ feature๋ถํฐ ๊ฐ์ฅ ์ค์ํ์ง ์์ feature๋ฅผ ํฉ์ฐํ์ฌ ๊ณ์ฐ
-
threshold = 0.9
: ๋์ ์ค์๋์ 90%์ ๋๋ฌํ๋ ๋ฐ ํ์ํ ๊ฐ์ฅ ์ค์ํ feature๋ฅผ ํ์
def plot_feature_importances(df, n = 10, threshold = None):
plt.style.use('fivethirtyeight')
# ๊ฐ์ฅ ์ค์ํ ๊ธฐ๋ฅ ๊ธฐ์ค ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ
df = df.sort_values('importance', ascending = False).reset_index(drop = True)
# ํผ์ณ ์ค์๋๋ฅผ ์ ๊ทํ(0 ~ 1 ์ฌ์ด)ํ์ฌ ๋์ ์ค์๋ ๊ณ์ฐ
df['importance_normalized'] = df['importance'] / df['importance'].sum()
df['cumulative_importance'] = np.cumsum(df['importance_normalized'])
plt.rcParams['font.size'] = 12
# ์ค์ํ ์์๋๋ก n๊ฐ feature์ ๋ํ barhplot
df.loc[:n, :].plot.barh(y = 'importance_normalized',
x = 'feature', color = 'darkgreen',
edgecolor = 'k', figsize = (12, 8),
legend = False, linewidth = 2)
plt.xlabel('Normalized Importance', size = 18); plt.ylabel('');
plt.title(f'{n} Most Important Features', size = 18)
plt.gca().invert_yaxis()
### ------------------------------------------------------------------------
# ์๊ณ๊ฐ์ ๋ค๋ค๋๋ค๋ฉด
if threshold:
# ๋์ ์ค์๋ plot
plt.figure(figsize = (8, 6))
plt.plot(list(range(len(df))), df['cumulative_importance'], 'b-')
plt.xlabel('Number of Features', size = 16); plt.ylabel('Cumulative Importance', size = 16)
plt.title('Cumulative Feature Importance', size = 18)
# ๋์ ์ค์๋์ ๋๋ฌํ๊ธฐ ์ํ feature ์
# ์ธ๋ฑ์ค(-> ์ค์ ์ซ์์ ๋ํด 1์ ์ถ๊ฐํด์ผ ํจ)
importance_index = np.min(np.where(df['cumulative_importance'] > threshold))
# ์์ง ์ ์ถ๊ฐ
plt.vlines(importance_index + 1, ymin = 0, ymax = 1.05, linestyles = '--', colors = 'red')
plt.show()
print('{} features required for {:.0f}% of cumulative importance.'.format(importance_index + 1,
100 * threshold))
return df
norm_fi = plot_feature_importances(feature_importances, threshold=0.95)
-
๊ฐ์ฅ ์ค์ํ ๋ณ์๋
meaneduc(๊ฐ๊ตฌ ๋ด ํ๊ท ๊ต์ก๋)
์ด๊ณ , ๋ค์์ดage-max(๊ฐ๊ตฌ ๋ด ํ ๊ฐ์ธ์ ์ต๋ ๊ต์ก๋)
์-
์ด ๋ ๋ณ์๋ ์๊ด์ฑ์ด ๋์ ๋ณ์๋ค์
-
๋ฐ๋ผ์, ๋ฐ์ดํฐ์์ ๋ณ์ ์ค ํ๋๋ฅผ ์ ๊ฑฐํด์ผ ํ๋ค๋ ๊ฒ์ ์๋ฏธ
-
-
๋ค๋ฅธ ์ค์ํ feature๋ค์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ๋ณ์์ ๋ฐ์ดํฐ์ ์ด๋ฏธ ์กด์ฌํ๋ ๋ณ์๋ค๊ณผ์ ์กฐํฉ์ผ๋ก ์์ฑ๋ ๋ณ์๋ค์
-
90%์ ์ค์๋๋ฅผ ์ํด์๋ ๋๋ต 180๊ฐ ์ ๋์ feature๋ค๋ง ์กด์ฌํด๋ ok
- ์ผ๋ถ feature๋ค์ ์ ๊ฑฐํด๋ ๋ฌด๋ฐฉํจ
-
ํผ์ฒ ์ค์๋์ ํผ์ฒ๊ฐ ์ด๋ ๋ฐฉํฅ์ผ๋ก ์ค์ํ์ง๋ฅผ ์๋ ค์ฃผ์ง๋ ์์
-
์๋ฅผ ๋ค์ด, ๊ต์ก์ ๋ง์ด ๋ฐ์์๋ก ๋ ์ฌ๊ฐํ ๋น๊ณค์ผ๋ก ์ด์ด์ง๋์ง๋ฅผ ์๋ ค์ฃผ์ง๋ ๋ชปํจ
-
๊ด๋ จ์ด ์์ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋๋ ๋ชจ๋ธ๋ง ์๋ ค์ค
-
### ์ปค๋ ๋ฐ๋ ํจ์ ์๊ฐํ
# "variable" ๋ณ๋ก "target" ๊ฐ์ ๋ถํฌ๋ฅผ ํ์
def kde_target(df, variable):
colors = {1: 'red', 2: 'orange', 3: 'blue', 4: 'green'}
plt.figure(figsize = (12, 8))
df = df[df['Target'].notnull()]
for level in df['Target'].unique():
subset = df[df['Target'] == level].copy()
sns.kdeplot(subset[variable].dropna(),
label = f'Poverty Level: {level}',
color = colors[int(subset['Target'].unique())])
plt.xlabel(variable); plt.ylabel('Density');
plt.title('{} Distribution'.format(variable.capitalize()));
kde_target(final, 'meaneduc')
kde_target(final, 'escolari/age-range_')
4-2. ๋ชจ๋ธ ์ ํ
-
์ด๋ฏธ RandomForestClassifier๋ ์๋
- Macro F1-score: 0.35
-
๊ธฐ๊ณ ํ์ต์์๋ ์ด๋ค ๋ชจ๋ธ์ด ์ฃผ์ด์ง ๋ฐ์ดํฐ ์ธํธ์ ๊ฐ์ฅ ์ ์๋ํ๋์ง ๋ฏธ๋ฆฌ ์ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์
-
๊ฐ ์ํฉ๋ง๋ค ๋ค๋ฆ..
-
์ด๋ค ๊ฒ์ด ์ต์ ์ธ์ง ํ์ธํ๊ธฐ ์ํด์๋ ์ฌ๋ฌ ๊ฐ์ง ๋ชจ๋ธ์ ์๋ํด ๋ณด์์ผ ํจ
-
# Model imports
from sklearn.svm import LinearSVC
from sklearn.naive_bayes import GaussianNB
from sklearn.neural_network import MLPClassifier
from sklearn.linear_model import LogisticRegressionCV, RidgeClassifierCV
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import ExtraTreesClassifier
import warnings
from sklearn.exceptions import ConvergenceWarning
# Filter out warnings from models
warnings.filterwarnings('ignore', category = ConvergenceWarning)
warnings.filterwarnings('ignore', category = DeprecationWarning)
warnings.filterwarnings('ignore', category = UserWarning)
# ๊ฒฐ๊ณผ ์ ์ฅ์ ์ํ data frame
model_results = pd.DataFrame(columns = ['model', 'cv_mean', 'cv_std'])
๐ ๋ชจ๋ธ ํ๊ฐ๋ฅผ ์ํ ํจ์
-
RandomForestClassifier
์ธ์ 8๊ฐ์ ๋ค๋ฅธ Scikit - Learn ๋ชจ๋ธ ์ฌ์ฉ -
๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ๋ฐ์ดํฐ ํ๋ ์์ ๋ง๋ค๊ณ , ํจ์๋ ๊ฐ ๋ชจ๋ธ์ ๋ฐ์ดํฐ ํ๋ ์์ ํ์ ์ถ๊ฐํ๋ ์์ ์ ์ํ
-
๊ฐ ๋ชจ๋ธ์ ๋ํด 10-fold ๊ต์ฐจ ๊ฒ์ฆ ์ํ
def cv_model(train, train_labels, model, name, model_results = None):
cv_scores = cross_val_score(model, train, train_labels, cv = 10, scoring=scorer, n_jobs = -1)
print(f'10 Fold CV Score: {round(cv_scores.mean(), 5)} with std: {round(cv_scores.std(), 5)}')
if model_results is not None:
# ๊ฒฐ๊ณผ ์ ์ฅ
model_results = model_results.append(pd.DataFrame({'model': name,
'cv_mean': cv_scores.mean(),
'cv_std': cv_scores.std()},
index = [0]),ignore_index = True)
return model_results
### 1. Linear SVC
model_results = cv_model(train_set, train_labels,
LinearSVC(), 'LSVC', model_results)
-
์ฑ๋ฅ์ด ๊ทธ๋ฅ ์ข์ง ์์
- ๋ชฉ๋ก์์ ์ญ์ ํ ์ ์๋ ๋ชจ๋ธ ์ค ํ๋
### 2. Gaussian Naive Bayes
model_results = cv_model(train_set, train_labels,
GaussianNB(), 'GNB', model_results)
- ๋งค์ฐ ๋์ ์ฑ๋ฅ..
### 3. Multi-Layer Perceptron
model_results = cv_model(train_set, train_labels,
MLPClassifier(hidden_layer_sizes=(32, 64, 128, 64, 32)),
'MLP', model_results)
-
๊ด์ฐฎ์ ์ฑ๋ฅ์ ๋ณด์ด๊ณ ์์
-
ํ์ดํผํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋คํธ์ํฌ๋ฅผ ์กฐ์ ํ ์ ์๋ ๊ฒฝ์ฐ ํด๋น ๋ชจ๋ธ์ ์ฌ์ฉํ ์ ์์
-
ํ์ง๋ง ์ ํ๋ ์์ ๋ฐ์ดํฐ๋ ์ผ๋ฐ์ ์ผ๋ก ํจ๊ณผ์ ์ธ ํ์ต์ ์ํด์ ์์ญ๋ง ๊ฐ์ ์์ ๋ฅผ ํ์๋ก ํ๊ธฐ ๋๋ฌธ์ ์ ๊ฒฝ๋ง์ ๋ฌธ์ ๊ฐ ๋ ์ ์์
-
### 4. LinearDiscriminantAnalysis
model_results = cv_model(train_set, train_labels,
LinearDiscriminantAnalysis(),
'LDA', model_results)
-
UserWarning์ filteringํ์ง ์๊ณ LDA๋ฅผ ์งํ ์ ์๋ฌ ๋ฐ์
Variables are collinear.
: ๊ณต์ ์ฑ ๋ฌธ์
-
์ ํ ๋ณ์๋ฅผ ์ ๊ฑฐํ ํ ํด๋น ๋ชจ๋ธ์ ๋ค์ ์๋ํด ๋ณผ ์ ์์
### 5. Ridge
model_results = cv_model(train_set, train_labels,
RidgeClassifierCV(), 'RIDGE', model_results)
-
์ ํ ๋ชจํ(ridge ๋ชจ๋ธ ํฌํจ)์ ๋๋ผ์ธ ์ ๋๋ก ์ ์๋ํจ
- ๋จ์ํ ๋ชจ๋ธ์ด ์ด ๋ฌธ์ ์์๋ ๋ ๋์์ด ๋ ์๋ ์์์ ์๋ฏธ
### 6. K-Neighbors
for n in [5, 10, 20]:
print(f'\nKNN with {n} neighbors\n')
model_results = cv_model(train_set, train_labels,
KNeighborsClassifier(n_neighbors = n),
f'knn-{n}', model_results)
### 7. ExtraTreeClassifier
model_results = cv_model(train_set, train_labels,
ExtraTreesClassifier(n_estimators = 100, random_state = 10),
'EXT', model_results)
4-3. ๋ชจ๋ธ ์ฑ๋ฅ ๋น๊ต
- ๋ชจ๋ธ๋ง ๊ฒฐ๊ณผ๊ฐ ์ ์ฅ๋ df๋ฅผ ํ์ฉํด ์ด๋ค ๋ชจ๋ธ์ด ๊ฐ์ฅ ํจ๊ณผ์ ์ธ์ง ์๊ฐํํ๋ ๊ทธ๋ํ๋ฅผ ๊ทธ๋ฆด ์ ์์
# ์ฒ์์ผ๋ก ์ํํ RandomForestClassifier์ ๊ฒฐ๊ณผ๋ ์ ์ฅํด์ฃผ๊ธฐ
model_results = cv_model(train_set, train_labels,
RandomForestClassifier(100, random_state=10),
'RF', model_results)
### ๋ชจ๋ธ๋ง ๊ฒฐ๊ณผ ์๊ฐํ
model_results.set_index('model', inplace = True)
model_results['cv_mean'].plot.bar(color = 'orange', figsize = (8, 6),
yerr = list(model_results['cv_std']),
edgecolor = 'k', linewidth = 2)
plt.title('Model F1 Score Results')
plt.ylabel('Mean F1 Score (with error bar)')
model_results.reset_index(inplace = True)
-
RandomForestClassifier
๋ ๊ฐ์ฅ ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ ์ ์๊ธฐ์, ๊ฐ์ฅ ๋จผ์ ์๋ํด ๋ณผ ์ ์๋ ๋ชจํ์ -
์์ง baseline model๋ค์ ๊ฒฝ์ฐ ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐ์ ํ์ง ์์ ๋ชจ๋ธ ๊ฐ ๋น๊ต๊ฐ ์๋ฒฝํ์ง๋ ์์ง๋ง, ํธ๋ฆฌ ๊ธฐ๋ฐ ์์๋ธ ๋ฐฉ๋ฒ(
Gradient Boosting Machine
ํฌํจ)์ด ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ ์ธํธ์์ ๋งค์ฐ ์ ์ํ๋๋ค๋ ๋ค๋ฅธ ๋ง์ Kaggle competition์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ํ๊ณ ์์
ํ์ดํผ ํ๋ผ๋ฏธํฐ ์กฐ์ ํจ๊ณผ
-
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ ํ๋ ํฅ์์ 10% ๋ฏธ๋ง
- ์ต์ ์ ๋ชจ๋ธ์ ํ๋์ ํตํด ๊ฐ์๊ธฐ ์ต๊ณ ์ ๋ชจ๋ธ์ด ๋์ง๋ ์์ ๊ฒ์
-
์ผ๋จ์ ๊ทธ๋ฅ RandomForestClassifier๋ก ์์ธก ์ํ
4-4. ์ ์ถ ํ์ผ ์์ฑ
-
์ ์ถํ๊ธฐ ์ํด์๋ test ๋ฐ์ดํฐ๊ฐ ํ์ํจ
- ํ์ฌ test data๊ฐ train data์ ๊ฐ์ ๋ฐฉ์์ผ๋ก format ๋์ด ์์
-
๊ฐ๊ตฌ๋ณ๋ก ์์ธก์ ํ๊ณ ์์ง๋ง ์ค์ ๋ก๋ ๊ฐ์ธ๋น ํ ์ค(Id๋ก ์๋ณ)๋ง ํ์
- ๊ฐ์ฅ(household)์ ๋ํ ์์ธก๋ง ์ ์๊ฐ ๋งค๊ฒจ์ง
-
ํ ์คํธ ์ ์ถ ํ์
Id,Target
ID_2f6873615,1
ID_1c78846d2,2
ID_e5442cf6a,3
ID_a8db26a79,4
ID_a62966799,4
-
submission_base
๋ ๊ฐ ๊ฐ์ธ์ ๋ํ ์์ธก์ด ์์ด์ผ ํจsubmission_base
๋ ๋ชจ๋ ๊ฐ์ธ์ test set์ ํฌํจ
-
test_ids
: ๊ฐ์ฅ์idhogar
๋ง ํฌํจ -
์์ธก ์์๋ ๊ฐ ๊ฐ๊ตฌ์ ๋ํด์๋ง ์์ธกํ ๋ค์ ์์ธก ๋ฐ์ดํฐ ํ๋ ์์ ๊ฐ๊ตฌ ID(
idhogar
)์ ๋ชจ๋ ๊ฐ์ธ๊ณผ ๋ณํฉ-
target
์ด ๊ฐ๊ตฌ์ ๋ชจ๋์๊ฒ ๋์ผํ ๊ฐ์ผ๋ก ์ค์ ๋จ -
๊ฐ์ฅ์ด ์๋ ๊ฐ๊ตฌ์ ๊ฒฝ์ฐ ์ ์๊ฐ ๋งค๊ฒจ์ง์ง ์์ผ๋ฏ๋ก ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ์์ธก์น๋ฅผ 4(non-vulnerable)๋ก ์ค์
-
test_ids = list(final.loc[final['Target'].isnull(), 'idhogar'])
๐ ์์ธก์ ์ํ ํจ์
-
๋ชจ๋ธ, train ์ธํธ, train label ๋ฐ test ์ธํธ๋ฅผ ๊ฐ์ ธ์ ๋ค์ ์์ ๋ค์ ์ํ
-
fit()
์ ํ์ฉํ์ฌ train ๋ฐ์ดํฐ์ ๋ํด ๋ชจ๋ธ์ ํ์ต -
predict()
๋ฅผ ํ์ฉํ์ฌ test ๋ฐ์ดํฐ๋ก ์์ธก -
์ด๋ฅผ ์ ์ฅํ์ฌ ์ ์ถ ํ์ผ๋ก ๋ง๋ค ์ ์๋๋ก submission ๋ฐ์ดํฐ ํ๋ ์ ์์ฑ
-
def submit(model, train, train_labels, test, test_ids):
model.fit(train, train_labels) # ํ์ต
predictions = model.predict(test) # ์์ธก
predictions = pd.DataFrame({'idhogar': test_ids,
'Target': predictions})
# ์ ์ถ์ฉ df ๋ง๋ค๊ธฐ
submission = submission_base.merge(predictions,
on = 'idhogar',
how = 'left').drop(columns = ['idhogar'])
# ๊ฐ์ฅ x -> 4๋ก ์ฑ์ฐ๊ธฐ
submission['Target'] = submission['Target'].fillna(4).astype(np.int8)
return submission
### RandomForest๋ก ์์ธก
rf_submission = submit(RandomForestClassifier(n_estimators = 100,
random_state=10, n_jobs = -1),
train_set, train_labels, test_set, test_ids)
rf_submission.to_csv('rf_submission.csv', index = False)
- ์์ธก ์ฑ๋ฅ: 0.370
4-5. ๋ณ์ ์ ํ
-
๋ชจ๋ธ ์ฑ๋ฅ์ ํฅ์์ํค๋ ํ ๊ฐ์ง ๋ฐฉ๋ฒ
- ๋ชจ๋ธ์ ๊ฐ์ฅ ์ ์ฉํ ๊ธฐ๋ฅ๋ง ์ ์งํ๋ ค๊ณ ํ๋ ํ๋ก์ธ์ค
-
ํด๋น ๋ ธํธ๋ถ์์๋ feature๋ฅผ ์ ํํ๋ ๊ฒฝ์ฐ ๋จผ์ ์๊ด ๊ด๊ณ๊ฐ 0.95๋ณด๋ค ํฐ ์ด์ ์ ๊ฑฐํ ๋ค์, scikit-learn ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ์ฌ ์ค๋ณต์ ์ธ feature ์ ๊ฑฐ๋ฅผ ์ ์ฉ
a) ์๊ด๋๊ฐ ๋์ ๋ณ์ ์ ๊ฑฐ
- ์๊ด๊ณ์๊ฐ 0.95 ์ด์์ธ ๋ณ์๋ค์ ์ ๊ฑฐ
### ์๊ด๊ณ์๊ฐ 0.95 ์ด์์ธ ์ปฌ๋ผ ํ์ธ
train_set = pd.DataFrame(train_set, columns = features)
# ์๊ด๊ณ์ ํ๋ ฌ ์์ฑ
corr_matrix = train_set.corr()
# ์์ผ๊ฐํ๋ ฌ๋ง ์ ํ
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))
# ์๊ด๊ณ์๊ฐ 0.95 ์ด์์ธ ์ปฌ๋ผ๋ง ์ ํ
to_drop = [column for column in upper.columns if any(abs(upper[column]) > 0.95)]
to_drop
# ํด๋น ์ปฌ๋ผ drop
train_set = train_set.drop(columns = to_drop)
train_set.shape
# test data์์๋ ํด๋น feature๋ค์ ์ ๊ฑฐ
test_set = pd.DataFrame(test_set, columns = features)
train_set, test_set = train_set.align(test_set, axis = 1, join = 'inner')
features = list(train_set.columns)
b) RandomForest๋ฅผ ํ์ฉํ์ฌ ์ค๋ณต ๋ณ์ ์ ๊ฑฐ
-
sklearn.RFECV
-
๊ต์ฐจ ๊ฒ์ฆ์ ํตํ ์ค๋ณต์ ์ธ feature ์ ๊ฑฐ๋ฅผ ์๋ฏธ
-
๋ฐ๋ณต์ ์ธ ๋ฐฉ์์ผ๋ก ํผ์ฒ ์ค์๋๊ฐ ์๋ ๋ชจ๋ธ์ ์ฌ์ฉ
-
๊ฐ ๋ฐ๋ณต๋ง๋ค ํผ์ฒ์ ์ผ๋ถ ๋๋ ์ค์ ๋ ๊ฐ์์ ํผ์ฒ๋ฅผ ์ ๊ฑฐ
-
๊ต์ฐจ ๊ฒ์ฆ ์ ์๊ฐ ๋ ์ด์ ํฅ์๋์ง ์์ ๋๊น์ง ์์ ์ ๊ณ์ ๋ฐ๋ณตํจ
-
-
selector ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๋ชจ๋ธ, ๊ฐ ๋ฐ๋ณต๋ง๋ค ์ ๊ฑฐํ feature์ ์, ๊ต์ฐจ ๊ฒ์ฆ ์์ fold ์, ์ฌ์ฉ์ ์ง์ ์ ์ ๊ณ์ฐ๊ธฐ ๋ฐ ์ ํ์ ์๋ดํ๋ ๊ธฐํ parameter๋ค์ ์ค์
from sklearn.feature_selection import RFECV
# ๋ณ์ ์ ํ์ ์ํ ๋ชจ๋ธ ๊ฐ์ฒด ์์ฑ
estimator = RandomForestClassifier(random_state = 10, n_estimators = 100, n_jobs = -1)
# selector ๊ฐ์ฒด ์์ฑ
selector = RFECV(estimator, step = 1, cv = 3, scoring = scorer, n_jobs = -1)
### ํ์ต
selector.fit(train_set, train_labels)
### ๊ฒฐ๊ณผ ์๊ฐํ
plt.plot(selector.cv_results_.keys())
plt.xlabel('Number of Features'); plt.ylabel('Macro F1 Score'); plt.title('Feature Selection Scores');
selector.n_features_
-
์ต๋ 96๊ฐ์ ๋ณ์๋ฅผ ์ถ๊ฐํ๋ฉด ์ ์๊ฐ ํฅ์๋๋ค๋ ๊ฒ์ ํ์ธํ ์ ์์
- selector์ ๋ฐ๋ฅด๋ฉด ์ด๊ฒ์ด ์ต์ ์ feature ๊ฐ์์
-
๊ฐ feature์ ์์๋ ํ๋ จ๋ selector ๊ฐ์ฒด๋ฅผ ํตํด ํ์ธํ ์ ์์
-
์ฌ๋ฌ ๋ฒ์ ๋ฐ๋ณต์ ๊ฑธ์ฒ ํ๊ท ํ๋ ๊ธฐ๋ฅ ์ค์๋๋ฅผ ํ์
-
์์๊ฐ ๋์ผํ ์ ์์ผ๋ฉฐ, ์์๊ฐ 1์ธ feature๋ง ์ ์ง๋จ
-
rankings = pd.DataFrame({'feature': list(train_set.columns), 'rank': list(selector.ranking_)}).sort_values('rank')
rankings.head(10)
์ต์ข ๋ณ์ ์ ํ & ๊ต์ฐจ ๊ฒ์ฆ ์ํ
train_selected = selector.transform(train_set)
test_selected = selector.transform(test_set)
# df๋ก ์ฌ๊ฐ๊ณต
selected_features = train_set.columns[np.where(selector.ranking_==1)]
train_selected = pd.DataFrame(train_selected, columns = selected_features)
test_selected = pd.DataFrame(test_selected, columns = selected_features)
model_results = cv_model(train_selected, train_labels, model, 'RF-SEL', model_results)
# ๊ฒฐ๊ณผ ์๊ฐํ
model_results.set_index('model', inplace = True)
model_results['cv_mean'].plot.bar(color = 'orange', figsize = (8, 6),
yerr = list(model_results['cv_std']),
edgecolor = 'k', linewidth = 2)
plt.title('Model F1 Score Results');
plt.ylabel('Mean F1 Score (with error bar)');
model_results.reset_index(inplace = True)
- feature selection ํ ๋ชจ๋ธ์ด ๊ต์ฐจ ๊ฒ์ฆ์์ ์ฝ๊ฐ ๋ ์ฐ์ํ ์ฑ๋ฅ์ ๋ณด์
5. ๋ชจ๋ธ ์ ๋ฐ์ดํธ
5-1. Light Gradient Boosting Machine
-
Kaggle ๋ํ์์ ์ฃผ๋ก ๋ฐ์ดํฐ๊ธฐ ๊ตฌ์กฐํ๋์ด ์๊ณ (ํ ์ด๋ธ ํํ), ๋ฐ์ดํฐ ์ ์ด ๊ทธ๋ฆฌ ํฌ์ง ์์ ๊ฒฝ์ฐ(๊ด์ธก์น๊ฐ ๋ฐฑ๋ง ๊ฐ ๋ฏธ๋ง)
GBM(Gradient Boosting Machine)
์ด ๊ฒฝ์์์ ๋์ ๋น์จ๋ก ์น๋ฆฌํจ -
Gradient Boosting Machine์ ์ํ ํ์ดํผ ํ๋ผ๋ฏธํฐ ์ต์ ํ๋ ์ฃผ๋ก ๋ชจ๋ธ ์ต์ ํ๋ฅผ ํตํด ์ํ๋จ
- ์ด์ ์ ์ ์๋ํ์๋ ๊ฐ๋ค์ ๊ธฐ์ค์ผ๋ก ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ์ค์ ํจ
-
n_estimators
๋ฅผ ์ผ๋จ 10000์ผ๋ก ์ค์ ํ์์ง๋ง, ํด๋น ์ซ์์ ๋๋ฌํ์ง๋ ๋ชปํจ-
์ฐ๋ฆฌ๋
early_stopping_rounds
๋ฅผ ์ค์ ํจ-
๊ต์ฐจ ๊ฒ์ฆ metric์ด ๊ฐ์ ๋์ง ์์ ๋ train estimator๋ฅผ ์ข ๋ฃ์ํด
-
display
๋%%capture
์ ๊ฒฐํฉํ์ฌ train ์ค ์ฌ์ฉ์ ์ง์ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์ฌ์ฉ๋จ
-
-
๐ ์กฐ๊ธฐ ์ข ๋ฃ(Early Stopping)๋ฅผ ํตํ estimator์ ๊ฐ์ ์ ํ๊ธฐ
-
estimator์ ์(
n_estimators
๋๋num_boost_rounds
๋ผ๊ณ ํ๋ ์์๋ธ์ ์์ฌ ๊ฒฐ์ ํธ๋ฆฌ ์)๋ฅผ ์ ํํ๊ธฐ ์ํด 5-fold ๊ต์ฐจ ๊ฒ์ฆ์ ํ์ฉํ์ฌ ์กฐ๊ธฐ ์ค์ง ์ํ-
Macro F1-score๋ก ์ธก์ ํ ์ฑ๋ฅ์ด 100ํ์ train ๋ผ์ด๋ ๋์ ์ฆ๊ฐํ์ง ์์ ๋๊น์ง ์ถ์ ์น๋ฅผ ๊ณ์ ์ถ๊ฐํ ์ ์์
-
ํด๋น metric์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ฌ์ฉ์ ์ง์ metric์ ์ ์ํด์ผ ํจ
-
def macro_f1_score(labels, predictions):
predictions = predictions.reshape(len(np.unique(labels)), -1).argmax(axis = 0)
metric_value = f1_score(labels, predictions, average = 'macro')
return 'macro_f1', metric_value, True
๐ Stratified K-Fold๋ฅผ ์ํ ํจ์
-
Stratified K-fold ๊ต์ฐจ ๊ฒ์ฆ ๋ฐ ์กฐ๊ธฐ ์ ์ง๋ฅผ ํตํด ๊ทธ๋ ์ด๋์ธํธ ๋ถ์คํ ๋จธ์ ์ ๊ต์ก
-
๊ต์ก ๋ฐ์ดํฐ์ ๊ณผ์ ํฉ๋๋ ๊ฒ์ ๋ฐฉ์ง
-
๊ต์ฐจ ๊ฒ์ฆ์ ํตํด ํ์ต์ ์ํํ๊ณ ๊ฐ fold์ ๋ํ ํ๋ฅ ๋ก ์์ธก์ ๊ธฐ๋ก
-
๊ฐ fold์ ์์ธก๊ฐ์ ๋ฐํํ ๋ค์ ์ ์ถ๋ฌผ์ ๋ฐํํ์ฌ ๊ฒฐ๊ณผ ํ์ธ
from sklearn.model_selection import StratifiedKFold
import lightgbm as lgb
from IPython.display import display
def model_gbm(features, labels, test_features, test_ids,
nfolds = 5, return_preds = False, hyp = None):
feature_names = list(features.columns) # ๋ณ์๋ค์ ์ ์ฅ
### ์ฌ์ฉ์ ์ง์ hyper parameter์ ๋ํ ์ต์
# ์ฌ์ฉ์ ์ง์ hyper parameter๊ฐ ์๋ ๊ฒฝ์ฐ
if hyp is not None:
# early sropping์ ์ฌ์ฉํ๋ฏ๋ก estimator ์๊ฐ ํ์ํ์ง ์์
if 'n_estimators' in hyp:
del hyp['n_estimators']
params = hyp
else:
# ๊ธฐ๋ณธ ํ์ดํผ ํ๋ผ๋ฏธํฐ ์ค์
params = {'boosting_type': 'dart',
'colsample_bytree': 0.88,
'learning_rate': 0.028,
'min_child_samples': 10,
'num_leaves': 36, 'reg_alpha': 0.76,
'reg_lambda': 0.43,
'subsample_for_bin': 40000,
'subsample': 0.54,
'class_weight': 'balanced'}
# ๋ชจ๋ธ ๊ฐ์ฒด ์์ฑ
model = lgb.LGBMClassifier(**params, objective = 'multiclass',
n_jobs = -1, n_estimators = 10000,
random_state = 10)
# Stratified k-Fold ๊ต์ฐจ ๊ฒ์ฆ
strkfold = StratifiedKFold(n_splits = nfolds, shuffle = True)
# ๊ฐ fold๋ง๋ค ์์ธกํ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅ
predictions = pd.DataFrame()
importances = np.zeros(len(feature_names))
# ์ธ๋ฑ์ฑ์ ์ํด array๋ก ๋ณํ
features = np.array(features)
test_features = np.array(test_features)
labels = np.array(labels).reshape((-1 ))
valid_scores = [] # ๊ฒ์ฆ ์ ์
### ๊ฐ fold ๋ง๋ค
for i, (train_indices, valid_indices) in enumerate(strkfold.split(features, labels)):
# ๊ฐ fold๋ง๋ค ์์ธก ์ํ -> ๊ฒฐ๊ณผ ์ ์ฅ
fold_predictions = pd.DataFrame()
# train data / valid data
X_train = features[train_indices]
y_train = labels[train_indices]
X_valid = features[valid_indices]
y_valid = labels[valid_indices]
# ํ์ต(early stopping ์ ์ฉ)
model.fit(X_train, y_train, early_stopping_rounds = 100,
eval_metric = macro_f1_score,
eval_set = [(X_train, y_train), (X_valid, y_valid)],
eval_names = ['train', 'valid'],
verbose = 200)
# ๊ฒ์ฆ ์ ์ ์ ์ฅ
valid_scores.append(model.best_score_['valid']['macro_f1'])
# "ํ๋ฅ "์ ํตํ ์์ธก ์ํ
fold_probabilitites = model.predict_proba(test_features)
# ๊ฐ๋ณ ์ปฌ๋ผ์ผ๋ก ์์ธก๊ฐ ์ ์ฅ
for j in range(4):
fold_predictions[(j + 1)] = fold_probabilitites[:, j]
# ์์ธก์ ์ํด ํ์ํ ์ ๋ณด ์ถ๊ฐ
fold_predictions['idhogar'] = test_ids
fold_predictions['fold'] = (i+1)
# ์์ธก์ ๊ธฐ์กด ์์ธก์ ์ ํ์ผ๋ก ์ถ๊ฐ
predictions = predictions.append(fold_predictions)
# ๊ฐ fold ๋ณ ํผ์ฒ ์ค์๋
importances += model.feature_importances_ / nfolds
# fold์ ๋ํ ์ ๋ณด ํ์
display(f'Fold {i + 1}, Validation Score: {round(valid_scores[i], 5)}, Estimators Trained: {model.best_iteration_}')
# ํผ์ณ ์ค์๋๋ฅผ df๋ก ์ ์ฅ
feature_importances = pd.DataFrame({'feature': feature_names,
'importance': importances})
# ๊ฒ์ฆ ์ ์์ ๋ํ ์ ๋ณด ํ์
valid_scores = np.array(valid_scores)
display(f'{nfolds} cross validation score: {round(valid_scores.mean(), 5)} with std: {round(valid_scores.std(), 5)}.')
# ์์ธก์ด ํ๊ท ์ ์ด๊ณผํ์ง ์๋์ง ํ์ธํ๋ ค๋ฉด
if return_preds:
predictions['Target'] = predictions[[1, 2, 3, 4]].idxmax(axis = 1)
predictions['confidence'] = predictions[[1, 2, 3, 4]].max(axis = 1)
return predictions, feature_importances
# fold ๋ณ ์์ธก์ ํ๊ท
predictions = predictions.groupby('idhogar', as_index = False).mean()
# ํด๋์ค ๋ฐ ๊ด๋ จ ํ๋ฅ ์ฐพ๊ธฐ
predictions['Target'] = predictions[[1, 2, 3, 4]].idxmax(axis = 1)
predictions['confidence'] = predictions[[1, 2, 3, 4]].max(axis = 1)
predictions = predictions.drop(columns = ['fold'])
# ๊ฐ ๊ฐ์ฒด์ ๋ํด "ํ๋"์ ์์ธก๊ฐ์ ๊ฐ๋๋ก ๊ธฐ์กด์ ๊ฐ๊ณผ ๋ณํฉ
submission = submission_base.merge(predictions[['idhogar', 'Target']],
on = 'idhogar', how = 'left').drop(columns = ['idhogar'])
# ๊ฒฐ์ธก์น -> class = 4๋ก ์ฑ์ฐ๊ธฐ
# ์ ์ ๊ณ์ฐ์ด ๋์ง x
submission['Target'] = submission['Target'].fillna(4).astype(np.int8)
return submission, feature_importances, valid_scores
a) ์กฐ๊ธฐ ์ค์ง ๋ ธํธ๋ฅผ ์ฌ์ฉํ ๊ต์ฐจ ๊ฒ์ฆ
-
train ์ธํธ์์ ๊ณผ์ ํฉ์ ๋ฐฉ์งํ๋ ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ ์ค ํ๋
- ๊ฒ์ฆ ์ ์๊ฐ ๊ฐ์ ๋์ง ์๋ ๊ฒ์ด ๋ถ๋ช ํด์ง๋ฉด ๋ชจ๋ธ ๋ณต์ก์ฑ์ ๋๋ฆด ์ ์๊ธฐ ๋๋ฌธ
-
ํด๋น ๊ณผ์ ์ ์ฌ๋ฌ fold์์ ๋ฐ๋ณตํ๋ฉด ๋จ์ผ fold๋ฅผ ์ฌ์ฉํ ๋ ๋ฐ์๋ ์ ์๋ ํธํฅ(bias)์ ์ค์ด๋ ๋ฐ ๋์์ด ๋จ
-
๋ํ, ๋น ๋ฅธ ํ์ต ๊ฐ๋ฅ
-
Gradient Boosting Machine์์ eatimator์ ์๋ฅผ ์ ํํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ
%%capture --no-display
predictions, gbm_fi = model_gbm(train_set, train_labels, test_set, test_ids, return_preds=True)
- LGBM์ ํ์ฉํ์ฌ ๊ต์ฐจ ๊ฒ์ฆ์ ์ํํ ๊ฒฐ๊ณผ ์ฑ๋ฅ์ด ๋ง์ด ๋์์ง
### ์์ธก๊ฐ ํ์ธ
predictions.head()
-
๊ฐ fold์ ๋ํด 1, 2, 3, 4์ด์ ๊ฐ target์ ๋ํ
ํ๋ฅ
์ ๋ํ๋- target๋ก confidence๊ฐ ์ต๋์น์ธ ๊ฒ์ ์ ํ
-
5๊ฐ์ fold ๋ชจ๋์ ๋ํ ์์ธก์ ๊ฐ์ง๊ณ ์์
- ๋ค๋ฅธ fold์ ๋ํ ๊ฐ target์ ๋ํ ์ ๋ขฐ๋ ํ์ ๊ฐ๋ฅ
plt.rcParams['font.size'] = 18
### Kdeplot
g = sns.FacetGrid(predictions, row = 'fold', hue = 'Target', aspect = 4)
g.map(sns.kdeplot, 'confidence');
g.add_legend();
plt.suptitle('Distribution of Confidence by Fold and Target', y = 1.05);
-
๊ฐ ํด๋์ค์ ๋ํ ์ ๋ขฐ๋๊ฐ ์๋์ ์ผ๋ก ๋ฎ์
- ํด๋์ค ๋ถ๊ท ํ๊ณผ ๋์ ๋ณด๊ธ๋ฅ ๋ก ์ธํด
Target = 4
์ ๋ํ ์ ๋ขฐ๋๊ฐ ๋์ ๊ฒ์ผ๋ก ๋ณด์
- ํด๋์ค ๋ถ๊ท ํ๊ณผ ๋์ ๋ณด๊ธ๋ฅ ๋ก ์ธํด
### violinplot
plt.figure(figsize = (24, 12))
sns.violinplot(x = 'Target', y = 'confidence', hue = 'fold', data = predictions)
-
๋ถ๊ท ํ ํด๋์ค์์ ํ์ธํ ์ ์์
-
๋ชจ๋ธ์ด ๊ฐ๊ฐ์ ํด๋์ค๋ฅผ ๊ตฌ๋ถํ๋ ๋ฐ ์ด๋ ค์์ ๊ฒช์ ์ ์์
-
์ดํ ์์ธก์น๋ฅผ ๋ณด๊ณ ํผ๋์ ์ผ๊ธฐํ๋ ์์น๋ฅผ ํ์ํ ์ ์์
-
-
๊ฐ ๊ฐ๊ตฌ๋ณ ์์ธก ์ํ ์ ๊ฐ fold์ ๋ํ ์์ธก๊ฐ์
ํ๊ท
ํจ- ๊ฐ๊ฐ์ ๋ชจ๋ธ์ ์ฝ๊ฐ์ฉ ๋ค๋ฅธ ๋ฐ์ดํฐ fold์ ๋ํด ํ์ต๋จ -> ์ฌ๋ฌ ๋ชจ๋ธ์ ์ฌ์ฉํจ
-
Gradient Boosting Machine์
์์๋ธ ๋ชจ๋ธ
์ด๋ฉฐ, ์ฌ๋ฌ gbm ๋ชจ๋ธ์ ํ์ํ์ฌmeta-ensemble
๋ก ํ์ฉ
# fold ๋ณ ์์ธก์ ํ๊ท
predictions = predictions.groupby('idhogar', as_index = False).mean()
# ํด๋์ค ๋ฐ ๊ด๋ จ ํ๋ฅ ์ฐพ๊ธฐ
predictions['Target'] = predictions[[1, 2, 3, 4]].idxmax(axis = 1)
predictions['confidence'] = predictions[[1, 2, 3, 4]].max(axis = 1)
predictions = predictions.drop(columns = ['fold'])
# ๊ฐ target์ ๋ํ ์ ๋ขฐ๋ plotting
plt.figure(figsize = (10, 6))
sns.boxplot(x = 'Target', y = 'confidence', data = predictions)
plt.title('Confidence by Target')
plt.figure(figsize = (10, 6))
sns.violinplot(x = 'Target', y = 'confidence', data = predictions)
plt.title('Confidence by Target')
-
5๊ฐ์ fold์ ๋ํ ํ๊ท ์์ธก์ ์ทจํ๋ฉฐ, ์ฌ์ค์ 5๊ฐ์ ์๋ก ๋ค๋ฅธ ๋ชจ๋ธ์ ๊ฒฐํฉํ๋ ๊ฒ๊ณผ ๋์ผ
-
๊ฐ ๋ชจ๋ธ์ ์ฝ๊ฐ์ฉ ๋ค๋ฅธ ๋ฐ์ดํฐ ๋ถ๋ถ ์งํฉ์ ๋ํด์ ํ์ต๋จ
%%capture
submission, gbm_fi, valid_scores = model_gbm(train_set, train_labels,
test_set, test_ids, return_preds=False)
submission.to_csv('gbm_baseline.csv')
### feature ์ค์๋ ํ์ธ
_ = plot_feature_importances(gbm_fi, threshold = 0.95)
-
gbm์์ ์ค์ํ๊ฒ ์์ฉํ๋ feature๋ค์ ์ฃผ๋ก
age(๋์ด)
์์ ํ์๋ feature๋ค์์ ํ์ธํ ์ ์์ -
education
๋ณ์ ๋ํ ์ค์ํ ๊ฒ์ผ๋ก ๋ํ๋จ
b) ์ ํ๋ ๋ณ์๋ค๋ง ์ ์ฉํ๊ธฐ
- ์ค๋ณต feature ์ ๊ฑฐ ์์ ์ ํตํด ์ ํ๋ feature๋ค์ ํ์ฉ
%%capture --no-display
### ์ ํ๋ ๋ณ์๋ค๋ง ๊ฐ์ง๊ณ ๊ต์ฐจ ๊ฒ์ฆ ์ํ
submission, gbm_fi_selected, valid_scores_selected = model_gbm(train_selected, train_labels,
test_selected, test_ids)
### ๊ฒฐ๊ณผ ์ ์ฅ
model_results = model_results.append(pd.DataFrame({'model': ["GBM", "GBM_SEL"],
'cv_mean': [valid_scores.mean(), valid_scores_selected.mean()],
'cv_std': [valid_scores.std(), valid_scores_selected.std()]}),
sort = True)
### ๊ฒฐ๊ณผ ์๊ฐํ
model_results.set_index('model', inplace = True)
model_results['cv_mean'].plot.bar(color = 'orange', figsize = (8, 6),
yerr = list(model_results['cv_std']),
edgecolor = 'k', linewidth = 2)
plt.title('Model F1 Score Results')
plt.ylabel('Mean F1 Score (with error bar)')
model_results.reset_index(inplace = True)
10-fold ๊ต์ฐจ ๊ฒ์ฆ
์ ์ ์ฉํด๋ณด์.
%%capture
### 1. ์ ์ฒด feature์ ๋ํด..
# 5-folds -> 10-folds
submission, gbm_fi, valid_scores = model_gbm(train_set, train_labels, test_set, test_ids,
nfolds = 10, return_preds = False)
submission.to_csv('gbm_10fold.csv', index = False)
%%capture
### 2. ์ ํ๋ feature์ ๋ํด์๋ง
submission, gbm_fi_selected, valid_scores_selected = model_gbm(train_selected, train_labels,
test_selected, test_ids, nfolds = 10)
submission.to_csv('gmb_10fold_selected.csv', index = False)
### ๊ฒฐ๊ณผ ์ ์ฅ
model_results = model_results.append(pd.DataFrame({'model': ["GBM_10Fold", "GBM_10Fold_SEL"],
'cv_mean': [valid_scores.mean(), valid_scores_selected.mean()],
'cv_std': [valid_scores.std(), valid_scores_selected.std()]}),
sort = True)
### ๊ฒฐ๊ณผ ์๊ฐํ
model_results.set_index('model', inplace = True)
model_results['cv_mean'].plot.bar(color = 'orange', figsize = (8, 6),
edgecolor = 'k', linewidth = 2,
yerr = list(model_results['cv_std']))
plt.title('Model F1 Score Results')
plt.ylabel('Mean F1 Score (with error bar)')
model_results.reset_index(inplace = True)
-
๊ฐ์ฅ ์ข์ ๋ชจ๋ธ์
์ ํ๋ feature
๋ค๋ก10-fold
๊ต์ฐจ ๊ฒ์ฆ์ ์ํํ ๋ชจ๋ธ์ -
์ต์ ํ๋ฅผ ํตํด ์ฑ๋ฅ์ ๋ ๊ฐ์ ์ํฌ ์ ์์ ๊ฒ์ด๋ผ ๊ธฐ๋๋จ
print(f"There are {gbm_fi_selected[gbm_fi_selected['importance'] == 0].shape[0]} features with no importance.")
- ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ ๋ชจ๋ feature๋ค์ Gradient Boosting Machine์์ ์ด๋ ์ ๋ ์ค์ํ ๊ฒ์ ํ์ธํ ์ ์๋ค.
6. ๋ชจ๋ธ ์ต์ ํ(Model Optimization)
-
๊ต์ฐจ ๊ฒ์ฆ์ ํตํด
ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐ์
ํ์ฌ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์์ ์ต๊ณ ์ ์ฑ๋ฅ์ ์ด๋์ด ๋ด๋ ํ๋ก์ธ์ค -
๋ชจ๋ธ ์ต์ ํ Options
1. ์๋(Manual)
2. GridSearch
3. RandomSearch
4. ์๋ํ ๊ธฐ๋ฒ
- 4์ ๊ฒฝ์ฐ
Tree Parzen Estimator
์ ํจ๊ปBayesian Optimization
์ ์์ ๋ฒ์ ์ ์ฌ์ฉํ๋Hyperopt
๋ฅผ ํฌํจํ ๋ค์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ฝ๊ฒ ๊ตฌํ ๊ฐ๋ฅ -> ์ด๋ฅผ ํ์ฉ
6-1. Hyperopt์ ํตํ ๋ชจ๋ธ ํ๋
๋ฒ ์ด์ง์ ์ต์ ํ
์๋ 4๊ฐ์ง ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋จ
1. ๋ชฉ์ ํจ์: ์ต๋ํ(๋๋ ์ต์ํ)ํ๊ณ ์ถ์ ๊ฒ
2. ๋๋ฉ์ธ ์์ญ: ๊ฒ์ํ ์์ญ
3. ๋ค์ ํ์ดํผ ํ๋ผ๋ฏธํฐ ์ ํ์ ์ํ ์๊ณ ๋ฆฌ์ฆ: ๊ณผ๊ฑฐ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ ๊ฐ์ ์ ์
4. ๊ฒฐ๊ณผ ์ ์ฅ
from hyperopt import hp, tpe, Trials, fmin, STATUS_OK
from hyperopt.pyll.stochastic import sample
import csv
import ast
from timeit import default_timer as timer
a) ๋ชฉ์ ํจ์(Objective Function)
-
๋ชจ๋ธ ํ์ดํผ ํ๋ผ๋ฏธํฐ๊ฐ ์ฌ์ฉ๋๊ณ ๊ด๋ จ validation ์ ์๊ฐ ๋ฐํ๋จ
-
Hyperopt์ ์ต์ํ ํ ์ ์๋ฅผ ์๊ตฌํจ
1 - Macro F1 score
๋ฅผ ๋ฆฌํด
-
hyper parameter์ ๋ํ ์ฌ๋ฌ ์ธ๋ถ ์ฌํญ๋ค์ ์ค์ ํ๋ ๋จ๊ณ
def objective(hyperparameters, nfolds=5):
global ITERATION
ITERATION += 1
# ํ์ ์ํ
subsample = hyperparameters['boosting_type'].get('subsample', 1.0)
subsample_freq = hyperparameters['boosting_type'].get('subsample_freq', 0)
boosting_type = hyperparameters['boosting_type']['boosting_type']
if boosting_type == 'dart':
hyperparameters['drop_rate'] = hyperparameters['boosting_type']['drop_rate']
# Subsample and subsample frequency to top level keys
hyperparameters['subsample'] = subsample
hyperparameters['subsample_freq'] = subsample_freq
hyperparameters['boosting_type'] = boosting_type
# Whether or not to use limit maximum depth
if not hyperparameters['limit_max_depth']:
hyperparameters['max_depth'] = -1
# Make sure parameters that need to be integers are integers
for parameter_name in ['max_depth', 'num_leaves', 'subsample_for_bin',
'min_child_samples', 'subsample_freq']:
hyperparameters[parameter_name] = int(hyperparameters[parameter_name])
if 'n_estimators' in hyperparameters:
del hyperparameters['n_estimators']
# Using stratified kfold cross validation
strkfold = StratifiedKFold(n_splits = nfolds, shuffle = True)
# Convert to arrays for indexing
features = np.array(train_selected)
labels = np.array(train_labels).reshape((-1 ))
valid_scores = []
best_estimators = []
run_times = []
model = lgb.LGBMClassifier(**hyperparameters, class_weight = 'balanced',
n_jobs=-1, metric = 'None',
n_estimators=10000)
# Iterate through the folds
for i, (train_indices, valid_indices) in enumerate(strkfold.split(features, labels)):
# Training and validation data
X_train = features[train_indices]
X_valid = features[valid_indices]
y_train = labels[train_indices]
y_valid = labels[valid_indices]
start = timer()
# Train with early stopping
model.fit(X_train, y_train, early_stopping_rounds = 100,
eval_metric = macro_f1_score,
eval_set = [(X_train, y_train), (X_valid, y_valid)],
eval_names = ['train', 'valid'],
verbose = 400)
end = timer()
# Record the validation fold score
valid_scores.append(model.best_score_['valid']['macro_f1'])
best_estimators.append(model.best_iteration_)
run_times.append(end - start)
score = np.mean(valid_scores)
score_std = np.std(valid_scores)
loss = 1 - score
run_time = np.mean(run_times)
run_time_std = np.std(run_times)
estimators = int(np.mean(best_estimators))
hyperparameters['n_estimators'] = estimators
# Write to the csv file ('a' means append)
of_connection = open(OUT_FILE, 'a')
writer = csv.writer(of_connection)
writer.writerow([loss, hyperparameters, ITERATION, run_time, score, score_std])
of_connection.close()
# Display progress
if ITERATION % PROGRESS == 0:
display(f'Iteration: {ITERATION}, Current Score: {round(score, 4)}.')
return {'loss': loss, 'hyperparameters': hyperparameters, 'iteration': ITERATION,
'time': run_time, 'time_std': run_time_std, 'status': STATUS_OK,
'score': score, 'score_std': score_std}
b) ๋๋ฉ์ธ ์์ญ(Search Space)
-
domain
: ๊ฒ์ํ ์ ์ฒด ๊ฐ์ ๋ฒ์ -
boosting_type
์ดgoss
์ธ ๊ฒฝ์ฐ subsample ๋น์จ์ ๋ฐ๋์ 1.0์ผ๋ก ์ค์ ํด์ผ ํจ
space = {
'boosting_type': hp.choice('boosting_type',
[{'boosting_type': 'gbdt',
'subsample': hp.uniform('gdbt_subsample', 0.5, 1),
'subsample_freq': hp.quniform('gbdt_subsample_freq', 1, 10, 1)},
{'boosting_type': 'dart',
'subsample': hp.uniform('dart_subsample', 0.5, 1),
'subsample_freq': hp.quniform('dart_subsample_freq', 1, 10, 1),
'drop_rate': hp.uniform('dart_drop_rate', 0.1, 0.5)},
{'boosting_type': 'goss',
'subsample': 1.0,
'subsample_freq': 0}]),
'limit_max_depth': hp.choice('limit_max_depth', [True, False]),
'max_depth': hp.quniform('max_depth', 1, 40, 1),
'num_leaves': hp.quniform('num_leaves', 3, 50, 1),
'learning_rate': hp.loguniform('learning_rate',
np.log(0.025),
np.log(0.25)),
'subsample_for_bin': hp.quniform('subsample_for_bin', 2000, 100000, 2000),
'min_child_samples': hp.quniform('min_child_samples', 5, 80, 5),
'reg_alpha': hp.uniform('reg_alpha', 0.0, 1.0),
'reg_lambda': hp.uniform('reg_lambda', 0.0, 1.0),
'colsample_bytree': hp.uniform('colsample_by_tree', 0.5, 1.0)
}
sample(space)
c) ์๊ณ ๋ฆฌ์ฆ
-
๋ค์ ๊ฐ์ ์ ํํ๋ ์๊ณ ๋ฆฌ์ฆ์
Tree Parzen Estimator
๋ก,Bayes rule
์ ์ฌ์ฉํ์ฌ ๋ชฉ์ ํจ์์ ๋์ฒด ๋ชจ๋ธ์ ๊ตฌ์ฑํจ -
objective function์ ์ต๋ํ ํ๋ ๋์ ๋์ฒด ๋ชจ๋ธ์
Expected Improvement (EI)
๋ฅผ ์ต๋ํ
algo = tpe.suggest
d) ๊ฒฐ๊ณผ ์ ์ฅ
- ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ํ์ฉ
1. Trials object: ๋ชฉ์ ํจ์์์ ๋ฐํ๋ ๋ชจ๋ ๊ฒ์ ์ ์ฅ
2. ๋ฐ๋ณตํ ๋๋ง๋ค CSV ํ์ผ์ ์ฐ๊ธฐ
# ๊ฒฐ๊ณผ ์ ์ฅํ๊ธฐ
trials = Trials()
# ํ์ผ ์ด๊ธฐ, ์ฐ๊ฒฐํ๊ธฐ
OUT_FILE = 'optimization.csv'
of_connection = open(OUT_FILE, 'w')
writer = csv.writer(of_connection)
MAX_EVALS = 100
PROGRESS = 10
N_FOLDS = 5
ITERATION = 0
# ์ปฌ๋ผ๋ช
์์ฑ
headers = ['loss', 'hyperparameters', 'iteration', 'runtime', 'score', 'std']
writer.writerow(headers)
of_connection.close()
%%capture --no-display
display("Running Optimization for {} Trials.".format(MAX_EVALS))
# ์ต์ ํ ์ํ
best = fmin(fn = objective, space = space, algo = tpe.suggest, trials = trials,
max_evals = MAX_EVALS)
-
ํ์ต์ ์ฌ๊ฐํ๊ธฐ ์ํด์ ๋์ผํ
trials
๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๊ณ ์ต๋ ๋ฐ๋ณต ํ์๋ฅผ ๋๋ฆฌ๋ฉด ๋จ -
๋์ค์ ํ์ฉํ๊ธฐ ์ํด trials๋ฅผ
json
์ผ๋ก ์ ์ฅํ ์ ์์
import json
# trial ๊ฒฐ๊ณผ ์ ์ฅ
with open('trials.json', 'w') as f:
f.write(json.dumps(str(trials)))
6-2. ์ต์ ํ๋ ๋ชจ๋ธ ์ฌ์ฉํ๊ธฐ
### ์ต์ ํ ๋ ๋ชจ๋ธ ๊ฒฐ๊ณผ ๊ฐ์ ธ์ค๊ธฐ
results = pd.read_csv(OUT_FILE).sort_values('loss', ascending = True).reset_index()
results.head()
### ๊ฒฐ๊ณผ ์๊ฐํ
plt.figure(figsize = (8, 6))
sns.regplot('iteration', 'score', data = results)
plt.title("Optimization Scores")
plt.xticks(list(range(1, results['iteration'].max() + 1, 3)))
### ์ต์ parameter ์ ํ
best_hyp = ast.literal_eval(results.loc[0, 'hyperparameters'])
best_hyp
%%capture
### ์ ํ๋ feature๋ค๋ก๋ง ๋ชจ๋ธ๋ง
submission, gbm_fi, valid_scores = model_gbm(train_selected, train_labels,
test_selected, test_ids,
nfolds = 10, return_preds=False)
model_results = model_results.append(pd.DataFrame({'model': ["GBM_OPT_10Fold_SEL"],
'cv_mean': [valid_scores.mean()],
'cv_std': [valid_scores.std()]}),
sort = True).sort_values('cv_mean', ascending = False)
%%capture
### ์ ์ฒด feature๋ก ๋ชจ๋ธ๋ง
submission, gbm_fi, valid_scores = model_gbm(train_set, train_labels,
test_set, test_ids,
nfolds = 10, return_preds=False)
model_results = model_results.append(pd.DataFrame({'model': ["GBM_OPT_10Fold"],
'cv_mean': [valid_scores.mean()],
'cv_std': [valid_scores.std()]}),
sort = True).sort_values('cv_mean', ascending = False)
model_results.head()
### ์ ์ผ ์ฑ๋ฅ์ด ์ข์ ๋ชจ๋ธ๋ก ์์ธก ํ ๊ฒฐ๊ณผ ์ ์ฅ
submission.to_csv('gbm_opt_10fold_selected.csv', index = False)
-
์ด ์์ ์์ ์ฑ๋ฅ์ ๊ฐ์ ํ๊ธฐ ์ํด ์ต์ ํ๋ฅผ ๊ณ์ํ๊ฑฐ๋, ๋ ๋ง์ ๊ธฐ๋ฅ ์์ง๋์ด๋ง/ ์ถ๊ฐ์ ์ธ ๋ชจ๋ธ ์คํ ๋๋ ์์๋ธ์ ์๋ํ๊ฑฐ๋, ์ฐจ์ ์ถ์ ๋๋ ์ค๋ฒ์ํ๋ง๊ณผ ๊ฐ์ ๋ ์คํ์ ์ธ ๋ฐฉ๋ฒ์ ๊ฒํ ํ ์ ์์
- ์์ธก๊ฐ์ ๊ฒํ ํ์ฌ ๋ชจ๋ธ์ด ์ด๋์ ์ค๋ฅ๋ฅผ ๋ฒํ๊ณ ์๋์ง๋ฅผ ํ์ธํ ์์
_ = plot_feature_importances(gbm_fi)
7. ์์ธก ํ์ธ
-
test ๋ฐ์ดํฐ์์ ์์ธก๋ label์ ๋ถํฌ๋ฅผ ์๊ฐํํ์ฌ ํ์ธํ ์ ์์
-
train ๋ฐ์ดํฐ์ ๋์ผํ ๋ถํฌ๋ฅผ ๋ณด์ผ ๊ฒ์ผ๋ก ์์๋จ
-
๊ฐ๊ตฌ๋ณ ์์ธก์ ๊ด์ฌ์ด ์๊ธฐ์, ๊ฐ ๊ฐ๊ตฌ์ ๋ํ ์์ธก๋ง ํ์ธํ์ฌ train ๋ฐ์ดํฐ์ ์์ธก๊ณผ ๋น๊ต
-
-
๋ค์ ํ์คํ ๊ทธ๋จ์ ์ ๋ ์นด์ดํธ ๋์ ์๋์ ์ธ ๋น๋๋ฅผ ํ์ํ๋ ์ ๊ทํ ๋ ๊ฐ
- ์๋ณธ์ ๋ฐ์ดํฐ ์์ validation ๋ฐ์ดํฐ์์์ ๋ฐ์ดํฐ ์๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ
preds = submission_base.merge(submission, on = 'Id', how = 'left')
preds = pd.DataFrame(preds.groupby('idhogar')['Target'].mean())
# train data์์์ label์ ๋ถํฌ ์๊ฐํ
fig, axes = plt.subplots(1, 2, sharey = True, figsize = (12, 6))
heads['Target'].sort_index().plot.hist(normed = True,
edgecolor = r'k',
linewidth = 2,
ax = axes[0])
axes[0].set_xticks([1, 2, 3, 4])
axes[0].set_xticklabels(poverty_mapping.values(), rotation = 60)
axes[0].set_title('Train Label Distribution')
# Plot the predicted labels
preds['Target'].sort_index().plot.hist(normed = True,
edgecolor = 'k',
linewidth = 2,
ax = axes[1])
axes[1].set_xticks([1, 2, 3, 4])
axes[1].set_xticklabels(poverty_mapping.values(), rotation = 60)
plt.subplots_adjust()
plt.title('Predicted Label Distribution')
heads['Target'].value_counts()
preds['Target'].value_counts()
-
์ฝ๊ฐ์ ์ฐจ์ด๊ฐ ์์ง๋ง train label์ ๋ถํฌ์ ๊ฐ๊น์
target = 4
๊ฐ ์๋target = 3
์ด ๊ณผ๋ํ๊ฒ ํํ๋จ
-
๋ถ๊ท ํ ๋ถ๋ฅ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์์์ ํด๋์ค๋ฅผ oversamplingํ๋ ๋ฐฉ๋ฒ์ด ์์
imbalanced learn
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ์ฌ ์ฝ๊ฒ ๊ตฌํ ๊ฐ๋ฅ
7-1. ๊ฒ์ฆ(Validation)
-
test์ฉ ์์ธก์ ํตํด label์ ๋ถํฌ๋ฅผ train ๋ฐ์ดํฐ์์์ ๋ถํฌ์ ๋น๊ตํ ์ ์์
-
์์ธก์ ์ค์ ๊ฐ๊ณผ ๋น๊ตํ๊ธฐ ์ํด์๋ train ๋ฐ์ดํฐ๋ฅผ ๋ณ๋์ validation ์ธํธ๋ก ๋ถํ ํด์ผ ํจ
-
1000๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ฆ์ ํ์ฉ
-
์ดํ
confusion matrix
๋ฅผ ํตํด ์ค๋ถ๋ฅ ํ์ง
-
from sklearn.model_selection import train_test_split
# ๋ฐ์ดํฐ ๋ถํ
X_train, X_valid, y_train, y_valid = train_test_split(train_selected,
train_labels,
test_size = 1000,
random_state = 10)
# ๋ชจ๋ธ ์์ฑ/ํ์ต
model = lgb.LGBMClassifier(**best_hyp,
class_weight = 'balanced',
random_state = 10)
model.fit(X_train, y_train);
# ๊ฒ์ฆ ์ํ
valid_preds = model.predict_proba(X_valid)
preds_df = pd.DataFrame(valid_preds, columns = [1, 2, 3, 4])
# ์์ธก๊ฐ์ผ๋ก ๋ณํ
preds_df['prediction'] = preds_df[[1, 2, 3, 4]].idxmax(axis = 1)
preds_df['confidence'] = preds_df[[1, 2, 3, 4]].max(axis = 1)
preds_df.head()
print('F1 score:', round(f1_score(y_valid, preds_df['prediction'], average = 'macro'), 5))
๐ ์ค์ฐจ ํ๋ ฌ(confusion matrix)
- ์์ธก๊ณผ ์ค์ ๊ฐ์ ์ฐจ์ด๋ฅผ ๋ณด์ฌ์ค์ผ๋ก์จ ๋ชจํ์ด ํผ๋ํ๋ ์ง์ ์ ํ์ ํ ์ ์์
from sklearn.metrics import confusion_matrix
import itertools
### ์ค์ฐจ ํ๋ ฌ์ ์์ฑํ๋ ํจ์
def plot_confusion_matrix(cm, classes,
normalize = False,
title = 'Confusion matrix',
cmap = plt.cm.Oranges):
### ์ ๊ทํ
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
print("Normalized confusion matrix")
else:
print('Confusion matrix, without normalization')
print(cm)
plt.figure(figsize = (10, 10))
plt.imshow(cm, interpolation='nearest', cmap = cmap)
plt.title(title, size = 24)
plt.colorbar(aspect = 4)
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation = 45, size = 14)
plt.yticks(tick_marks, classes, size = 14)
fmt = '.2f' if normalize else 'd' # formatting
thresh = cm.max() / 2. # ์๊ณ๊ฐ ์ค์
### Labeling
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], fmt), fontsize = 20,
horizontalalignment = "center",
color = "white" if cm[i, j] > thresh else "black")
plt.grid(None)
plt.tight_layout()
plt.ylabel('True label', size = 18)
plt.xlabel('Predicted label', size = 18)
cm = confusion_matrix(y_valid, preds_df['prediction']) # ์ค์ฐจ ํ๋ ฌ
plot_confusion_matrix(cm, classes = ['Extreme', 'Moderate', 'Vulnerable', 'Non-Vulnerable'],
title = 'Poverty Confusion Matrix')
-
Confusion Matrix ํด์
-
๋๊ฐ์ :(์์ธก ๊ฐ) == (์ค์ ๊ฐ)
-
๋๋จธ์ง: ์๋ชป๋ ๊ฐ
-
-
ํ์ฌ ๋ชจ๋ธ์
poverty = extreme
์ธ 25๊ฐ์ ๊ด์ธก์น๋ฅผ ์ ํํ๊ฒ ์์ธกํ ๋ฐ๋ฉด, ๋๋จธ์ง 26๊ฐ์ ๊ด์ธก์น์ ๊ฒฝ์ฐpoverty = moderate
๋ผ๊ณ ์๋ชป ์์ธกํจ -
์ ๋ฐ์ ์ผ๋ก ๋ชจ๋ธ์
poverty = non-vulnerable
์ธ ๊ฐ๊ตฌ๋ฅผ ์๋ณํ๋ ๋ฐ๋ง ๋งค์ฐ ์ ํํ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์์ -
์ค์ ๋ ์ด๋ธ์ ๋ํ ์ค์ฐจ ํ๋ ฌ์ ์ ๊ทํํ์ฌ ๊ฐ ํด๋์ค์์ ์์ธก๋ ์ค์ ๋ ์ด๋ธ์ ๋ฐฑ๋ถ์จ์ ํ์ธํ ์ ์์
plot_confusion_matrix(cm, normalize = True,
classes = ['Extreme', 'Moderate', 'Vulnerable', 'Non-Vulnerable'],
title = 'Poverty Confusion Matrix')
-
poverty = non-vulnerable
์ธ์ ํด๋์ค๋ ์ ๊ตฌ๋ถํ์ง ๋ชปํ๊ณ ์๋ ๊ฒ์ ํ์ธํ ์ ์์ -
poverty = vulnerable
์ค ์ฝ 35%๋ง ์ ํํ๊ฒ ์๋ณํ๊ณ , ๋ ๋ง์ ์๋ ์๋ชป ๋ถ๋ฅํ๊ณ ์์
๋ถ๊ท ํ ๋ฐ์ดํฐ ๋ถ๋ฅ ๋ฌธ์ ๋ ๋ชจ๋ธ์ด ์ ํํ ์์ธก์ ํ๋ ๋ฐ ์ด๋ ค์์ด ์์
- ์ด๋ฌํ ๊ฒฝ์ฐ oversampling์ด๋ ์ฌ๋ฌ ์์ญ์์ ๋ค์ํ ๋ชจ๋ธ์ ํ์ตํ๋ ๋ฑ์ ๋ฐฉ๋ฒ์ ํํ ์๋ ์์ง๋ง,
๋ฐ์ดํฐ๋ฅผ ์ต๋ํ ๋ง์ด ๋ชจ์ผ๋ ๊ฒ
์ด ๊ถ์ฅ๋จ
7-2. ์ฐจ์ ์ถ์(Dimension Reduction)
-
์ ํ๋ ๋ฐ์ดํฐ ์ธํธ์ ๋ช ๊ฐ์ง ๋ค๋ฅธ ์ฐจ์ ์ถ์ ๋ฐฉ๋ฒ์ ์ ์ฉํ ์ ์์
- ์๊ฐํ ๋๋ ๊ธฐ๊ณ ํ์ต์ ์ํ ์ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ผ๋ก ์ฌ์ฉํ ์ ์์
-
์ข ๋ฅ
-
PCA
(Principal Components Analysis): ๋ฐ์ดํฐ์์ ๊ฐ์ฅ ํฐ ๋ณ๋์ด ์ผ์ด๋๋ ์ฐจ์์ ์ฐพ์ -
ICA
(Independent Components Analysis): ๋ค๋ณ๋ ์ ํธ๋ฅผ ๋ ๋ฆฝ์ ์ธ ์ ํธ๋ก ๋ถ๋ฆฌํ๋ ค๊ณ ์๋ -
TSNE
(T-distributed Stochastic Neighbor Embedding): ๊ณ ์ฐจ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฐจ์ ๋งค๋ํด๋์ ๋งคํํ์ฌ ๋ฐ์ดํฐ ๋ด์ ๋ก์ปฌ ๊ตฌ์กฐ๋ฅผ ์ ์ง -
UMAP
(Uniform Manifold Approximation and Projection): ๋ฐ์ดํฐ๋ฅผ ์ ์ฐจ์ ๋งค๋ํด๋์ ๋งคํํ์ง๋ง TSNE๋ณด๋ค ๋ ๋ง์ ์ ์ญ ๊ตฌ์กฐ๋ฅผ ๋ณด์กดํ๋ ค๊ณ ํ๋ ๋น๊ต์ ์๋ก์ด ๊ธฐ์
-
๋ค ๊ฐ์ง ๋ฐฉ๋ฒ ๋ชจ๋ ํ์ด์ฌ์์ ๊ตฌํํ๊ธฐ๊ฐ ๋น๊ต์ ๊ฐ๋จํจ
-
์๊ฐํ๋ฅผ ์ํด ์ ํํ ํ์์ 3์ฐจ์์ผ๋ก ๋งคํํ ๋ค์ ๋ชจ๋ธ๋ง ํ์์ผ๋ก
PCA
,ICA
๋ฐUMAP
์ ์ฌ์ฉTSNE
์๋ ๋ณํ ๋ฐฉ๋ฒ์ด ์์ผ๋ฏ๋ก ์ ์ฒ๋ฆฌ์ ์ฌ์ฉํ ์ ์์
!pip install umap
from umap import UMAP
from sklearn.decomposition import PCA, FastICA
from sklearn.manifold import TSNE
n_components = 3 # 3์ฐจ์
### ์ฐจ์ ์ถ์๋ฅผ ์ํ ๊ฐ์ฒด ์์ฑ
umap = UMAP(n_components = n_components)
pca = PCA(n_components = n_components)
ica = FastICA(n_components = n_components)
tsne = TSNE(n_components = n_components)
train_df = train_selected.copy()
test_df = test_selected.copy()
for method, name in zip([umap, pca, ica, tsne],
['umap', 'pca', 'ica', 'tsne']):
# TSNE๋ ๋ณํ method๊ฐ ์์
if name == 'tsne':
start = timer()
reduction = method.fit_transform(train_selected)
end = timer()
else:
start = timer()
reduction = method.fit_transform(train_selected)
end = timer()
test_reduction = method.transform(test_selected)
# Add components to test data
test_df['%s_c1' % name] = test_reduction[:, 0]
test_df['%s_c2' % name] = test_reduction[:, 1]
test_df['%s_c3' % name] = test_reduction[:, 2]
# Add components to training data for visualization and modeling
train_df['%s_c1' % name] = reduction[:, 0]
train_df['%s_c2' % name] = reduction[:, 1]
train_df['%s_c3' % name] = reduction[:, 2]
# ์์ ์๊ฐ ์ถ๋ ฅ
print(f'Method: {name} {round(end - start, 2)} seconds elapsed.')
from mpl_toolkits.mplot3d import Axes3D
def discrete_cmap(N, base_cmap=None):
"""Create an N-bin discrete colormap from the specified input map
Source: https://gist.github.com/jakevdp/91077b0cae40f8f8244a"""
base = plt.cm.get_cmap(base_cmap)
color_list = base(np.linspace(0, 1, N))
cmap_name = base.name + str(N)
return base.from_list(cmap_name, color_list, N)
cmap = discrete_cmap(4, base_cmap = plt.cm.RdYlBu)
train_df['label'] = train_labels
### ๊ฐ๊ฐ์ ๋ฐฉ๋ฒ์ ํ์ฉํ์ฌ ์๊ฐํ
for method, name in zip([umap, pca, ica, tsne],
['umap', 'pca', 'ica', 'tsne']):
fig = plt.figure(figsize = (8, 8))
ax = fig.add_subplot(111, projection='3d')
p = ax.scatter(train_df['%s_c1' % name], train_df['%s_c2' % name], train_df['%s_c3' % name],
c = train_df['label'].astype(int), cmap = cmap)
plt.title(f'{name.capitalize()}', size = 22)
fig.colorbar(p, aspect = 4, ticks = [1, 2, 3, 4])
-
์ด๋ฌํ ๊ทธ๋ํ์์ ๋ง์ ๊ตฐ์งํ๋ฅผ ๋ณด๊ธฐ๋ ์ด๋ ค์
- ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฐ์ดํฐ๋ฅผ ๊ณ ๋ คํ ๋ ๋น๊ณค ์์ค์ ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ด๋ ค์์ ์๋ฏธ
-
๋ง์ง๋ง์ผ๋ก
PCA
,ICA
๋ฐUMAP
์ ํ์ฉํ์ฌ ์ถ๊ฐ์ ์ผ๋ก feature์ ๊ฐ์๋ฅผ ์ค์ฌ ๋ชจ๋ธ์ ํ์ต์ํฌ ์ ์์
train_df, test_df = train_df.align(test_df, axis = 1, join = 'inner')
%%capture
submission, gbm_fi, valid_scores = model_gbm(train_df, train_labels,
test_df, test_ids, nfolds = 10,
hyp = best_hyp)
submission.to_csv('gbm_opt_10fold_dr.csv', index = False)
model_results = model_results.append(pd.DataFrame({'model': ["GBM_OPT_10Fold_DR"],
'cv_mean': [valid_scores.mean()],
'cv_std': [valid_scores.std()]}),
sort = True)
model_results = model_results.sort_values('cv_mean')
model_results.set_index('model', inplace = True)
model_results['cv_mean'].plot.bar(color = 'orange', figsize = (10, 8),
edgecolor = 'k', linewidth = 2,
yerr = list(model_results['cv_std']))
plt.title('Model F1 Score Results')
plt.ylabel('Mean F1 Score (with error bar)')
model_results.reset_index(inplace = True)
-
์ฐจ์์ด ๊ฐ์๋ ์ฑ๋ถ์ ๋ชจํ์ ์ ์ฒด ์ฑ๋ฅ์ ์ฝ๊ฐ ์ํฅ์ ๋ฏธ์นจ
- train data์ ๊ณผ์ ํฉ์ ์ด๋ํ ์ ์์
_ = plot_feature_importances(gbm_fi)
-
์ฐจ์ ์ถ์๋ feature์ feature importance๊ฐ ๋งค์ฐ ๋์
- overfitting์ด ๋ฐ์ํ ์ ์์
-
์ฐจ์ ์ถ์๋ label ์ ๋ณด๋ฅผ ์ฌ์ฉํ์ง x
- ๋ชจํ์ ์์ธก์ ์ค์ํ ์ ๋ณด๋ค์ ํฌํจํ์ง ๋ชปํ ์๋ ์์
7-3. ๋จ์ผ ํธ๋ฆฌ ๋ชจ๋ธ ์๊ฐํ
-
RandomForestClassifier์์ ํ๋์ ์์ฌ ๊ฒฐ์ ํธ๋ฆฌ๋ฅผ ์ดํด๋ณผ ์ ์์
- ๊ฐ์์ฑ์ ์ํด
max_depth
๋ฅผ ์ ํํ ๋ค์ ํธ๋ฆฌ๋ฅผ ์ ์ฒด์ ์ผ๋ก ํ์ฅํจ
- ๊ฐ์์ฑ์ ์ํด
model = RandomForestClassifier(max_depth = 3, n_estimators=10)
model.fit(train_selected, train_labels)
### ํ๋์ ํธ๋ฆฌ๋ฅผ ์ถ์ถ
estimator_limited = model.estimators_[5]
estimator_limited
- ํ๋ จ๋ ํธ๋ฆฌ๋ฅผ ๊ฐ์ ธ์
export_graphviz
๋ฅผ ์ฌ์ฉํ์ฌ.dot
ํ์ผ๋ก ๋ด๋ณด๋
### ๋จ์ผ ํธ๋ฆฌ ๋ชจํ ๋ด๋ณด๋ด๊ธฐ
from sklearn.tree import export_graphviz
export_graphviz(estimator_limited, out_file='tree_limited.dot', feature_names = train_selected.columns,
class_names = ['extreme', 'moderate' , 'vulnerable', 'non-vulnerable'],
rounded = True, proportion = False, precision = 2, filled = True)
.dot
ํ์ผ์.png
ํ์ผ๋ก ๋ณํ
!dot -Tpng tree_limited.dot -o tree_limited.png
IPython.display
์ ํ์ฉํ์ฌ Jupyter Notebook์์ ํธ๋ฆฌ๋ฅผ ํ์ธ
### ํธ๋ฆฌ ์๊ฐํ
from IPython.display import Image
Image(filename = 'tree_limited.png')
๐ ์ต๋ ๊น์ด ์ ํ ์์ด ํธ๋ฆฌ ์๊ฐํ
-
๊น์ด ์ ํ์ด ์์ผ๋ฉด, ํธ๋ฆฌ๋ ๋ฌดํ์ ์ฑ์ฅํ ์ ์์
- ๋ฐ๋ผ์, ์ผ๋ฐ์ ์ผ๋ก๋ ์ฝ๊ฐ์ ์ ํ์ ๋๋ ๊ฒ์ด ๋์๋จ
# ๊น์ด ์ ํ x
model = RandomForestClassifier(max_depth = None, n_estimators=10)
model.fit(train_selected, train_labels)
estimator_nonlimited = model.estimators_[5]
export_graphviz(estimator_nonlimited, out_file='tree_nonlimited.dot', feature_names = train_selected.columns,
class_names = ['extreme', 'moderate' , 'vulnerable', 'non-vulnerable'],
rounded = True, proportion = False, precision = 2)
!dot -Tpng tree_nonlimited.dot -o tree_nonlimited.png -Gdpi=600
Image(filename = 'tree_nonlimited.png')
~๋์ ํ ์์๋ณผ ์ ์์~
8. ๊ฒฐ๋ก
-
์ค์ ๋ฌธ์ ์ ๋ํ ์ ์ฒด ๋ฐ์ดํฐ ๊ณผํ ์๋ฃจ์ ์ ๋จ๊ณ๋ณ ๊ตฌํ์ ์ํ
-
ํ๋ก์ธ์ค ์ ๋ฆฌ>
1. ๋ฌธ์ ์ดํด
2. ํ์์ ๋ฐ์ดํฐ ๋ถ์(EDA)
- ๋ฐ์ดํฐ ๋ฌธ์ ์ฒ๋ฆฌ
- ๊ฒฐ์ธก๊ฐ ์
๋ ฅ
3. ํน์ฑ ๊ณตํ(Feature Engineering)
- ๋ฐ์ดํฐ ์ง๊ณ(aggregation)
- ๋จ๊ณ๋ณ ํผ์ณ ์ ํ
4. ๋ชจ๋ธ ์ ํ
- ๋ค์ํ ๋ชจ๋ธ์ ์๋ํ์ฌ ์ด๋ค ๋ชจ๋ธ์ด ๊ฐ์ฅ ์ ๋ ฅํ์ง ํ์ธ
- ๊ธฐ๋ฅ ์ ํ ๊ธฐ๋ฅ๋ ์๋ ๊ฐ๋ฅ
5. ๋ชจ๋ธ ์ต์ ํ
- ์ต๊ณ ์ฑ๋ฅ ๋ชจ๋ธ์ ์ ํํ๊ณ ํ๋
6. ๋ชจ๋ธ ์ต์ ํ
7. ์์ธก ๊ฒํ
- ๋ชจ๋ธ์ ๋จ์ ์ ์๋ณํฉ๋๋ค
8. ์๋ก์ด ๊ธฐ์ ์ ์๋
-
์๋ก ์์ ์ธ๊ธํ ๋ฐ์ ๊ฐ์ด, ์ด๋ฌํ ๋จ๊ณ๋ ์ผ๋ฐ์ ์ธ ์์๋ฅผ ๊ฐ์ง๊ณ ์์ง๋ง, ์ฑ๋ฅ์ ๋ง์กฑ๋์ง ๋ชปํ๋ ๊ฒฝ์ฐ ๋ชจ๋ธ๋ง ํ ํผ์ณ ์์ง๋์ด๋ง/์ ํ ํญ๋ชฉ์ผ๋ก ๋๋์๊ฐ๋ ๊ฒฝ์ฐ๋ ๋ง์
- ์์ธก์ ์กฐ์ฌํ ํ ๋ชจ๋ธ๋ง ๋จ๊ณ๋ก ๋์๊ฐ์ ์ ๊ทผ ๋ฐฉ์์ ๋ค์ ์๊ฐํ ์๋ ์์
-
๊ธฐ๊ณ ํ์ต์ ๋๋ถ๋ถ ๊ฒฝํ์ ์ด๋ผ๋ ๊ฒ์ ๋ช ์ฌํด์ผ ํจ
- ํ๋ฆฝ๋ ๋ชจ๋ฒ ์ฌ๋ก๊ฐ ๊ฑฐ์ ์์ผ๋ฏ๋ก ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์ ๊ฒฐ์ ํ๊ธฐ ์ํด ์ง์์ ์ผ๋ก ๊ฒฝํํด์ผ ํจ
-
์ฐ๋ฆฌ์ ์ต์ข ๋ชจ๋ธ์ ๋ค๋ฅธ ๊ฒฝ์ ๋ชจ๋ธ๋ค์ ๋นํด ์ฐ์ํ์ง๋ง, ์ ์ฒด์ ์ผ๋ก ๋งค์ฐ ์ ํํ์ง๋ ์์
-
์ฑ๋ฅ์ ๊ฐ์ ํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์ ์ ์์ง๋ง, ์ ๋ฐ์ ์ผ๋ก
๋ฐ์ดํฐ๊ฐ ๋ถ์กฑ
ํ์ฌ ์์ธ์ ์ธ ๋ฉํธ๋ฆญ์ ๋ฌ์ฑํ ์ ์์ -
๊ฒฐ๊ตญ ๋ฐ์ดํฐ ๊ณผํ ํ๋ก์ ํธ์ ์ฑํจ๋
์ฌ์ฉ ๊ฐ๋ฅํ ๋ฐ์ดํฐ์ ํ์ง๊ณผ ์
์ ๋ฌ๋ ค ์์
-
๐ ์ถ๊ฐ์ ์ผ๋ก ํ ์ ์๋ ๊ฒ๋ค
- ์ถ๊ฐ์ ์ธ hyper parameter tuning
- ๋ชจ๋ธ์ ์ต์ ํํ๋ ๋ฐ ๋ง์ ์๊ฐ์ ํฌ์ํ์ง ์์์ผ๋ฉฐ, ์ต์ ํ๋ฅผ ์ํด ์๋ํ ์ ์๋ ๋ค๋ฅธ ํจํค์ง๊ฐ ์์
- ์ถ๊ฐ์ ์ธ feature selection
- ๋์ผํ ์ฑ๋ฅ์ ์ป๊ธฐ ์ํด ๋ชจ๋ feature์ ์ ์งํ ํ์๋ ์์
-
์์์ class์ ๋ํ oversampling, ๋ง์ class์ ๋ํ undersampling
-
์ฌ๋ฌ ๋ชจ๋ธ์ ์์๋ธ/์คํํน
- ๋ฐ์ดํฐ์ ๋ค๋ฅธ ๋ถ๋ถ์ ๋ํด ๋ชจ๋ธ์ ํ๋ จ์ํค๊ณ ๊ทธ๋ค์ ์์ธก์ ๊ฒฐํฉํ์ฌ ํด๋์ค๋ฅผ ๋ ์ ๋ถ๋ฆฌํ ์ ์์