글 목록
#1 불균형한 데이터 분포 전처리하기
#2 (Random Forest) train-test 분할 및 간단한 모델 학습
#3 Validation 데이터 분할, K-fold 교차검증
1. Validation 데이터 분할
- 사이킷런의 model_selection의 train_test_split을 활용
(여기서 'test'이라는 표현에 혼동이 있을 수 있으나 'validation'의 의미로 생각하면 됨)
- stratify
- 기존에 train과 test로만 분리된 데이터를 => train, val, test의 세 가지로 나눔
(train에서 일정 비율을 떼어내 val 데이터로 만듦)
train_x |
train_y |
val_x |
val_y |
test_x |
test_y |
from sklearn.model_selection import train_test_split
X_train, X_val, Y_train, Y_val = train_test_split(train_x, train_y,
stratify = train_y,
test_size = 0.25,
random_state = 10086)
#'stratify = train_y': train_y에 존재하는 요소의 비율을 고려하여, 검증셋과 훈련셋을 분할함
# 직접 데이터명 지정하여 따로 저장함
아까 방법 그대로. clf 분류기를 학습시켜보자!
이후, (최종 test 데이터에 대한 예측 전), valid 데이터에 대한 예측을 우선적으로 진행해보자.
clf = RandomForestClassifier()
clf.fit(X_train, Y_train)
Y_proba = clf.predict_proba(X_val) #학습한 분류기의 예측 결과
val 데이터에 대한 모델의 예측 점수(성능)을 계산해보자.
- 사이킷런의 함수 통해 점수 반환하려면, Y_val을 원핫인코딩 형태로 변환해야 함.
pandas의 get.dummies()
- val에 대한 점수 반환해보기
사이킷런의 metrics의 log_loss 함수 이용
log_loss(정답, 예측값)
Y_val_onehot = pd.get_dummies(Y_val) #실제 정답지의 원핫인코딩 버전
from sklearn.metrics import log_loss #val에 대한 logloss 점수 반환
log_loss(Y_val_onehot, Y_proba)
2. K-fold 교차검증
2.1 Fold 생성
상대적으로 데이터량이 충분하지 않은 경우, 머신러닝에서는 나에게 주어진 데이터를 얼마나 효율적이고 효과적으로 사용해내느냐가 중요하다. 이때 활용할 수 있는 것이 'K-fold 교차검증'이다.
- 과적합 방지 위한 툴
- 데이터를 k개의 폴드로 쪼개어 하나씩 돌아가며 valid data를 수행함 => k개 경우의 성능 평균을 산출
- 사이킷런의 model_selection에서 (Stratified)KFold 사용
StratifiedKFold(n_splites = n, shuffle = True, randome_state = n)
각 데이터의 인덱스 숫자를 기준으로.
from sklearn.model_selection import StratifiedKFold
#단순 KFold를 사용할 수 있지만 stratified가 추가된 버전을 사용하자!
folds = StratifiedKFold(n_splits=5, shuffle=True, random_state=55)
#KFold 생성기 생성=> 이후 folds.split(~)과 같은 방식으로 데이터를 쪼갬
잠깐, StratifiedKFold가 어떠한 방식으로 데이터를 쪼개는지 간단히 살펴보자.
K개의 폴드가 생성되므로, 쪼개는 경우의 수 역시 K일 것이다. 그 가운데 첫 번째 경우는 이하와 같이 쪼개진다.
(array([ 0, 1, 2, ..., 26454, 26455, 26456]), #train_index에 해당
array([ 4, 12, 23, ..., 26442, 26443, 26446])) #val_index에 해당
따라서 iloc을 이용하면 train에 해당하는 데이터와 val에 해당하는 데이터를 '인덱스'를 기준으로 쪼갤 수 있다.
KFold를 생성하고 각 경우에 대한 학습 성능을 산출하는 일련의 과정을 for문으로 합쳐보자.
2.2 for문으로 합치기: 각 폴드에서의 예측 점수를 반환
- enumerate : 출력되는 현재 for문에 몇번째에 대한 for문인지 알려줌
- 각각의 학습이 서로 독립적으로 이루어지도록, classifier를 매번 새롭게 선언해야 함.
- 문자열 formatting 문법 기억!"%d번째 학습 결과는 %.4f점 입니다.\n\n"%(n_fold+1,score)
https://studymake.tistory.com/179
scores = []
n_splits=5
folds = StratifiedKFold(n_splits=5, shuffle=True, random_state=55)
#각각의 학습이 서로 독립적으로 이루어지도록, classifier를 매번 새롭게 선언해야 함.
for n_fold, (train_index, val_index) in enumerate(folds.split(train_x, train_y)):
X_train, X_val = train_x.iloc[train_index], train_x.iloc[val_index]
Y_train, Y_val = train_y.iloc[train_index], train_y.iloc[val_index]
clf = RandomForestClassifier()
clf.fit(X_train, Y_train)
Y_val_proba = clf.predict_proba(X_val)
Y_val_onehot = pd.get_dummies(Y_val)
score = log_loss(Y_val_onehot, Y_val_proba)
print("%d번째 학습 결과는 %.4f점 입니다.\n\n"%(n_fold+1,score))
scores.append(score)
if n_fold+1 == n_splits:
avg_score = sum(scores)/n_splits #numpy통해 np.mean(scores)로 바로 구할 수 있음.
print("평균 점수는 %.4f점 입니다!"%avg_score)
break
>>> 1번째 학습 결과는 1.0524점 입니다.
2번째 학습 결과는 1.0799점 입니다.
3번째 학습 결과는 1.1412점 입니다.
4번째 학습 결과는 1.0329점 입니다.
5번째 학습 결과는 1.0653점 입니다.
평균 점수는 1.0743점 입니다!
2.3 최종 Test (앙상블)
KFold를 사용함에 따라, 주어진 데이터로 총 K번의 서로 다른 학습을 진행할 수 있게 되었다.
이같은 방식으로 랜덤포레스트 classifier를 튜닝하고, 더 좋은 성능의 모델을 만들 수 있다.
=> 이때 각 fold별 모델을 test 데이터에 대한 추론으로 바로 사용하여 제출물을 만들 수도 있다. (= 앙상블)
=> 1개밖에 없던 분류기를 -> k개로 늘린 것 -> val은 각 분류기의 성능을 대략 예측해줌 -> 동일한 test 데이터에 대해 각 분류기가 k가지의 서로 다른 예측 결과를 반환함
➡️모델 전체에 대한 최종 성능 = mean(k개의 성능 점수)
➡️모델이 test에 대해 최종 예측한 결과 = mean(k개의 예측 결과)
scores = []
sub = np.zeros((test_x.shape[0],3)) # 제출해야 하는 값: test_x의 row X 3개의 columns
#각각의 학습이 서로 독립적으로 이루어지도록, classifier를 매번 새롭게 선언해야 함.
for n_fold, (train_index, val_index) in enumerate(folds.split(train_x, train_y)):
X_train, X_val = train_x.iloc[train_index], train_x.iloc[val_index]
Y_train, Y_val = train_y.iloc[train_index], train_y.iloc[val_index]
clf = RandomForestClassifier()
clf.fit(X_train, Y_train)
Y_val_proba = clf.predict_proba(X_val)
Y_val_onehot = pd.get_dummies(Y_val)
sub += clf.predict_proba(test_x) #얘랑
score = log_loss(Y_val_onehot, Y_val_proba)
scores.append(score) #얘랑 구분하기!!
sub = sub / 5
np.mean(scores) #fold별 추론 값들의 평균 (다섯 번의 추론 결과 평균)
sample_submission.to_csv("5fold_prediction.csv", index=False)
출처
https://www.youtube.com/watch?v=fBBHiShcJZo&list=LL&index=3
가쟈가쟈가쟈~