지금 분석 하려고 하는 내용은 복잡하니, 개괄적인 내용만 미리 정리해보겠습니다.
우선 Imbalanced Dataset를 모델링시키기 위해서는 아래와 같은 순서로 진행합니다.
- StratifiedKFold기법을 적용하여, train과 test dataset으로 쪼개고
- Train dataset의 Minority class를 over sampling하고
- over sampling 된 traing dataset으로 모델을 Traning 시킨 후
- 원래 데이터의 test dataset을 통해 test한 후 모델설명력을 평균 내는 것 (cross validation의 원리)
왜 imbalanced dataset에서는 위와 같이 복잡하게 진행할까라고 하시는 분들은 아래 설명을 보시면 조금 이해가 될거 같습니다.
(우리와 같은 궁금증에 대해서 올려놓은 글이니 참고만하셔요)
> datascience.stackexchange.com/questions/16247/cross-validation-plus-oversampling
위의 두 사이트를 정리해 보자면 실제 우리가 oversampling을 하고 그 다음 cross validation을 할 때,
실제, validation set이나, test set이 oversampling되지 않는 것에 유의하자! 라는 얘기죠.
만약!
oversampling 된 노란표시 데이터가, 아래 그림과 같이 training set에도 그리고 validation set에도 들어가게 된다면,
과적합될 가능성이 있는겁니다.
따라서 위의 이슈를 해결하기 위해서는 아래와 같이 k-fold로 나눈 데이터 셋의 training dataset만을 oversampling 시키고, 순수한(원 상태의) validation set만을 테스트 할 때 사용하는 것이죠.
(더 상세한 설명은 링크 공유된 사이트를 참조하시길)
위 사이트에서는 해당 logic이 R코드로 되어있어, 저는 파이썬으로 정리해보려고 합니다.
우선 아래와 같이 사전작업을 먼저 할게요.
K-fold split을 위해 x_origin, y_origin dataframe을 array형태로 바꿔줍니다.
1
2
3
4
5
6
7
8
|
import numpy as np
# K-fold split을 위해 x_origin, y_origin dataframe을 array형태로 바꿔줍니다.
# 혹시 array형태로 바꾸지 않고 k-fold split을 할 수 있는 로직을 아시는 분은 공유부탁드려요.
x_arr=np.asarray(x_origin)
y_arr=np.asarray(y_origin)
from sklearn.model_selection import StratifiedKFold
kf = StratifiedKFold(n_splits=5)
|
cs |
그 다음은, 모델링 관련된 함수를 만들어 주는데, 저는 random forest 분류모델을 쓰겠습니다.
아래 함수 안에 추가하고 싶은 다양한 분류모델링을 넣어주셔도 됩니다.
1
2
3
4
|
def clf():
rfc = RandomForestClassifier(max_depth=5, random_state=333,
criterion = "entropy",n_estimators = 5, max_features='auto')
return rfc
|
cs |
아래에서 minority class는 target값이 1일 때 입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
col_list=x_arr.columns
from sklearn.metrics import accuracy_score
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
from sklearn.metrics import f1_score
from sklearn.metrics import roc_curve
a_rfc=[] # accuracy
r_rfc=[] # recall
p_rfc=[] # precision
f_rfc=[] # f-score
ro_rfc=[] # roc
#for 문 안에서 이전에 설정한 n_split=5의 값으로 데이터를 split해 줍니다.
for train_index, test_index in kf.split(x_arr, y_arr):
x_train, x_test = x_arr[train_index], x_arr[test_index]
y_train, y_test = y_arr[train_index], y_arr[test_index]
x_test=pd.DataFrame(x_test, columns=col_list)
# array concat
y_train2=y_train.reshape(y_train.shape[0],1)
trset=np.concatenate([x_train,y_train2],axis=1)
# over sampling
# 여기서는 중복추출을 통해 단순히 minority class 데이터를 2배로 뻥튀기 시키겠습니다.
# 원하신다면, 이 부분에는 smote관련 코드를 넣어도 됩니다.
trset_df=pd.DataFrame(trset, columns=col_list)
over=trset_df[trset_df['target']==1]
# minority class를 그대로 가져와서만든 over라는 dataset과 trset_df와 합쳐줍니다.
trset_over=pd.concat([trset_df, over], axis=0)
# split
# 이제 최종적인 train dataset에서 x & y(타겟) 변수로 나눠줍니다.
x_train_fin=trset_over.drop(['target'],axis=1)
y_train_fin=trset_over['target']
#clf
rfc = clf()
rfc.fit(x_train_fin, y_train_fin)
pred_rfc = rfc.predict(x_test)
#score
accuracy_rfc = accuracy_score(y_test,pred_rfc)
a_rfc.append(accuracy_rfc)
recall_rfc = recall_score(y_test,pred_rfc)
r_rfc.append(recall_rfc)
precision_rfc = precision_score(y_test,pred_rfc)
p_rfc.append(precision_rfc)
f1_rfc = f1_score(y_test,pred_rfc)
f_rfc.append(f1_rfc)
roc_rfc = roc_curve(y_test,pred_rfc)
ro_rfc.append(roc_rfc)
|
cs |
이 결과 5개의 scoring결과가 저장된 list안에는 각 iteration별 score점수가 append 되어있을거에요.따라서, iteration별 score 점수의 평균을 내준다면, 우리가 cross-validation결과로 얻고싶어하는 값을 얻을 수 있습니다.
1
|
np.mean(a_rfc), np.mean(p_rfc), np.mean(r_rfc), np.mean(f_rfc), np.mean(ro_rfc)
|
cs |
별로 좋은 결과는 아니지만, 참고만 하시라고 공유드립니다.
참고로 dummy classification과 비교할 수 있는데, imblanced 인것을 감안해서 아래와 같이 baseline을 확인하시면 됩니다.
1
2
3
4
|
from sklearn.dummy import DummyClassifier
dummy = DummyClassifier(strategy='stratified', random_state=333)
dummy.fit(x_origin, y_origin['target'])
cv_accuracy(dummy, x_origin, y_origin['target'] )
|
cs |
cv_accuracy등은 함수로 아래와 같이 만들어 놓으시면 쓰기 편하답니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
from sklearn.model_selection import cross_val_score
def cv_recall(model, x, y):
scores = cross_val_score(model, x, y, cv=5, scoring='recall'); scores
print("Mean: {:.3f}\nStd: {:.3f}\nMin: {:.3f}\nMax: {:.3f}".format(scores.mean(), scores.std(), scores.min(), scores.max()))
def cv_f1(model, x, y):
scores = cross_val_score(model, x, y, cv=5, scoring='f1'); scores
print("Mean: {:.3f}\nStd: {:.3f}\nMin: {:.3f}\nMax: {:.3f}".format(scores.mean(), scores.std(), scores.min(), scores.max()))
def cv_precision(model, x, y):
scores = cross_val_score(model, x, y, cv=5, scoring='precision'); scores
print("Mean: {:.3f}\nStd: {:.3f}\nMin: {:.3f}\nMax: {:.3f}".format(scores.mean(), scores.std(), scores.min(), scores.max()))
def cv_accuracy(model, x, y):
scores = cross_val_score(model, x, y, cv=5, scoring='accuracy'); scores
print("Mean: {:.3f}\nStd: {:.3f}\nMin: {:.3f}\nMax: {:.3f}".format(scores.mean(), scores.std(), scores.min(), scores.max()))
def cv_roc(model, x, y):
scores = cross_val_score(model, x, y, cv=5, scoring='roc_auc'); scores
print("Mean: {:.3f}\nStd: {:.3f}\nMin: {:.3f}\nMax: {:.3f}".format(scores.mean(), scores.std(), scores.min(), scores.max()))
|
cs |
'IT > 파이썬' 카테고리의 다른 글
GridSearchCV 그리드서치 1탄 (0) | 2020.12.21 |
---|---|
의사결정나무(Decision Tree) 그래프 그리기 (0) | 2020.12.10 |
ANOVA분석 & POST-HOC (사후검정) (0) | 2020.12.04 |
Chi-square test, Fisher's exact 검정 & post-hoc (0) | 2020.12.04 |
T-Test, levene test, 맨-휘트니 U 검정(Mann-Whitney U test) (0) | 2020.12.04 |