Python to AI

Iris 데이터셋과 결정 트리(Decision Tree) 모델 : 평가 방법 비교 및 교차 검증 실습

최 수빈 2025. 1. 24. 01:40

 

 

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를 지정하지 않아도 기본 동작으로 데이터가 섞인 상태에서 학습/테스트 데이터로 분할

 

  1. 시간 순서 데이터

    시계열 데이터에서는 데이터를 시간 순서대로 분할해야 하는 경우가 대다수
    이 경우 데이터를 섞으면 안됨

  2. 특정 분할이 필요한 경우

    데이터셋의 순서를 유지하고 싶거나, 특정한 분할 방식이 필요한 경우 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