교차 검증의 정보 누설

The Elements of Statistical Learning (Hastie, Springer, 2016) 파이썬 라이브러리를 활용한 머신러닝 (안드레아스 뮐러 저, 박해선 역, 한빛미디어, 2017)

Improper Preprocessing

교차 검증에서 검증 폴드 데이터의 정보가 모델 구축 과정에 누설되면 교차 검증에서 낙관적인 결과가 만들어진다. 아래 그림에서는 파라미터 선택을 위해 scaler.fitSVC.predict가 모두 검증 폴드를 사용하고 있다. 하지만 모델의 성능을 평가할 때는 scaler.fit이 테스트 세트에 적용되지 않는다. (아래와 같은 문제를 해결하기 위해 Pipeline을 사용한다.)

mage-20180401155447

[Pipeline 사용 예시]

1
2
3
4
5
6
7
8
9
# MinMaxScaler와 SVC를 Pipeline으로 연결하고
# GridSearchCV에 Pipeline을 적용

pipe = Pipeline([("Scaler", MinMaxScaler()), ("svm", SVC())])
pipe.fit(X_train, y_train)
param_grid = {"svm__C": [0.001, 0.01, 0.1, 1, 10, 100], 
              "svm__gamma": [0.001, 0.01, 0.1, 1, 10, 100]}
grid = GridSearchCV(pipe, param_grid=param_grid, cv=5)
grid.fit(X_train, y_train)

교차 검증에서 정보 누설의 영향

무작위로 생성된 X와 y에는 아무런 관계가 없다. (독립)

1
2
3
4
5
# 정규분포로부터 독립적으로 추출한 10,000개의 특성을 가진 샘플 100개

rnd = np.random.RandomState(seed=0)
X = rnd.normal(size=(100, 10000))
y = rnd.normal(size=(100,))

아래와 같이 피처를 선택하고 학습을 시키면 다음과 같은 점수를 얻는다.

1
2
3
4
5
6
7
8
9
10
11
12
# SelectPercentile로 유용한 피처를 선택하고 교차 검증을 사용해 Ridge 회귀 평가

from sklearn.feature_selection import SelectPercentile, f_regression

select = SelectPercentile(score_func=f_regression, percentile=5).fit(X, y)
X_selected = select.transform(X)
print("X_selected.shape: {}".format(X_selected.shape)) # (100, 500)

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import Ridge
print("CV Score (Ridge): {:.2f}".format(
    np.mean(cross_val_score(Ridge(), X_selected, y, cv=5))))
1
CV Score (Ridge): 0.91

$R^2​$가 0.91로 매우 좋은 모델이라고 생각할 수 있지만, 데이터셋을 무작위로 만들었기 때문에 불가능한 일이다. 교차 검증 밖에서 특성을 선택했기 때문에 훈련과 테스트 폴드 양쪽에 연관된 특성이 찾아질 수 있다. 테스트 폴드에서 유출된 정보는 매우 중요한 역할을 하기 때문에 비현실적으로 높은 결과가 나왔다. 이 결과를 Pipeline을 이용한 교차 검증과 비교하면 다음과 같다.

1
2
3
4
5
pipe = Pipeline([("select", SelectPercentile(score_func=f_regression, 
                                             percentile=5)), 
                 ("ridge", Ridge())])
print("CV score (Pipeline): {:.2f}".format(
    np.mean(cross_val_score(pipe, X, y, cv=5))))
1
CV score (Pipeline): -0.25

이번에는 $R^2$가 음수로 성능이 매우 나쁘 모델임을 나타낸다. Pipeline을 사용했기 때문에 특성 선택이 교차 검증 반복 안으로 들어갔다. 즉, 훈련 폴드를 사용해서만 특성이 선택되었고 테스트 폴드는 사용되지 않았다는 뜻이다. 특성 선택 단계에서 타깃값과 연관된 훈련 폴드의 특성을 찾았지만 전체 데이터가 무작위로 만들어졌으므로 테스트 폴드의 타깃과는 연관성이 없다. 이는 특성 선택 단계에서 일어나는 정보 누설을 막는 것이 모델의 성능을 평가하는 데 큰 차이를 만든다는 것을 보여준다.