사전 교차 검증
알고리즘

교차 검증

gabury1고친 사람 github-actions[bot]

교차 검증은 모델이 처음 보는 데이터를 얼마나 맞힐지 가진 데이터만으로 재 보는 방법입니다. 데이터를 몇 조각으로 나눈 뒤 한 조각으로 채점하고 나머지로 학습하기를 조각마다 되풀이합니다. 결과는 조각마다 나온 점수와 그 평균입니다. 여러 출처로 사실을 맞대어 보는 일상의 교차 검증과는 다른 머신러닝 용어입니다.

쉽고 빠른 이해

교차 검증은 모델을 여러 번 나눠 채점해 보는 방법입니다. 스팸 메일 천 통이 있으면 이백 통씩 다섯 조각으로 나눕니다. 조각마다 한 번씩 채점용으로 돌립니다.

채점용 메일을 한 번만 떼어 두면 어떤 메일이 거기 들어갔느냐에 따라 점수가 크게 흔들립니다. 돌아가며 채점하면 모든 메일이 한 번씩 채점에 쓰입니다. 점수도 다섯 개가 나와서 평균을 낼 수 있습니다.

  1. 데이터를 다섯 조각으로 나눕니다
  2. 한 조각을 빼 두고 나머지 넷으로 학습합니다. 그 모델을 빼 둔 조각으로 채점합니다
  3. 빼 두는 조각을 바꿔 가며 다섯 번 되풀이하고 점수를 평균 냅니다

대가는 학습을 다섯 번 해야 한다는 점입니다. 모델 하나를 만드는 데 한 시간이 걸리면 다섯 시간이 듭니다. 그래서 데이터가 아주 많거나 학습이 며칠 걸리는 모델이면 한 번 떼어 두는 것으로 대신합니다.

상세

이 절은 스팸 메일 천 통을 가려내는 모델 하나를 끝까지 예로 듭니다.

모의고사를 한 번만 보면 그날 나온 문제와의 궁합이 점수를 흔듭니다. 잘 아는 단원만 나온 날은 점수가 높습니다. 약한 단원이 몰린 날은 낮습니다. 다섯 번 보고 평균을 내면 문제 운에 휘둘리는 몫이 줄어듭니다.

교차 검증도 채점을 여러 번 하고 평균을 냅니다. 새 데이터를 구해 오는 대신 가진 데이터를 조각으로 나눠 돌려 가며 채점에 씁니다.

모델과 채점

머신러닝에서 모델은 입력을 받아 답을 내는 함수입니다. 메일을 넣으면 「스팸」이나 「정상」을 내는 식입니다. 모델은 정답이 달린 예제를 보며 판정 기준을 고쳐 나갑니다. 이 과정이 학습입니다.

예제마다 달린 정답 표시를 레이블이라고 합니다. 사람이 메일마다 「스팸」이나 「정상」을 달아 둔 것이 레이블입니다.

채점은 모델의 답을 레이블과 맞대어 보는 일입니다. 가장 흔한 점수는 정확도입니다. 메일 이백 통 가운데 백팔십 통을 맞히면 정확도는 0.9입니다.

모델을 만드는 목적은 앞으로 들어올 새 메일을 맞히는 것입니다. 처음 보는 데이터에서도 잘 맞히는 성질을 일반화라고 합니다. 교차 검증이 재려는 것이 이 일반화 성능입니다.

학습에 쓴 메일로 채점하면 일반화를 못 잽니다. 모델이 그 메일들을 외워서 맞힐 수 있기 때문입니다. 학습 데이터에만 맞춰져 새 데이터에서 틀리는 상태를 과적합이라고 합니다. 그래서 채점은 학습에 안 쓴 데이터로 해야 합니다.

한 번만 떼어 두는 방법의 약점

가장 단순한 방법은 데이터 일부를 한 번 떼어 두는 것입니다. 천 통 가운데 이백 통을 떼어 두고 나머지 팔백 통으로 학습합니다. 떼어 둔 이백 통으로 한 번 채점합니다. 이 방법을 홀드아웃 검증이라고 부릅니다.

첫째 약점은 점수가 운을 탄다는 것입니다. 어려운 메일이 떼어 둔 쪽에 몰리면 점수가 낮게 나옵니다. 쉬운 메일이 몰리면 높게 나옵니다. 데이터가 적어 사십 통만 떼어 둘 수 있다면 한 통을 더 맞히고 덜 맞히는 것만으로 정확도가 0.025씩 움직입니다.

