# 홀드아웃(hold-out)방법
# -----------------------------------
# 홀드아웃(hold-out)방법으로 검증 데이터의 분할
from sklearn.model_selection import train_test_split
# train_test_split()함수를 이용한 홀드아웃 방법으로 분할
tr_x, va_x, tr_y, va_y = train_test_split(train_x, train_y,
test_size=0.25, random_state=71, shuffle=True)
# -----------------------------------
# 홀드아웃(hold-out)방법으로 검증을 수행
from sklearn.metrics import log_loss
from sklearn.model_selection import train_test_split
# Model 클래스를 정의
# Model 클래스는 fit으로 학습하고 predict로 예측값 확률을 출력
# train_test_split 함수를 이용하여 홀드아웃 방법으로 분할
tr_x, va_x, tr_y, va_y = train_test_split(train_x, train_y,
test_size=0.25, random_state=71, shuffle=True)
# 학습 실행, 검증 데이터 예측값 출력, 점수 계산
model = Model()
model.fit(tr_x, tr_y, va_x, va_y)
va_pred = model.predict(va_x)
score = log_loss(va_y, va_pred)
print(score)
# -----------------------------------
# KFold 클래스를 이용하여 홀드아웃 방법으로 검증 데이터를 분할
from sklearn.model_selection import KFold
# KFold 클래스를 이용하여 홀드아웃 방법으로 분할
kf = KFold(n_splits=4, shuffle=True, random_state=71)
tr_idx, va_idx = list(kf.split(train_x))[0]
print(tr_idx, va_idx)
tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]
tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
# 교차 검증 방법으로 데이터 분할
from sklearn.model_selection import KFold
# KFold 클래스를 이용하여 교차 검증 분할을 수행
kf = KFold(n_splits=4, shuffle=True, random_state=71)
for tr_idx, va_idx in kf.split(train_x):
tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]
tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
# 교차 검증을 수행
from sklearn.metrics import log_loss
from sklearn.model_selection import KFold
# Model 클래스를 정의
# Model 클래스는 fit으로 학습하고, predict로 예측값 확률을 출력
scores = []
# KFold 클래스를 이용하여 교차 검증 방법으로 분할
kf = KFold(n_splits=4, shuffle=True, random_state=71)
for tr_idx, va_idx in kf.split(train_x):
tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]
tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
# 학습 실행, 검증 데이터의 예측값 출력, 점수 계산
model = Model()
model.fit(tr_x, tr_y, va_x, va_y)
va_pred = model.predict(va_x)
score = log_loss(va_y, va_pred)
scores.append(score)
# 각 폴더의 점수 평균을 출력
print(np.mean(scores))
from sklearn.model_selection import StratifiedKFold
# StratifiedKFold 클래스를 이용하여 층화추출로 데이터 분할
kf = StratifiedKFold(n_splits=4, shuffle=True, random_state=71)
for tr_idx, va_idx in kf.split(train_x, train_y):
tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]
tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
from sklearn.model_selection import KFold, GroupKFold
# user_id열의 고객 ID 단위로 분할
user_id = train_x['user_id']
unique_user_ids = user_id.unique()
# KFold 클래스를 이용하여 고객 ID 단위로 분할
scores = []
kf = KFold(n_splits=4, shuffle=True, random_state=71)
for tr_group_idx, va_group_idx in kf.split(unique_user_ids):
# 고객 ID를 train/valid(학습에 사용하는 데이터, 검증 데이터)로 분할
tr_groups, va_groups = unique_user_ids[tr_group_idx], unique_user_ids[va_group_idx]
# 각 샘플의 고객 ID가 train/valid 중 어느 쪽에 속해 있느냐에 따라 분할
is_tr = user_id.isin(tr_groups)
is_va = user_id.isin(va_groups)
tr_x, va_x = train_x[is_tr], train_x[is_va]
tr_y, va_y = train_y[is_tr], train_y[is_va]
# (참고)GroupKFold 클래스에서는 셔플과 난수 시드를 지정할 수 없으므로 사용하기 어려움
kf = GroupKFold(n_splits=4)
for tr_idx, va_idx in kf.split(train_x, train_y, user_id):
tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]
tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
from sklearn.model_selection import LeaveOneOut
loo = LeaveOneOut()
for tr_idx, va_idx in loo.split(train_x):
tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]
tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
추가로, LOO 검증의 경우 GBDT나 신경망과 같이 순서대로 학습을 진행하는 모델에서 조기 종료를 사용하면 검증 데이터에 가장 최적의 포인트에서 학습을 멈출 수 있어 모델의 성능이 과대 평가된다.
LOO 검증이 아니더라도 폴드 수가 많아지면 과적합 문제가 발생할 수 있다. 대처 방법 중 하나로는 각 폴드에서 한 번 조기 종료하고, 그 평군 등으로부터 적절한 반복수의 견적을 낸 뒤에 해당 반복 수를 고정하고 다시 교차 검증을 실행하는 방법이 있다.
다만 데이터가 주기성을 갖는다면 데이터 나눌 때 이를 고려해야한다. 예를 들면 1년 단위로 주기성이 강한 데이터일 때는 가장 최근 데이터보다 테스트 데이터의 1년 전 기간을 검증 데이터로 삼는 편이 나을 수 있다.
이 방법은 홀드아웃 검증의 응용이므로 마찬가지로 데이터를 유효하게 사용하지 못한다는 단점이 있다. 검증 데이터는 어느 기간으로 한정되는 만큼 그 밖의 기간을 적절히 예측할 수 있는 모델인지 여부를 확인하기 어렵고, 단순히 검증 데이터의 수가 부족하여 결과가 안정되지 않을 수도 있다.
# 변수 period를 기준으로 분할(0부터 2까지가 학습 데이터, 3이 테스트 데이터)
# 변수 period가 1, 2, 3의 데이터를 각각 검증 데이터로 하고 그 이전 데이터를 학습에 사용
va_period_list = [1, 2, 3]
for va_period in va_period_list:
is_tr = train_x['period'] < va_period
is_va = train_x['period'] == va_period
tr_x, va_x = train_x[is_tr], train_x[is_va]
tr_y, va_y = train_y[is_tr], train_y[is_va]
# (참고)periodSeriesSplit의 경우, 데이터 정렬 순서밖에 사용할 수 없으므로 쓰기 어려움
from sklearn.model_selection import TimeSeriesSplit
tss = TimeSeriesSplit(n_splits=4)
for tr_idx, va_idx in tss.split(train_x):
tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]
tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
참고 : 데이터가 뛰어노는 AI 놀이터, 캐글