Sklearn train_test_split: Python에서 머신러닝 데이터 분할하기
Updated on
평가에 사용하는 것과 동일한 데이터로 머신러닝 모델을 훈련하면 오해의 소지가 있는 높은 정확도가 나옵니다. 모델이 일반화 가능한 패턴을 학습하는 대신 훈련 데이터를 암기합니다 -- 이것을 과적합이라고 합니다. 정직한 성능 지표를 얻으려면 모델이 훈련 중에 한 번도 보지 못한 별도의 테스트 세트가 필요합니다.
Scikit-learn의 train_test_split()은 데이터셋을 훈련과 테스트 부분으로 나누는 표준 방법입니다. 배열, DataFrame, 희소 행렬을 처리하며, 층화 추출, 재현성, 사용자 정의 분할 비율 옵션을 제공합니다.
기본 사용법
from sklearn.model_selection import train_test_split
import numpy as np
# 샘플 데이터: 100개 샘플, 5개 특성
X = np.random.randn(100, 5)
y = np.random.randint(0, 2, 100) # 이진 레이블
# 분할: 80% 훈련, 20% 테스트
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print(f"훈련 세트: {X_train.shape[0]} 샘플")
print(f"테스트 세트: {X_test.shape[0]} 샘플")
# 훈련 세트: 80 샘플
# 테스트 세트: 20 샘플주요 매개변수
| 매개변수 | 기본값 | 설명 |
|---|---|---|
test_size | 0.25 | 테스트 샘플의 비율(0.0-1.0) 또는 절대 수 |
train_size | None | 훈련 샘플의 비율 또는 수 (test_size의 보수) |
random_state | None | 재현 가능한 분할을 위한 시드 |
shuffle | True | 분할 전 데이터 셔플 여부 |
stratify | None | 층화 분할에 사용할 배열 |
Pandas DataFrame과 함께 사용
from sklearn.model_selection import train_test_split
import pandas as pd
df = pd.DataFrame({
'age': [25, 30, 35, 40, 45, 50, 55, 60, 28, 33],
'income': [40, 50, 60, 70, 80, 90, 100, 110, 45, 55],
'purchased': [0, 0, 1, 1, 1, 1, 1, 1, 0, 0]
})
X = df[['age', 'income']]
y = df['purchased']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
print(f"훈련 형태: {X_train.shape}") # (7, 2)
print(f"테스트 형태: {X_test.shape}") # (3, 2)
print(type(X_train)) # <class 'pandas.core.frame.DataFrame'>분할 후에도 DataFrame은 DataFrame으로 유지됩니다 -- 열 이름과 인덱스가 보존됩니다.
random_state: 재현 가능한 분할
random_state 없이는 매번 다른 분할이 됩니다:
from sklearn.model_selection import train_test_split
import numpy as np
X = np.arange(10).reshape(5, 2)
y = np.array([0, 0, 1, 1, 1])
# random_state 없이: 매번 다른 분할
_, X_test1, _, _ = train_test_split(X, y, test_size=0.4)
_, X_test2, _, _ = train_test_split(X, y, test_size=0.4)
print(np.array_equal(X_test1, X_test2)) # 아마 False
# random_state 있으면: 매번 같은 분할
_, X_test3, _, _ = train_test_split(X, y, test_size=0.4, random_state=42)
_, X_test4, _, _ = train_test_split(X, y, test_size=0.4, random_state=42)
print(np.array_equal(X_test3, X_test4)) # True재현성을 위해 항상 random_state를 설정하세요. 아무 정수나 사용하세요 -- 42가 관례이지만 구체적인 숫자는 중요하지 않습니다.
층화 분할
불균형 데이터셋에서는 랜덤 분할이 대부분의 소수 클래스 샘플을 한 세트에 넣을 수 있습니다. 층화는 두 세트가 같은 클래스 비율을 갖도록 보장합니다:
from sklearn.model_selection import train_test_split
import numpy as np
from collections import Counter
# 불균형 데이터셋: 90% 클래스 0, 10% 클래스 1
np.random.seed(42)
X = np.random.randn(200, 4)
y = np.array([0] * 180 + [1] * 20)
# 층화 없이
_, _, y_train_bad, y_test_bad = train_test_split(
X, y, test_size=0.2, random_state=42
)
print("층화 없이:")
print(f" 훈련: {Counter(y_train_bad)}")
print(f" 테스트: {Counter(y_test_bad)}")
# 층화 있으면
_, _, y_train_good, y_test_good = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
print("\nstratify=y 사용:")
print(f" 훈련: {Counter(y_train_good)}")
print(f" 테스트: {Counter(y_test_good)}")
# 훈련: Counter({0: 144, 1: 16}) -- 10% 클래스 1
# 테스트: Counter({0: 36, 1: 4}) -- 10% 클래스 1언제 층화를 사용해야 하나
| 시나리오 | 층화 사용? |
|---|---|
| 균형 잡힌 클래스 (50/50) | 선택 사항 |
| 불균형 클래스 (90/10) | 예 |
| 다중 클래스 분류 | 예 |
| 회귀 (연속 타겟) | 아니오 (지원 안 함) |
| 작은 데이터셋 (< 100 샘플) | 예 (빈 클래스 방지) |
훈련/검증/테스트 분할
하이퍼파라미터 튜닝에는 훈련, 검증, 테스트의 세 세트가 필요합니다. train_test_split을 두 번 호출합니다:
from sklearn.model_selection import train_test_split
import numpy as np
X = np.random.randn(1000, 10)
y = np.random.randint(0, 3, 1000)
# 첫 번째 분할: 80% 훈련+검증, 20% 테스트
X_temp, X_test, y_temp, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 두 번째 분할: 75% 훈련, 25% 검증 (80%의 25% = 전체 60/20/20)
X_train, X_val, y_train, y_val = train_test_split(
X_temp, y_temp, test_size=0.25, random_state=42, stratify=y_temp
)
print(f"훈련: {X_train.shape[0]} 샘플 (60%)")
print(f"검증: {X_val.shape[0]} 샘플 (20%)")
print(f"테스트: {X_test.shape[0]} 샘플 (20%)")완전한 ML 파이프라인 예제
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
import numpy as np
# 샘플 데이터 생성
np.random.seed(42)
X = np.random.randn(500, 8)
y = (X[:, 0] + X[:, 1] > 0).astype(int)
# 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 특성 스케일링 (훈련 세트에서만 fit!)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test) # 훈련 통계량 사용
# 모델 훈련
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train_scaled, y_train)
# 평가
y_pred = model.predict(X_test_scaled)
print(f"정확도: {accuracy_score(y_test, y_pred):.4f}")
print(classification_report(y_test, y_pred))중요한 규칙: 스케일러(및 모든 전처리)는 훈련 세트에서만 fit하세요. 동일한 변환을 테스트 세트에 적용합니다. 전체 데이터셋에서 fit하면 데이터 누수가 발생합니다.
일반적인 분할 비율
| 분할 | 훈련 | 테스트 | 언제 사용 |
|---|---|---|---|
| 80/20 | 80% | 20% | 기본 선택, 대부분의 데이터셋 |
| 70/30 | 70% | 30% | 작은 데이터셋, 더 큰 테스트 세트 필요 |
| 90/10 | 90% | 10% | 큰 데이터셋 (10k+ 샘플) |
| 60/20/20 | 60% | 20% 검증 + 20% 테스트 | 하이퍼파라미터 튜닝 시 |
모델 결과 탐색
분할하고 모델을 훈련한 후, PyGWalker (opens in a new tab)를 사용하면 Jupyter에서 예측 vs 실제 값, 훈련/테스트 세트 간의 특성 분포, 오류 패턴을 인터랙티브하게 탐색할 수 있습니다:
import pandas as pd
import pygwalker as pyg
results = pd.DataFrame({
'actual': y_test,
'predicted': y_pred,
'correct': y_test == y_pred
})
walker = pyg.walk(results)자주 묻는 질문
sklearn의 train_test_split은 무엇을 하나요?
train_test_split()은 배열이나 DataFrame을 무작위로 훈련용과 테스트용 두 하위 집합으로 나눕니다. 모델 평가가 훈련 중 보지 못한 데이터를 사용하도록 보장하여 정직한 성능 추정치를 제공합니다.
최적의 훈련/테스트 분할 비율은?
80/20이 표준 기본값입니다. 신뢰할 수 있는 테스트 세트가 필요한 작은 데이터셋에는 70/30을, 큰 데이터셋(10k+ 샘플)에는 90/10을 사용합니다. 하이퍼파라미터 튜닝에는 60/20/20(훈련/검증/테스트)을 사용합니다.
train_test_split에서 random_state는 무엇을 하나요?
random_state는 분할 전 셔플링의 랜덤 시드를 설정합니다. 같은 random_state 값을 사용하면 매번 같은 분할이 생성되어 결과를 재현할 수 있습니다. 아무 정수나 사용할 수 있습니다.
train_test_split에서 stratify는 언제 사용해야 하나요?
타겟 변수가 불균형하거나(예: 95% 음성, 5% 양성) 데이터셋이 작을 때 stratify=y를 사용합니다. 층화는 훈련 세트와 테스트 세트 모두 각 클래스의 같은 비율을 갖도록 보장합니다.
데이터를 훈련, 검증, 테스트 세트로 나누려면?
train_test_split을 두 번 호출합니다. 먼저 훈련+검증과 테스트로 분할(예: 80/20). 그다음 훈련+검증을 훈련과 검증으로 분할(예: 80%의 75/25로 전체 60/20/20). 또는 교차 검증을 위해 sklearn.model_selection.KFold를 사용합니다.
결론
train_test_split()은 Python에서 모든 머신러닝 워크플로의 기반입니다. 항상 훈련 전에 사용하세요 -- 절대 훈련 데이터에서 평가하지 마세요. 재현성을 위해 random_state를 설정하고, 불균형 클래스에는 stratify=y를 사용하며, 전처리 단계는 훈련 세트에서만 fit해야 한다는 것을 기억하세요. 모델 선택을 위해서는 3방향 분할(훈련/검증/테스트)하거나 더 강건한 추정을 위해 교차 검증을 사용하세요.