Iris 데이터셋을 사용하여 결정 트리(Decision Tree) 모델의 성능을 다양한 방법을 평가
각각의 방법론에 따라 과적합 여부를 판단, 교차 검증 등을 통해 일반화 성능을 측정
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split, KFold, StratifiedKFold, cross_val_score
import numpy as np
dataset = load_iris()
model = DecisionTreeClassifier() #결정 트리 모델 객체 생성, 파라미터 없이 기본 설정으로 초기화
#X, y = load_iris(return_X_y = True)
X = dataset.data #특성 값
y = dataset.target #정답 레이블(클래스)
model.fit(X, y)
DecisionTreeClassifier(결정 트리)
데이터를 조건에 따라 분할하여 분류 또는 회귀 문제를 해결하는 데 사용
노드, 가지, 잎의 구조를 갖춘 트리 형태로 학습
1. 학습 데이터로 평가한 경우 (잘못된 방식)
pred = model.predict(X)
print(f'잘못된 방식으로 학습 데이터로 평가한 정확도(과적합) >>>> {accuracy_score(y, pred)}')
"""
잘못된 방식으로 학습 데이터로 평가한 정확도(과적합) >>>> 1.0
"""
학습 데이터(X)로 모델을 평가하여 과적합(overfitting)이 발생
• 모델이 학습 데이터에 대해 과도하게 최적화되어 실제 데이터에 대한 일반화 성능이 떨어질 수 있음
→ 평가에는 반드시 학습에 사용하지 않은 데이터(테스트 데이터)가 필요
→ train_test_split 또는 교차 검증 사용
2. Train-Test Split (학습/테스트 데이터 분리) 후 학습
X_train, X_test, y_train, y_test = train_test_split(
dataset.data, dataset.target, test_size=0.4, random_state=44
)
model.fit(X_train, y_train)
pred = model.predict(X_test)
print(f'학습 데이터로 평가한 정확도 >>>> {accuracy_score(y_test, pred)}')
"""
학습 데이터로 평가한 정확도 >>>> 0.9833333333333333
"""
데이터셋을 학습 데이터와 테스트 데이터로 분리(train_test_split)하여 과적합을 방지
• test_size=0.4 : 40%의 데이터를 테스트 데이터로 사용
테스트 데이터는 모델의 성능을 검증하는 용도로만 사용하며, 학습 과정에서는 절대 사용되지 않아야 함
단일 분할로는 데이터의 특이점에 민감할 수 있어 교차 검증(Cross-Validation)을 사용하는 것이 더 좋음
*random_state
- 랜덤성 제어
- 데이터 분리(train_test_split), 교차 검증(KFold, StratifiedKFold), 무작위 샘플링 등에 사용되는 랜덤 작업의 초기 상태를 고정
→ 같은 데이터를 같은 조건으로 실행할 때마다 동일한 결과 보장(결과 재현성 확보)
→ 머신러닝 실험을 반복적으로 수행할 때 결과가 달라지지 않도록 동일한 상태 유지
→ 실험의 신뢰성을 높이고, 결과를 비교하거나 디버깅 시 유용 - 난수 생성기 초기화
random_state는 내부적으로 난수를 생성하는 난수 생성기의 초기값(seed) 역할
random_state의 값이 같다면, 동일한 난수 시퀀스 생성
from sklearn.model_selection import train_test_split
X = [[1], [2], [3], [4], [5], [6]]
y = [0, 1, 0, 1, 0, 1]
# random_state = 42
X_train_1, X_test_1, y_train_1, y_test_1 = train_test_split(
X, y, test_size=0.33, random_state=42
)
print("첫 번째 실행 결과:")
print("X_train:", X_train_1)
print("X_test:", X_test_1)
# random_state = 42 (같은 값)
X_train_2, X_test_2, y_train_2, y_test_2 = train_test_split(
X, y, test_size=0.33, random_state=42
)
print("\n두 번째 실행 결과:")
print("X_train:", X_train_2)
print("X_test:", X_test_2)
# random_state = 99 (다른 값)
X_train_3, X_test_3, y_train_3, y_test_3 = train_test_split(
X, y, test_size=0.33, random_state=99
)
print("\n세 번째 실행 결과 (random_state=99):")
print("X_train:", X_train_3)
print("X_test:", X_test_3)
"""
첫 번째 실행 결과:
X_train: [[6], [3], [5], [4]]
X_test: [[1], [2]]
두 번째 실행 결과:
X_train: [[6], [3], [5], [4]]
X_test: [[1], [2]]
세 번째 실행 결과 (random_state=99):
X_train: [[1], [6], [4], [2]]
X_test: [[3], [5]]
"""
random_state를 동일하게 설정한 경우
- 첫 번째 실행과 두 번째 실행의 결과 동일
random_state를 변경한 경우
- 세 번째 실행은 데이터가 다르게 분리
*suffle = False를 명시해야할 경우
train_test_split에서 기본적으로 데이터를 무작위로 섞음
→shuffle = True를 지정하지 않아도 기본 동작으로 데이터가 섞인 상태에서 학습/테스트 데이터로 분할
- 시간 순서 데이터
시계열 데이터에서는 데이터를 시간 순서대로 분할해야 하는 경우가 대다수
이 경우 데이터를 섞으면 안됨 - 특정 분할이 필요한 경우
데이터셋의 순서를 유지하고 싶거나, 특정한 분할 방식이 필요한 경우 shuffle = False 사용
3. K-Fold Cross-Validation (K-겹 교차 검증)
kf = KFold(n_splits=5, shuffle=True, random_state=44)
cv = []
fold_index = 0
for train_index, test_index in kf.split(dataset.data):
X_train, X_test = dataset.data[train_index], dataset.data[test_index]
y_train, y_test = dataset.target[train_index], dataset.target[test_index]
model.fit(X_train, y_train)
pred = model.predict(X_test)
fold_accuracy = np.round(accuracy_score(y_test, pred), 4)
fold_index += 1
print(f'{fold_index} 교차 검증 정확도 {fold_accuracy}')
cv.append(fold_accuracy)
print(f'평균 검증 정확도 >>>> {np.mean(cv)}')
"""
1 교차 검증 정확도 0.9333
2 교차 검증 정확도 1.0
3 교차 검증 정확도 0.9667
4 교차 검증 정확도 0.9
5 교차 검증 정확도 0.9333
평균 검증 정확도 >>>> 0.94666
"""
데이터를 K개의 폴드로 나누어 각 폴드에 대해 학습과 평가를 반복하여 모델 성능을 검증
모든 데이터가 학습 및 테스트에 고르게 사용되도록 shuffle=True로 설정
→ 데이터의 편향을 줄이고 더 신뢰할 수 있는 성능 평가 가능
*클래스 비율이 불균형한 데이터셋에서는 StratifiedKFold가 더 적합
4. Stratified K-Fold Cross-Validation (계층적 K-겹 교차 검증)
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=44)
cv = []
fold_index = 0
for train_index, test_index in skf.split(dataset.data, dataset.target):
X_train, X_test = dataset.data[train_index], dataset.data[test_index]
y_train, y_test = dataset.target[train_index], dataset.target[test_index]
model.fit(X_train, y_train)
pred = model.predict(X_test)
fold_accuracy = np.round(accuracy_score(y_test, pred), 4)
fold_index += 1
print(f'{fold_index} 교차 검증 정확도 {fold_accuracy}')
cv.append(fold_accuracy)
print(f'평균 검증 정확도 >>>> {np.mean(cv)}')
"""
1 교차 검증 정확도 0.9
2 교차 검증 정확도 1.0
3 교차 검증 정확도 0.9667
4 교차 검증 정확도 0.9333
5 교차 검증 정확도 0.9667
평균 검증 정확도 >>>> 0.9533400000000001
"""
StratifiedKFold는 각 폴드가 동일한 클래스 비율을 유지하도록 데이터를 나눔
불균형 데이터에서 학습 데이터와 테스트 데이터가 적절히 분배되도록 도와줌
*일반적으로 분류 문제에서는 StratifiedKFold가 KFold보다 적합
5. cross_val_score로 교차 검증 간소화
scores = cross_val_score(model, dataset.data, dataset.target, scoring='accuracy', cv=5)
for fold_index, fold_score in enumerate(scores, start=1):
print(f'{fold_index}의 정확도는 >>>> {fold_score:.4f}')
print(f'평균 검증 정확도 >>>> {np.mean(scores)}')
"""
1의 정확도는 >>>> 0.9667
2의 정확도는 >>>> 0.9667
3의 정확도는 >>>> 0.9000
4의 정확도는 >>>> 0.9333
5의 정확도는 >>>> 1.0000
평균 검증 정확도 >>>> 0.9533333333333334
"""
cross_val_score는 데이터 분할, 모델 학습, 예측, 평가를 한 번에 처리
- cv = 5로 5-겹 교차 검증 수행
- 간단히 여러 폴드의 결과를 확인할 수 있어 편리
기본적으로 scoring = 'accuracy'를 설정했지만, 다른 평가지표(예: f1_score, roc_auc)도 가능
'Python to AI' 카테고리의 다른 글
titanic 데이터셋 분석 및 모델 학습 (0) | 2025.01.29 |
---|---|
Scikit-Learn과 Estimator (0) | 2025.01.21 |
Perceptron(퍼셉트론) (1) | 2025.01.14 |
Machine Learning Algorithms (0) | 2025.01.10 |
Python - Matplotlib (4) | 2024.12.30 |