둘째 약점은 떼어 둔 데이터가 학습에 못 쓰인다는 것입니다. 데이터가 넉넉하면 괜찮습니다. 레이블 달린 메일이 백 통뿐이라면 스무 통을 빼는 것도 아깝습니다.

교차 검증은 이 두 약점을 함께 줄입니다. 떼어 두는 몫을 돌려 가며 바꾸면 모든 데이터가 한 번은 채점에 쓰입니다. 채점에 안 쓰이는 차례에는 학습에 쓰입니다. 채점도 여러 번 하므로 한 번의 운이 결과를 좌우하지 못합니다.

넣는 것과 나오는 것

교차 검증은 받는 것과 내놓는 것이 정해진 절차입니다. 아래 표가 그 둘입니다.

무엇 스팸 필터 예
넣는 것 레이블 달린 데이터 메일 천 통
넣는 것 학습 방법 메일에 든 단어 빈도로 스팸 여부를 매기는 모델, 설정값은 한 가지로 고정
넣는 것 조각 수 k 5
나오는 것 조각마다 하나씩 나온 점수 k 개와 그 평균 점수 다섯 개와 평균 0.9

표의 학습 방법 줄에 교차 검증의 성격이 드러납니다. 교차 검증이 받는 것은 다 만든 모델 하나가 아닙니다. 모델을 만드는 방법입니다. 그래서 교차 검증이 재는 것도 그 방법으로 모델을 만들었을 때 새 데이터에서 나올 점수입니다.

절차

데이터를 k 개로 나눈 조각을 겹(fold)이라고 부릅니다. 다섯 겹이면 k 는 5입니다. 아래 절차가 가장 기본인 k-겹 교차 검증입니다.

  1. 데이터를 섞은 뒤 크기가 같은 k 개 조각으로 나눕니다
  2. 첫째 조각을 빼 두고 나머지 조각을 모아 모델을 새로 학습합니다
  3. 빼 둔 조각으로 그 모델을 채점하고 점수를 적어 둡니다
  4. 빼 두는 조각을 둘째, 셋째로 바꿔 가며 2와 3을 k 번 합니다
  5. 적어 둔 점수 k 개의 평균을 냅니다

다섯 겹에서 회차마다 어느 조각이 무슨 일을 하는지 표로 보면 이렇습니다.

회차 조각 1 조각 2 조각 3 조각 4 조각 5
1 채점 학습 학습 학습 학습
2 학습 채점 학습 학습 학습
3 학습 학습 채점 학습 학습
4 학습 학습 학습 채점 학습
5 학습 학습 학습 학습 채점

표를 세로로 읽으면 어느 조각이든 채점에 딱 한 번 쓰입니다. 가로로 읽으면 회차마다 다섯 조각 가운데 넷이 학습에 쓰입니다. 모델은 회차마다 처음부터 새로 학습합니다. 앞 회차의 모델을 이어 쓰면 채점할 조각을 이미 본 모델이 됩니다.

같은 절차를 파이썬 꼴로 적으면 아래와 같습니다. fit 은 학습을, score 는 채점을 맡는 함수라고 둡니다.

Python
k = 5
n = len(mails)            # 1000
size = n // k             # 200

scores = []
for i in range(k):
    lo, hi = i * size, (i + 1) * size
    test = mails[lo:hi]           # 200
    train = mails[:lo] + mails[hi:]  # 800
    m = fit(train)
    scores.append(score(m, test))

반복문 한 바퀴가 표의 한 줄입니다. test 가 채점 칸이고 train 이 학습 칸 넷을 이어 붙인 것입니다.

결과를 읽는 법

반복문이 끝나면 점수 다섯 개가 남습니다. 평균은 새 데이터에서 나올 점수를 가늠한 값입니다. 가장 높은 점수와 가장 낮은 점수의 차이를 폭이라고 합니다. 폭은 점수가 얼마나 흔들리는지를 보여 줍니다.

Python
scores = [0.91, 0.88, 0.93, 0.86, 0.92]
round(sum(scores) / k, 2)            # 0.9
round(max(scores) - min(scores), 2)  # 0.07

평균이 0.9이고 폭이 0.07입니다. 홀드아웃 검증을 한 번만 했다면 이 다섯 점수 가운데 하나만 봤을 겁니다. 0.86을 봤는지 0.93을 봤는지에 따라 결론이 달라질 수 있었습니다.

