🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

교차 검증 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 3. · 11 Views

교차 검증 완벽 가이드

머신러닝 모델의 성능을 제대로 평가하는 방법, 교차 검증에 대해 알아봅니다. 데이터를 여러 번 나누어 검증하는 기법으로 과적합을 방지하고 신뢰할 수 있는 모델 성능을 측정하는 핵심 기술입니다.


목차

  1. 교차 검증의 필요성
  2. K-Fold 교차 검증
  3. Stratified K-Fold
  4. Leave-One-Out 검증
  5. cross_val_score 사용법
  6. 교차 검증 결과 해석

1. 교차 검증의 필요성

김개발 씨는 회사에서 고객 이탈 예측 모델을 만들었습니다. 학습 데이터에서 정확도가 95%나 나와서 자신만만하게 보고했는데, 실제 서비스에 적용하니 정확도가 60%로 뚝 떨어졌습니다.

대체 무엇이 문제였을까요?

교차 검증은 한마디로 모델의 진짜 실력을 테스트하는 방법입니다. 마치 수능 모의고사를 여러 번 보면서 실전 감각을 키우는 것과 같습니다.

하나의 시험 결과만으로 실력을 판단하지 않고, 여러 번의 시험을 통해 평균적인 실력을 파악하는 것이 교차 검증의 핵심입니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris

# 데이터 로드
iris = load_iris()
X, y = iris.data, iris.target

# 일반적인 train/test 분할의 문제점
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)

# 이 점수는 어떤 데이터가 테스트셋에 들어갔느냐에 따라 크게 달라집니다
score = model.score(X_test, y_test)
print(f"단일 분할 정확도: {score:.4f}")

김개발 씨는 입사 6개월 차 데이터 분석가입니다. 팀장님이 고객 이탈 예측 모델을 만들어달라고 요청하셨고, 김개발 씨는 일주일 동안 열심히 모델을 학습시켰습니다.

결과는 놀라웠습니다. 학습 데이터에서 정확도 95%라니!

김개발 씨는 뿌듯한 마음으로 결과를 보고했습니다. 하지만 실제 서비스에 적용하자마자 문제가 터졌습니다.

정확도가 60%밖에 되지 않는 것이었습니다. 선배 박시니어 씨가 다가와 물었습니다.

"혹시 과적합 검증은 해봤어요?" 과적합이란 무엇일까요? 쉽게 비유하자면, 시험 전날 기출문제만 달달 외운 학생과 같습니다.

그 학생은 기출문제 시험에서는 100점을 받겠지만, 조금만 문제가 바뀌면 손도 못 대게 됩니다. 모델도 마찬가지입니다.

학습 데이터에 너무 맞춰져 있으면 새로운 데이터에는 제대로 대응하지 못합니다. 그렇다면 어떻게 해야 진짜 실력을 알 수 있을까요?

일반적으로 데이터를 학습용테스트용으로 나눕니다. 보통 80%는 학습에, 20%는 테스트에 사용합니다.

하지만 여기에 함정이 있습니다. 어떤 데이터가 테스트셋에 들어가느냐에 따라 점수가 크게 달라질 수 있습니다.

운 좋게 쉬운 데이터가 테스트셋에 들어가면 점수가 높게 나옵니다. 반대로 어려운 데이터가 들어가면 점수가 낮게 나옵니다.

이것은 마치 모의고사를 딱 한 번만 보고 수능 점수를 예측하는 것과 같습니다. 박시니어 씨가 해결책을 알려주었습니다.

"교차 검증을 사용해보세요. 데이터를 여러 번 다르게 나누어서 검증하는 방법이에요." 교차 검증은 데이터를 K개의 조각으로 나눈 뒤, 각 조각이 한 번씩 테스트셋이 되도록 K번 학습과 검증을 반복합니다.

그리고 K번의 점수를 평균 내어 최종 성능을 계산합니다. 이렇게 하면 운에 의한 편차를 줄일 수 있습니다.

