K-Fold 교차 검증 마스터링: GridSearchCV 없이 종합 가이드
머신 러닝 분야에서 모델의 견고성과 신뢰성을 보장하는 것은 매우 중요합니다. 이를 달성하기 위한 기본적인 기술 중 하나가 K-Fold 교차 검증입니다. Scikit-Learn과 같은 인기 있는 라이브러리는 교차 검증과 결합된 하이퍼파라미터 튜닝을 위한 GridSearchCV
와 같은 도구를 제공하지만, 때로는 K-Fold 교차 검증을 수동으로 구현하고자 할 수 있습니다. 이 가이드는 Python과 Jupyter 노트북을 사용하여 GridSearchCV
에 의존하지 않고 K-Fold 교차 검증을 이해하고 구현하는 방법을 깊이 있게 다룹니다.
목차
- K-Fold 교차 검증 소개
- 데이터셋 이해하기
- 데이터 전처리
- 결측치 처리
- 특징 선택
- 범주형 변수 인코딩
- 특징 스케일링
- 머신 러닝 모델 구축
- GridSearchCV 없이 K-Fold 교차 검증 구현
- 모범 사례 및 팁
- 결론
K-Fold 교차 검증 소개
K-Fold 교차 검증은 제한된 데이터 샘플에서 머신 러닝 모델을 평가하기 위해 사용되는 재샘플링 기법입니다. 이 프로세스는 원본 데이터셋을 K개의 서로 겹치지 않는 하위 집합(폴드)으로 분할하는 것을 포함합니다. 모델은 K-1개의 폴드에서 학습되고, 남은 폴드에서 검증됩니다. 이 절차는 K번 반복되며, 각 폴드는 한 번씩 검증 세트로 사용됩니다. 최종 성능 지표는 일반적으로 K개의 검증 점수의 평균입니다.
왜 K-Fold 교차 검증을 사용할까?
- 견고한 평가: 단일 학습-테스트 분할에 비해 모델 성능에 대한 보다 신뢰할 수 있는 추정치를 제공합니다.
- 과적합 감소: 여러 하위 집합에서 학습함으로써 모델이 보이지 않는 데이터에 대해 더 잘 일반화됩니다.
- 효율적인 데이터 사용: 특히 제한된 데이터셋을 다룰 때 유용합니다.
GridSearchCV
는 교차 검증과 하이퍼파라미터 튜닝을 통합하지만, K-Fold 교차 검증을 수동으로 구현하는 방법을 이해하면 모델 훈련 과정에 대한 더 큰 유연성과 통찰력을 얻을 수 있습니다.
데이터셋 이해하기
이 가이드를 위해 우리는 Kaggle에서 얻은 자동차 가격 예측 데이터셋을 사용합니다. 이 데이터셋은 자동차의 다양한 특징을 포함하고 있으며, 그들의 시장 가격을 예측하는 것을 목표로 합니다.
데이터셋 개요
- 특징: 25개 (타겟 변수 제외)
- 수치형: 엔진 크기, 마력, 최고 RPM, 시내 MPG, 고속도로 MPG 등
- 범주형: 자동차 브랜드, 연료 유형, 흡기 방식, 도어 수, 자동차 바디 타입, 드라이브 휠 구성 등
- 타겟 변수:
price
(연속 값)
초기 데이터 검토
데이터 전처리에 들어가기 전에 데이터셋을 검토하는 것이 중요합니다:
1 2 3 4 5 |
import pandas as pd # 데이터셋 로드 data = pd.read_csv('CarPrice.csv') print(data.head()) |
샘플 출력:
car_ID | symboling | CarName | fueltype | aspiration | doornumber | carbody | highwaympg | price |
---|---|---|---|---|---|---|---|---|
1 | 3 | alfa-romero giulia | gas | std | two | convertible | 27 | 13495.0 |
2 | 3 | alfa-romero stelvio | gas | std | two | convertible | 27 | 16500.0 |
3 | 1 | alfa-romero Quadrifoglio | gas | std | two | hatchback | 26 | 16500.0 |
4 | 2 | audi 100 ls | gas | std | four | sedan | 30 | 13950.0 |
5 | 2 | audi 100ls | gas | std | four | sedan | 22 | 17450.0 |
데이터 전처리
효과적인 데이터 전처리는 정확하고 효율적인 머신 러닝 모델을 구축하는 데 필수적입니다. 이 섹션에서는 결측치 처리, 특징 선택, 범주형 변수 인코딩, 특징 스케일링에 대해 다룹니다.
결측치 처리
수치형 특징
수치형 특징의 결측치는 평균, 중앙값 또는 최빈값과 같은 전략을 사용하여 대체할 수 있습니다:
1 2 3 4 5 6 7 8 9 10 11 12 |
import numpy as np from sklearn.impute import SimpleImputer # 평균 전략으로 임퓨터 초기화 imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean') # 수치형 열 식별 numerical_cols = list(np.where((X.dtypes == np.int64) | (X.dtypes == np.float64))[0]) # 수치형 데이터에 적합 및 변환 imp_mean.fit(X.iloc[:, numerical_cols]) X.iloc[:, numerical_cols] = imp_mean.transform(X.iloc[:, numerical_cols]) |
범주형 특징
범주형 데이터의 경우, 결측치를 최빈값으로 대체할 수 있습니다:
1 2 3 4 5 6 7 8 9 10 11 |
from sklearn.impute import SimpleImputer # 문자열 열 식별 string_cols = list(np.where((X.dtypes == object))[0]) # 최빈값 전략으로 임퓨터 초기화 imp_freq = SimpleImputer(missing_values=np.nan, strategy='most_frequent') # 범주형 데이터에 적합 및 변환 imp_freq.fit(X.iloc[:, string_cols]) X.iloc[:, string_cols] = imp_freq.transform(X.iloc[:, string_cols]) |
특징 선택
관련성이 없거나 중복된 특징을 제거하면 모델 성능을 향상시킬 수 있습니다:
1 2 |
# 'car_ID' 열은 예측에 사용되지 않으므로 삭제 X.drop('car_ID', axis=1, inplace=True) |
범주형 변수 인코딩
머신 러닝 모델은 수치형 입력을 요구하므로, 범주형 변수는 인코딩되어야 합니다.
원-핫 인코딩
원-핫 인코딩은 범주형 변수를 이진 행렬로 변환합니다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from sklearn.preprocessing import OneHotEncoder from sklearn.compose import ColumnTransformer # 인코딩할 문자열 열 식별 string_cols = list(np.where((X.dtypes == object))[0]) # OneHotEncoder로 ColumnTransformer 초기화 columnTransformer = ColumnTransformer( [('encoder', OneHotEncoder(), string_cols)], remainder='passthrough' ) # 변환 적용 X = columnTransformer.fit_transform(X) |
특징 스케일링
스케일링은 수치형 특징이 모델 훈련 과정에 동일하게 기여하도록 보장합니다.
표준화
표준화는 특징의 평균을 0, 표준 편차를 1로 스케일링합니다:
1 2 3 4 5 6 7 8 9 |
from sklearn.preprocessing import StandardScaler # StandardScaler 초기화 sc = StandardScaler(with_mean=False) # 훈련 데이터에 적합 및 변환 sc.fit(X_train) X_train = sc.transform(X_train) X_test = sc.transform(X_test) |
머신 러닝 모델 구축
전처리된 데이터를 사용하여 다양한 회귀 모델을 구축하고 평가할 수 있습니다.
결정 트리 회귀
1 2 3 4 5 6 7 8 9 10 |
from sklearn.tree import DecisionTreeRegressor from sklearn.metrics import r2_score # 모델 초기화 model = DecisionTreeRegressor(max_depth=4) # 학습 및 평가 model.fit(X_train, y_train) y_pred = model.predict(X_test) print(r2_score(y_test, y_pred)) |
R² 점수: 0.884
랜덤 포레스트 회귀
1 2 3 4 5 6 7 8 9 |
from sklearn.ensemble import RandomForestRegressor # 모델 초기화 model = RandomForestRegressor(n_estimators=25, random_state=10) # 학습 및 평가 model.fit(X_train, y_train) y_pred = model.predict(X_test) print(r2_score(y_test, y_pred)) |
R² 점수: 0.911
AdaBoost 회귀
1 2 3 4 5 6 7 8 9 |
from sklearn.ensemble import AdaBoostRegressor # 모델 초기화 model = AdaBoostRegressor(random_state=0, n_estimators=100) # 학습 및 평가 model.fit(X_train, y_train) y_pred = model.predict(X_test) print(r2_score(y_test, y_pred)) |
R² 점수: 0.881
XGBoost 회귀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import xgboost as xgb # 모델 초기화 model = xgb.XGBRegressor( n_estimators=100, reg_lambda=1, gamma=0, max_depth=3, learning_rate=0.05 ) # 학습 및 평가 model.fit(X_train, y_train) y_pred = model.predict(X_test) print(r2_score(y_test, y_pred)) |
R² 점수: 0.895
서포트 벡터 회귀(SVR)
1 2 3 4 5 6 7 8 9 |
from sklearn.svm import SVR # 모델 초기화 model = SVR() # 학습 및 평가 model.fit(X_train, y_train) y_pred = model.predict(X_test) print(r2_score(y_test, y_pred)) |
R² 점수: -0.027
참고: R² 점수가 0 이하인 경우 모델이 수평선보다 성능이 떨어짐을 나타냅니다.
GridSearchCV 없이 K-Fold 교차 검증 구현
K-Fold 교차 검증을 수동으로 구현하면 훈련 및 평가 프로세스에 대한 세밀한 제어가 가능합니다. 다음은 단계별 가이드입니다:
1단계: K-Fold 초기화
1 2 3 4 |
from sklearn.model_selection import KFold # 5개의 분할, 셔플링, 재현 가능성을 위한 고정된 랜덤 상태로 KFold 초기화 kf = KFold(n_splits=5, random_state=42, shuffle=True) |
2단계: 모델 구축 함수 정의
모델 훈련 및 평가를 재사용 가능하도록 함수로 캡슐화합니다:
1 2 3 4 5 6 |
from sklearn.metrics import r2_score def build_model(X_train, X_test, y_train, y_test, model): model.fit(X_train, y_train) y_pred = model.predict(X_test) return r2_score(y_test, y_pred) |
3단계: K-Fold 교차 검증 실행
각 폴드를 반복하며 모델을 학습하고 R² 점수를 수집합니다:
1 2 3 4 5 6 7 8 |
scores = [] for train_index, test_index in kf.split(X): X_train_fold, X_test_fold = X[train_index], X[test_index] y_train_fold, y_test_fold = y.iloc[train_index], y.iloc[test_index] score = build_model(X_train_fold, X_test_fold, y_train_fold, y_test_fold, model) scores.append(score) print(scores) |
샘플 출력:
1 2 3 4 5 |
[-0.10198885010286984, -0.05769313782320418, -0.1910165707884004, -0.09880100338491071, -0.260272529471554] |
점수 해석: 음수 R² 점수는 모든 폴드에서 모델 성능이 저조함을 나타냅니다. 이는 과적합, 데이터 누수, 부적절한 모델 선택과 같은 문제를 시사합니다.
4단계: 결과 분석
교차 검증 점수에 대한 종합적인 분석은 모델의 안정성과 일반화 능력에 대한 통찰을 제공할 수 있습니다.
1 2 3 4 5 6 7 8 |
import numpy as np # 평균 및 표준 편차 계산 mean_score = np.mean(scores) std_score = np.std(scores) print(f"Mean R² Score: {mean_score}") print(f"Standard Deviation: {std_score}") |
샘플 출력:
1 2 |
Mean R² Score: -0.133554 Standard Deviation: 0.077''' |
통찰:
- 음수 평균 R² 점수는 모델이 성능이 저조함을 나타냅니다.
- 높은 표준 편차는 다양한 폴드에서 유의미한 변동성을 나타내며, 모델의 예측 능력에 일관성이 없음을 시사합니다.
모범 사례 및 팁
- 분류를 위한 계층적 K-Fold: 이 가이드는 회귀에 중점을 두지만, 분류 작업을 다룰 때는 폴드 간 클래스 분포를 유지하기 위해 계층적 K-Fold를 사용하는 것이 중요합니다.
- 특징 중요도 분석: 모델 훈련 후, 특징 중요도를 분석하면 타겟 변수에 가장 큰 영향을 미치는 특징을 이해하는 데 도움이 됩니다.
- 하이퍼파라미터 튜닝:
GridSearchCV
없이도, 각 폴드 내에서 하이퍼파라미터를 수동으로 조정하여 모델의 최적 설정을 찾을 수 있습니다. - 불균형 데이터셋 처리: 특히 분류 작업에서, 훈련 및 테스트 분할이 클래스의 균형을 유지하도록 해야 합니다.
- 모델 선택: 항상 여러 모델을 실험하여 데이터셋의 특성에 가장 적합한 모델을 식별하세요.
결론
K-Fold 교차 검증은 머신 러닝 도구 키트에서 빼놓을 수 없는 기법으로, 모델 성능을 평가하는 견고한 방법을 제공합니다. 이 가이드에서 시연한 바와 같이 K-Fold 교차 검증을 수동으로 구현함으로써, 모델 훈련 과정에 대한 더 깊은 통찰을 얻고 각 평가 단계에 대한 완전한 제어를 유지할 수 있습니다. GridSearchCV
와 같은 자동화 도구는 편리하지만, 기본 메커니즘을 이해하면 더 복잡한 시나리오에 대처하고 검증 프로세스를 특정 요구 사항에 맞게 조정할 수 있게 됩니다.
K-Fold 교차 검증의 힘을 활용하여 예측 모델의 신뢰성과 정확성을 향상시키고, 보다 정보에 기반한 데이터 중심의 결정을 내리세요.
키워드: K-Fold 교차 검증, GridSearchCV, 머신 러닝, 모델 평가, Python, Jupyter Notebook, 데이터 전처리, 회귀 모델, 교차 검증 기법, Scikit-Learn