흩어진 정도는 폭 말고 표준 편차로도 적습니다. 표준 편차는 점수들이 평균에서 얼마나 떨어져 있는지를 한 값으로 나타냅니다. 평균과 함께 적어 두면 두 학습 방법의 점수 차이가 흔들림보다 큰지 가늠할 수 있습니다.

회차마다 만든 모델 다섯 개는 채점이 끝나면 버립니다. 교차 검증은 학습 방법을 잰 것이기 때문입니다. 서비스에 내놓을 모델은 그 방법으로 데이터 전체를 써서 한 번 더 학습해 만듭니다.

조각 수와 비용

학습 한 번에 드는 시간을 T 라고 하면 k-겹 교차 검증은 대략 k 곱하기 T 만큼 듭니다. 채점에 드는 시간은 대개 학습보다 훨씬 짧아서 셈에서 뺍니다. 다섯 겹이면 다섯 배, 열 겹이면 열 배입니다.

메모리는 회차를 하나씩 돌리면 모델 하나만큼만 씁니다. 회차끼리는 서로 기대는 것이 없습니다. 그래서 컴퓨터가 여럿이면 k 회차를 동시에 돌려 걸리는 시간을 줄일 수 있습니다.

k 를 키우면 회차마다 학습에 쓰는 데이터가 전체에 가까워집니다. 그만큼 전체 데이터로 학습한 최종 모델과 비슷한 조건에서 잽니다. 대신 학습 횟수가 늘어납니다.

k 회차마다 학습에 쓰는 몫 학습 횟수
2 절반 2
5 다섯 중 넷 5
10 열 중 아홉 10
데이터 건수 n 한 건만 빼고 전부 n

흔히 5나 10을 씁니다. 마지막 줄처럼 한 건씩 빼는 방식은 leave-one-out 교차 검증이라고 따로 부릅니다. 학습을 데이터 건수만큼 해야 하므로 데이터가 아주 적을 때 씁니다.

쓰는 때와 건너뛰는 때

교차 검증은 주로 데이터가 많지 않을 때 씁니다. 레이블 달린 데이터가 수백에서 수천 건이면 한 번 떼어 둔 점수가 크게 흔들립니다. 이때 여러 번 재서 평균을 내면 흔들림이 줄어듭니다.

데이터가 아주 많으면 한 번 떼어 두는 것으로 충분합니다. 백만 건에서 만 건을 떼어도 점수가 잘 안 흔들립니다. 학습에 며칠씩 걸리는 큰 모델도 교차 검증을 건너뛰는 경우가 많습니다. 학습을 k 번 되풀이하는 비용을 감당하기 어렵기 때문입니다.

데이터 모양에 맞춰 나누기

기본 절차는 데이터를 무작위로 섞어 나눕니다. 데이터에 따라서는 그렇게 나누면 점수가 부풀거나 흔들립니다. 그럴 때 쓰는 나누는 법을 이름만 짚습니다.

표에 나오는 클래스는 모델이 고르는 갈래입니다. 스팸 필터라면 「스팸」과 「정상」이 두 클래스입니다.

데이터 모양 나누는 법 이름
드문 클래스가 있다 조각마다 클래스 비율을 전체와 같게 맞춘다 층화 k-겹 교차 검증
시간 순서가 있다 과거 조각으로 학습하고 그 뒤 조각으로 채점한다 시계열 교차 검증
한 사람이 여러 건을 남겼다 한 사람의 데이터를 한 조각에 몰아넣는다 그룹 k-겹 교차 검증

메일 백 통에 스팸이 두 통꼴이면 어떤 조각에는 스팸이 하나도 안 들어갈 수 있습니다. 그 조각의 채점은 스팸을 가려내는 능력을 못 잽니다. 층화 k-겹 교차 검증은 조각마다 스팸을 같은 비율로 넣어 이 일을 막습니다.

시간 순서가 있는 데이터를 무작위로 섞으면 다음 달 메일로 학습한 모델이 이번 달 메일을 채점받게 됩니다. 실제로 쓸 때 모델은 앞으로 올 메일을 본 적이 없습니다. 그러니 섞어 나누면 점수가 실제보다 좋게 나옵니다.