모의고사를 5번, 10번 보면 실력을 더 정확히 파악할 수 있는 것처럼요. 김개발 씨는 고개를 끄덕였습니다.

"아, 그래서 한 번의 테스트 결과만 믿으면 안 되는 거군요!" 그렇습니다. 머신러닝에서 신뢰할 수 있는 성능 평가는 좋은 모델을 만드는 것만큼 중요합니다.

교차 검증은 그 첫걸음입니다.

실전 팁

💡 - 학습 데이터와 테스트 데이터는 반드시 분리하세요

  • 한 번의 검증 결과만으로 모델 성능을 판단하지 마세요

2. K-Fold 교차 검증

박시니어 씨가 화이트보드에 그림을 그리기 시작했습니다. "자, 데이터를 케이크처럼 5조각으로 나눈다고 생각해봐요." 김개발 씨는 본격적으로 교차 검증의 가장 기본적인 방법을 배우기 시작했습니다.

K-Fold 교차 검증은 데이터를 K개의 동일한 크기로 나누어 검증하는 방법입니다. 마치 돌아가면서 조별 발표를 하는 것처럼, 각 조각이 한 번씩 테스트셋 역할을 맡습니다.

K번의 실험 결과를 평균 내면 더 신뢰할 수 있는 성능 지표를 얻을 수 있습니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
import numpy as np

iris = load_iris()
X, y = iris.data, iris.target

# 5-Fold 교차 검증 설정
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
model = RandomForestClassifier(random_state=42)
scores = []

# 각 폴드별로 학습과 검증 수행
for fold, (train_idx, test_idx) in enumerate(kfold.split(X), 1):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    model.fit(X_train, y_train)
    score = model.score(X_test, y_test)
    scores.append(score)
    print(f"Fold {fold}: {score:.4f}")

print(f"평균 정확도: {np.mean(scores):.4f} (+/- {np.std(scores):.4f})")

박시니어 씨가 화이트보드 앞에 섰습니다. "자, K-Fold가 어떻게 동작하는지 그림으로 설명해줄게요." 화이트보드에 긴 막대가 그려졌습니다.

박시니어 씨가 그 막대를 5등분으로 나누었습니다. "이게 우리 데이터라고 생각해봐요.

5-Fold 교차 검증을 하려면 데이터를 5개의 폴드로 나눕니다." 첫 번째 실험에서는 1번 폴드가 테스트셋이 됩니다. 나머지 2, 3, 4, 5번 폴드로 모델을 학습시키고, 1번 폴드로 성능을 측정합니다.

두 번째 실험에서는 2번 폴드가 테스트셋이 됩니다. 이번에는 1, 3, 4, 5번 폴드로 학습하고, 2번 폴드로 검증합니다.

이런 식으로 5번의 실험을 진행하면 모든 데이터가 한 번씩은 테스트에 사용됩니다. 마치 학교에서 돌아가면서 조별 발표를 하는 것과 같습니다.

모든 조가 한 번씩 발표자가 되는 것처럼, 모든 데이터가 한 번씩 테스트 역할을 맡습니다. 김개발 씨가 질문했습니다.

"그런데 K는 보통 얼마로 설정하나요?" 박시니어 씨가 답했습니다. "가장 흔히 사용하는 값은 510이에요.

K가 너무 작으면 검증의 신뢰도가 떨어지고, 너무 크면 계산 시간이 오래 걸려요." 또 한 가지 중요한 설정이 있습니다. 바로 shuffle 옵션입니다.

데이터가 특정 순서로 정렬되어 있을 수 있기 때문에, 나누기 전에 섞어주는 것이 좋습니다. 예를 들어, 앞쪽에는 클래스 A만, 뒤쪽에는 클래스 B만 있다면 섞지 않으면 각 폴드의 구성이 편향될 수 있습니다.

코드를 살펴보면 KFold 클래스를 생성할 때 n_splits=5로 5개의 폴드를 지정합니다. shuffle=True로 데이터를 미리 섞고, random_state를 지정해 재현성을 확보합니다.

split 메서드는 각 폴드의 학습용 인덱스와 테스트용 인덱스를 반환합니다. 이 인덱스를 사용해 데이터를 나누고 모델을 학습시킵니다.

5번의 실험이 끝나면 각 폴드별 점수와 함께 평균 점수를 계산합니다. 표준편차도 함께 출력하면 점수의 변동성을 파악할 수 있습니다.

김개발 씨가 눈을 빛냈습니다. "아, 평균만 보는 게 아니라 표준편차도 중요하군요!" 그렇습니다.

평균 점수가 90%라도 표준편차가 10%라면 폴드마다 결과가 크게 다르다는 의미입니다. 이는 모델이 불안정하다는 신호일 수 있습니다.

실전 팁

💡 - K값은 보통 5나 10을 사용하며, 데이터가 적으면 더 큰 K를 고려하세요

  • shuffle=True로 데이터를 섞어주면 편향을 방지할 수 있습니다

3. Stratified K-Fold

김개발 씨가 실제 프로젝트에 K-Fold를 적용했는데 이상한 결과가 나왔습니다. 어떤 폴드에서는 정확도가 90%인데, 어떤 폴드에서는 50%밖에 안 됩니다.

알고 보니 데이터의 클래스 비율이 불균형했던 것이 문제였습니다.

Stratified K-Fold는 각 폴드에서 클래스 비율을 원본 데이터와 동일하게 유지하는 방법입니다. 마치 여론조사에서 연령대별로 인원을 맞춰서 샘플링하는 것처럼, 각 폴드가 전체 데이터의 축소판이 되도록 보장합니다.

클래스 불균형 데이터에서 특히 중요한 기법입니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
import numpy as np

# 불균형 데이터 생성 (클래스 비율 9:1)
X, y = make_classification(n_samples=1000, n_classes=2,
                           weights=[0.9, 0.1], random_state=42)

# Stratified K-Fold 설정
skfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
model = RandomForestClassifier(random_state=42)
scores = []

for fold, (train_idx, test_idx) in enumerate(skfold.split(X, y), 1):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    model.fit(X_train, y_train)
    score = model.score(X_test, y_test)
    # 각 폴드의 클래스 비율 확인
    ratio = np.mean(y_test)
    print(f"Fold {fold}: 정확도={score:.4f}, 양성 비율={ratio:.2f}")

김개발 씨가 이상한 현상을 발견했습니다. 같은 모델인데 폴드마다 점수 차이가 너무 큽니다.

90%가 나오는 폴드도 있고, 50%가 나오는 폴드도 있습니다. 박시니어 씨가 데이터를 살펴보았습니다.

"아, 이건 클래스 불균형 때문이네요. 데이터에서 정상 고객이 90%, 이탈 고객이 10%밖에 안 되죠?" 문제가 뭘까요?

일반 K-Fold는 데이터를 무작위로 나눕니다. 운이 나쁘면 어떤 폴드에는 이탈 고객이 거의 없을 수도 있습니다.

그러면 그 폴드로는 이탈 예측 성능을 제대로 평가할 수 없습니다. 비유하자면 여론조사와 같습니다.

전체 국민의 의견을 알고 싶은데, 우연히 특정 연령대만 조사하면 결과가 편향됩니다. 그래서 여론조사에서는 연령대, 지역, 성별 등을 고려해서 층화 샘플링을 합니다.

Stratified K-Fold가 바로 이 층화 샘플링을 적용한 것입니다. 각 폴드에서 클래스 비율이 원본 데이터와 동일하도록 보장합니다.

원본 데이터가 정상 90%, 이탈 10%라면, 모든 폴드에서도 정상 90%, 이탈 10%가 유지됩니다. 이렇게 하면 매 폴드에서 공정한 평가가 가능합니다.

코드를 보면 KFold 대신 StratifiedKFold를 사용합니다. 사용법은 거의 동일하지만, split 메서드에 y값을 함께 전달해야 합니다.