한 사람이 여러 건을 남긴 데이터에서는 모델이 사람의 버릇을 외워서 맞힐 수 있습니다. 같은 사람의 메일이 학습 조각과 채점 조각에 나뉘어 들어가면 점수가 부풉니다.

테스트 세트와 함께 쓰기

교차 검증은 흔히 후보 여럿 가운데 하나를 고를 때 씁니다. 후보는 학습 전에 사람이 정하는 설정값을 바꿔 가며 만듭니다. 이 설정값을 하이퍼파라미터라고 합니다. 설정마다 교차 검증 평균을 구하고 가장 높은 설정을 고릅니다.

고르는 일 자체가 점수를 부풀립니다. 후보 스무 개를 견주면 우연히 이 데이터와 잘 맞은 후보가 뽑히기 쉽습니다. 그래서 뽑힌 설정의 교차 검증 평균은 새 데이터에서의 점수보다 높게 나오기 쉽습니다.

이 부풀림을 피하려고 고르는 데 한 번도 안 쓴 테스트 세트를 맨 먼저 떼어 둡니다. 교차 검증은 남은 데이터 안에서만 돌립니다.

flowchart TD
    D["레이블 달린 데이터"] --> S["테스트 세트 · 먼저 떼어 둔다"]
    D --> R["남은 데이터"]
    R --> C["설정마다 교차 검증 평균을 구한다"]
    C --> P["평균이 가장 높은 설정을 고른다"]
    P --> F["고른 설정으로 남은 데이터 전체를 학습한다"]
    F --> E["테스트 세트로 한 번 잰다"]
    S --> E

그림에서 테스트 세트는 처음에 갈라진 뒤 마지막 채점까지 아무 데도 안 들릅니다. 교차 검증은 가운데의 고르는 단계에만 쓰입니다. 데이터가 너무 적어 테스트 세트를 뗄 수 없으면 교차 검증 안에 교차 검증을 한 번 더 넣는 중첩 교차 검증을 씁니다.

조각마다 따로 해야 하는 전처리

학습 전에 데이터를 손보는 일을 전처리라고 합니다. 전처리 가운데는 데이터에서 값을 구해 쓰는 것이 있습니다. 이 절은 그런 전처리를 교차 검증에서 어떻게 하는지 표준화로 봅니다.

표준화는 흔히 쓰는 전처리입니다. 값마다 평균을 빼고 표준 편차로 나눠 크기를 맞춥니다. 메일 길이와 링크 개수처럼 단위가 다른 값을 견줄 수 있게 하려는 것입니다. 이때 쓰는 평균은 데이터에서 구합니다.

교차 검증에서는 이 평균을 회차마다 학습 조각에서만 구해야 합니다. 데이터 전체에서 한 번 구해 두면 채점 조각의 값이 평균에 섞여 들어갑니다. 채점할 데이터를 학습 쪽이 미리 엿본 셈이 되어 점수가 부풉니다. 이런 일을 데이터 누수라고 합니다.

채점 조각도 표준화는 합니다. 학습 조각에서 구한 평균을 채점 조각에도 그대로 써서 빼 줍니다.

관련 항목

교차 검증이 나눠 쓰는 데이터 세트

훈련 세트 · 검증 세트 · 테스트 세트 · 홀드아웃 검증 · 데이터 분할

교차 검증의 하위 종류

k-겹 교차 검증 · 층화 k-겹 교차 검증 · leave-one-out 교차 검증 · 시계열 교차 검증 · 그룹 k-겹 교차 검증 · 중첩 교차 검증 · 반복 k-겹 교차 검증

교차 검증으로 드러내거나 막는 문제

과적합 · 데이터 누수 · 일반화 오차 · 편향과 분산 · 표본 편향

교차 검증 점수로 고르는 설정과 모델

하이퍼파라미터 · 하이퍼파라미터 튜닝 · 그리드 탐색 · 모델 선택 · 특성 선택

교차 검증으로 재는 평가 지표

정확도 · 정밀도 · 재현율 · F1 점수 · 오차율 · 평균 제곱 오차

교차 검증처럼 데이터를 다시 뽑아 쓰는 통계 기법

재표본추출 · 부트스트랩 · 잭나이프 · 순열 검정

교차 검증이 속하는 상위 분야

머신러닝 · 지도 학습 · 모델 평가 · 통계학

교차 검증 함수를 내장한 라이브러리

scikit-learn · XGBoost · LightGBM · caret

다른 이름: cross-validation · 교차검증