클래스 정보를 알아야 비율을 맞출 수 있기 때문입니다. 실행 결과를 보면 각 폴드에서 양성 비율이 거의 동일하게 유지되는 것을 확인할 수 있습니다.

이제 폴드마다 점수 차이가 크게 줄어듭니다. 김개발 씨가 깨달았습니다.

"그러면 분류 문제에서는 항상 Stratified를 사용해야겠네요!" 박시니어 씨가 고개를 끄덕였습니다. "맞아요.

사실 scikit-learn의 cross_val_score 함수도 분류 문제에서는 기본적으로 Stratified를 사용해요." 특히 클래스 불균형이 심한 문제에서는 Stratified K-Fold가 필수입니다. 사기 탐지, 질병 진단, 고객 이탈 예측 등 현업에서 만나는 대부분의 문제가 불균형 데이터입니다.

다만 회귀 문제에서는 Stratified를 사용할 수 없습니다. 연속적인 값에는 클래스 비율이라는 개념이 없기 때문입니다.

회귀에서는 일반 K-Fold를 사용합니다.

실전 팁

💡 - 분류 문제에서는 기본적으로 Stratified K-Fold를 사용하세요

  • split 메서드에 y값을 전달하는 것을 잊지 마세요

4. Leave-One-Out 검증

김개발 씨가 의료 데이터를 분석하게 되었습니다. 문제는 데이터가 겨우 50개뿐입니다.

5-Fold를 적용하면 테스트셋에 10개밖에 없어서 신뢰할 수 없습니다. 이렇게 데이터가 적을 때는 어떻게 해야 할까요?

**Leave-One-Out(LOO)**은 K-Fold의 극단적인 형태로, K를 데이터 개수와 같게 설정하는 방법입니다. 마치 한 사람씩 돌아가며 면접을 보는 것처럼, 한 개의 샘플만 테스트에 사용하고 나머지 전체로 학습합니다.

데이터가 매우 적을 때 유용하지만, 계산 비용이 높다는 단점이 있습니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import LeaveOneOut, cross_val_score
from sklearn.svm import SVC
from sklearn.datasets import load_iris
import numpy as np

# 샘플 데이터 (소규모 데이터셋 시뮬레이션)
iris = load_iris()
X, y = iris.data[:50], iris.target[:50]  # 50개 샘플만 사용

# Leave-One-Out 검증
loo = LeaveOneOut()
model = SVC(kernel='rbf', random_state=42)

# LOO는 n개의 폴드를 생성 (n = 샘플 수)
print(f"총 폴드 수: {loo.get_n_splits(X)}")

# cross_val_score로 간편하게 계산
scores = cross_val_score(model, X, y, cv=loo)
print(f"평균 정확도: {np.mean(scores):.4f}")
print(f"표준편차: {np.std(scores):.4f}")

김개발 씨가 새로운 프로젝트를 맡았습니다. 희귀 질병 진단 모델을 만들어야 하는데, 데이터가 겨우 50개뿐입니다.

희귀 질병이라 환자 수 자체가 적기 때문입니다. "5-Fold를 적용하면 각 폴드에 10개밖에 없어요.

10개로 성능을 평가해도 될까요?" 김개발 씨가 걱정스럽게 물었습니다. 박시니어 씨가 고개를 저었습니다.

"10개는 너무 적어요. 그 10개가 어떤 샘플이냐에 따라 결과가 크게 달라질 거예요.

이럴 때는 Leave-One-Out을 고려해보세요." Leave-One-Out, 줄여서 LOO라고 부르는 이 방법은 이름 그대로 하나만 남기고 나머지로 학습하는 방식입니다. 50개 데이터가 있다면, 첫 번째 실험에서는 1번 샘플 하나만 테스트에 사용하고 나머지 49개로 학습합니다.

두 번째 실험에서는 2번 샘플을 테스트에 사용하고 나머지 49개로 학습합니다. 이렇게 50번의 실험을 진행합니다.

마치 한 사람씩 돌아가며 면접을 보는 것과 같습니다. 한 명이 면접실에 들어가면, 나머지 전원이 면접관이 됩니다.

모든 사람이 한 번씩 면접을 보면 끝입니다. LOO의 장점은 모든 데이터를 최대한 활용한다는 것입니다.

매 실험에서 n-1개의 데이터로 학습하므로, 학습 데이터 양이 가장 많습니다. 또한 모든 샘플이 정확히 한 번씩 테스트되므로 편향이 없습니다.

하지만 단점도 명확합니다. 데이터 개수만큼 모델을 학습해야 하므로 계산 비용이 매우 높습니다.

1000개 데이터에 LOO를 적용하면 모델을 1000번 학습해야 합니다. 또한 테스트셋이 1개뿐이므로 각 실험의 분산이 큽니다.

맞으면 100%, 틀리면 0%입니다. 다행히 평균을 내면 안정적인 추정치를 얻을 수 있습니다.

코드를 보면 LeaveOneOut 클래스를 사용합니다. get_n_splits 메서드로 확인하면 폴드 수가 데이터 개수와 같은 것을 알 수 있습니다.

김개발 씨가 질문했습니다. "그러면 언제 LOO를 사용해야 하나요?" 박시니어 씨가 정리해주었습니다.

"데이터가 100개 미만으로 매우 적을 때, 그리고 계산 시간이 오래 걸려도 괜찮을 때 사용해요. 데이터가 충분하면 일반 K-Fold가 더 효율적이에요." 의료, 금융 등 데이터 확보가 어려운 분야에서 LOO가 종종 사용됩니다.

하지만 대용량 데이터에서는 비현실적이므로 상황에 맞게 선택해야 합니다.

실전 팁

💡 - LOO는 데이터가 100개 미만인 소규모 데이터셋에서 고려하세요

  • 계산 비용이 높으므로 복잡한 모델에는 주의가 필요합니다

5. cross val score 사용법

김개발 씨가 매번 for문을 돌려서 교차 검증을 구현하는 것이 번거로웠습니다. "이거 매번 이렇게 직접 짜야 해요?" 박시니어 씨가 웃으며 말했습니다.

"당연히 더 편한 방법이 있지."

cross_val_score는 scikit-learn에서 제공하는 편리한 함수로, 교차 검증을 한 줄로 수행할 수 있습니다. 마치 커피머신의 원터치 버튼처럼, 복잡한 과정을 자동화해줍니다.

모델, 데이터, 폴드 수만 지정하면 알아서 학습, 검증, 점수 계산까지 처리합니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import cross_val_score, cross_validate
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
import numpy as np

iris = load_iris()
X, y = iris.data, iris.target
model = RandomForestClassifier(random_state=42)

# 기본 사용법: 한 줄로 교차 검증
scores = cross_val_score(model, X, y, cv=5)
print(f"5-Fold 정확도: {scores}")
print(f"평균: {np.mean(scores):.4f} (+/- {np.std(scores):.4f})")

# 다른 평가 지표 사용 (F1 스코어)
f1_scores = cross_val_score(model, X, y, cv=5, scoring='f1_macro')
print(f"F1 스코어: {np.mean(f1_scores):.4f}")

# cross_validate로 여러 지표 동시에 계산
results = cross_validate(model, X, y, cv=5,
                         scoring=['accuracy', 'f1_macro'],
                         return_train_score=True)
print(f"테스트 정확도: {np.mean(results['test_accuracy']):.4f}")
print(f"학습 정확도: {np.mean(results['train_accuracy']):.4f}")

김개발 씨가 투덜거렸습니다. "교차 검증 코드가 매번 비슷한데, 좀 더 간단한 방법은 없나요?

for문 돌리고, 인덱스 추출하고, 점수 모으고..." 박시니어 씨가 빙긋 웃었습니다. "당연히 있죠.

scikit-learn은 개발자 편의를 정말 잘 챙겨요." cross_val_score 함수는 교차 검증의 모든 과정을 한 줄로 처리합니다. 마치 커피머신의 원터치 버튼처럼, 버튼 하나로 원두 분쇄부터 추출까지 자동으로 진행됩니다.

사용법은 매우 간단합니다. 모델 객체, 입력 데이터 X, 타겟 데이터 y, 그리고 cv 파라미터에 폴드 수를 지정하면 끝입니다.

함수는 각 폴드의 점수를 배열로 반환합니다. cv 파라미터에는 여러 가지를 넣을 수 있습니다.

정수를 넣으면 해당 숫자만큼 폴드를 생성합니다. 분류 문제에서는 자동으로 StratifiedKFold가 적용됩니다.

직접 KFold나 StratifiedKFold 객체를 전달할 수도 있습니다. 특정 설정이 필요할 때 유용합니다.

scoring 파라미터도 중요합니다. 기본값은 분류 문제에서는 accuracy, 회귀 문제에서는 r2입니다.

하지만 다른 지표가 필요할 때가 많습니다. 예를 들어 불균형 데이터에서는 accuracy보다 f1_score가 더 적절합니다.

scoring='f1_macro'를 지정하면 F1 스코어로 평가할 수 있습니다. 사용 가능한 지표는 'accuracy', 'precision', 'recall', 'f1', 'roc_auc' 등 다양합니다.

회귀 문제에서는 'neg_mean_squared_error', 'r2' 등을 사용합니다. 만약 여러 지표를 동시에 계산하고 싶다면 cross_validate 함수를 사용합니다.

scoring 파라미터에 리스트로 여러 지표를 전달할 수 있습니다. cross_validate는 딕셔너리를 반환하며, 테스트 점수뿐 아니라 학습 시간, 테스트 시간까지 제공합니다.

return_train_score=True를 설정하면 학습 데이터에서의 점수도 확인할 수 있습니다. 학습 점수와 테스트 점수의 차이가 크면 과적합의 신호입니다.

학습 점수는 99%인데 테스트 점수는 70%라면 모델이 학습 데이터에 과하게 맞춰진 것입니다. 김개발 씨가 감탄했습니다.

"와, 이렇게 간단할 수가! 왜 진작 안 알려주셨어요?" 박시니어 씨가 대답했습니다.

"원리를 알아야 도구를 제대로 쓸 수 있거든요. 이제 원리를 알았으니 편한 도구를 마음껏 사용하세요."

실전 팁

💡 - scoring 파라미터로 문제에 맞는 평가 지표를 선택하세요

  • cross_validate를 사용하면 여러 지표를 동시에 계산할 수 있습니다

6. 교차 검증 결과 해석

김개발 씨가 교차 검증을 돌렸더니 결과가 나왔습니다. [0.92, 0.88, 0.95, 0.87, 0.91].

그런데 이 숫자들을 어떻게 해석해야 할까요? 평균만 보면 될까요?

박시니어 씨가 결과 해석의 핵심을 알려주기 시작했습니다.

교차 검증 결과를 해석할 때는 평균표준편차를 함께 봐야 합니다. 마치 학생의 성적을 평가할 때 평균 점수뿐 아니라 점수의 일관성도 보는 것과 같습니다.

표준편차가 크면 모델이 불안정하다는 신호이며, 데이터나 모델 구조를 점검해야 합니다.

다음 코드를 살펴봅시다.

from sklearn.model_selection import cross_val_score, cross_validate
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
import numpy as np

iris = load_iris()
X, y = iris.data, iris.target

# 두 모델 비교
models = {
    'RandomForest': RandomForestClassifier(random_state=42),
    'LogisticRegression': LogisticRegression(max_iter=200, random_state=42)
}

for name, model in models.items():
    scores = cross_val_score(model, X, y, cv=10)
    print(f"\n{name}:")
    print(f"  각 폴드: {scores.round(3)}")
    print(f"  평균: {np.mean(scores):.4f}")
    print(f"  표준편차: {np.std(scores):.4f}")
    print(f"  95% 신뢰구간: {np.mean(scores):.4f} +/- {1.96 * np.std(scores):.4f}")

    # 최악의 경우도 확인
    print(f"  최소: {np.min(scores):.4f}, 최대: {np.max(scores):.4f}")

김개발 씨가 교차 검증 결과를 가져왔습니다. "평균 정확도가 90%에요.

이 정도면 괜찮은 건가요?" 박시니어 씨가 물었습니다. "표준편차는 얼마예요?" 김개발 씨가 다시 확인했습니다.

"0.08이요." 박시니어 씨가 고개를 갸웃했습니다. "흠, 8%는 꽤 높은 편이에요.

각 폴드별 점수를 보여줄래요?" 점수를 확인해보니 [0.98, 0.82, 0.95, 0.78, 0.97]이었습니다. 어떤 폴드에서는 98%인데 어떤 폴드에서는 78%입니다.

무려 20%나 차이가 납니다. "이건 모델이 불안정하다는 신호예요." 박시니어 씨가 설명을 시작했습니다.

교차 검증 결과를 해석할 때 가장 중요한 것은 평균표준편차를 함께 보는 것입니다. 평균은 모델의 전반적인 성능을 나타내고, 표준편차는 일관성을 나타냅니다.

비유하자면 야구 선수의 타율과 같습니다. 3할 타자라도 어떤 경기에서는 5타수 5안타, 어떤 경기에서는 5타수 무안타라면 불안정한 선수입니다.

반면 꾸준히 3타수 1안타를 기록하는 선수가 더 신뢰할 수 있습니다. 표준편차가 높은 원인은 여러 가지가 있습니다.

첫째, 데이터 자체의 품질 문제입니다. 특정 구간에 노이즈가 많거나 이상치가 있을 수 있습니다.

둘째, 데이터 양이 부족할 수 있습니다. 데이터가 적으면 폴드마다 구성이 크게 달라집니다.

셋째, 모델이 데이터의 특정 패턴에 과적합되었을 수 있습니다. 결과를 해석할 때 95% 신뢰구간을 계산하면 유용합니다.

평균에서 1.96배의 표준편차를 더하고 빼면 됩니다. 예를 들어 평균 0.90, 표준편차 0.05라면 신뢰구간은 0.90 +/- 0.098, 즉 약 80%에서 100% 사이입니다.

모델을 비교할 때도 신뢰구간이 유용합니다. 모델 A의 신뢰구간이 85%-95%이고, 모델 B의 신뢰구간이 82%-88%라면, 겹치는 부분이 있으므로 통계적으로 유의미한 차이인지 신중하게 판단해야 합니다.

최솟값과 최댓값도 확인하세요. 최솟값은 모델이 가장 못할 때의 성능입니다.

실제 서비스에서 이 정도 성능이 나올 수도 있다는 것을 의미합니다. 최솟값이 너무 낮다면 문제가 될 수 있습니다.

김개발 씨가 정리했습니다. "그러니까 평균만 보면 안 되고, 표준편차도 낮아야 좋은 모델이군요!" 박시니어 씨가 덧붙였습니다.

"맞아요. 그리고 여러 모델을 비교할 때는 같은 폴드로 검증해야 공정해요.

random_state를 고정하면 동일한 폴드가 생성됩니다." 교차 검증은 단순히 점수를 얻는 것이 아니라, 모델의 강점과 약점을 파악하는 도구입니다. 결과를 꼼꼼히 분석하면 더 나은 모델을 만들 수 있는 인사이트를 얻을 수 있습니다.

실전 팁

💡 - 평균과 표준편차를 항상 함께 보고하세요

  • 모델 비교 시 동일한 random_state로 폴드를 고정하면 공정한 비교가 가능합니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#CrossValidation#MachineLearning#Scikit-learn#ModelEvaluation#Machine Learning,Python

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.