(실습) 결정트리

참고

(구글코랩) 결정트리

의 소스코드를 먼저 공부하세요.

문제 1

(구글코랩) 결정트리

맨 아래에 있는 연습문제 7번-8번 내용을 정리하라.

7.

초승달 데이터셋을 이용한 결정트리 모델을 미세 조정한다.

a. 초승달 데이터셋 생성

1
2
3
from sklearn.datasets import make_moons

X_moons, y_moons = make_moons(n_samples=10000, noise=0.4, random_state=42)
  • make_moons 함수는 scikit-learn 라이브러리에서 제공하는 데이터셋 생성 함수 중 하나로, 비선형 분류 문제를 시뮬레이션하기 위해 사용된다.

  • X_moons와 y_moons 데이터셋은 반달 모양의 비선형 분포를 가지고 있다.

b. 훈련셋과 테스트셋으로 쪼개기

1
2
3
4
5
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X_moons, y_moons,
                                                    test_size=0.2,
                                                    random_state=42)

- X_trainy_train은 훈련 데이터셋으로 사용되며, X_testy_test는 테스트 데이터셋으로 사용된다.

c. 교차검증을 사용하는 그리드 탐색 실행. 힌트: 다양한 max_leaf_nodes 값 활용.

c - 1. iris 데이터셋을 사용하여 Decision Tree 분류기를 학습

1
2
3
4
5
6
7
8
9
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier

iris = load_iris(as_frame=True)
X_iris = iris.data[["petal length (cm)", "petal width (cm)"]].values
y_iris = iris.target

tree_clf = DecisionTreeClassifier(max_depth=2, random_state=42)
tree_clf.fit(X_iris, y_iris)
DecisionTreeClassifier(max_depth=2, random_state=42)

c - 2. GridSearchCV를 사용하여 그리드 탐색을 실행

1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.model_selection import GridSearchCV

params = {
    'max_leaf_nodes': list(range(2, 100)),
    'max_depth': list(range(1, 7)),
    'min_samples_split': [2, 3, 4]
}
grid_search_cv = GridSearchCV(DecisionTreeClassifier(random_state=42),
                              params,
                              cv=3)

grid_search_cv.fit(X_train, y_train)
GridSearchCV(cv=3, estimator=DecisionTreeClassifier(random_state=42),
             param_grid={'max_depth': [1, 2, 3, 4, 5, 6],
                         'max_leaf_nodes': [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
                                            13, 14, 15, 16, 17, 18, 19, 20, 21,
                                            22, 23, 24, 25, 26, 27, 28, 29, 30,
                                            31, ...],
                         'min_samples_split': [2, 3, 4]})

최적의 분류기 확인

1
grid_search_cv.best_estimator_
DecisionTreeClassifier(max_depth=6, max_leaf_nodes=17, random_state=42)

grid_search_cv.best_estimator_는 그리드 탐색을 통해 얻은 최적의 모델(추정기)을 반환하는 코드

d. 최적 모델을 전체 훈련셋에 대해 훈련을 다시 진행한 다음 테스트셋에 대한 정확도를 확인할 것. 85% ~ 87% 정도의 정확도 나와야 함.

단, GridSearchCV는 자동으로 전체 훈련셋을 대상으로 한 번 더 훈련한다.

이 옵션을 원하지 않는다면 refit=False 옵션을 GridSearchCV 를 선언할 때 지정한다.

따라서 단순히 아래와 같이 바로 테스트셋에 대한 정확도를 확인할 수 있다.

1
2
3
4
from sklearn.metrics import accuracy_score

y_pred = grid_search_cv.predict(X_test)
accuracy_score(y_test, y_pred)
0.8595

8.

랜덤 포레스트(random forest) 모델을 훈련하는 방법을 살펴본다.

랜덤 포레스트는 여러 개의 결정트리로 구성된다.

a. 무작위로 선택된 100개의 초승달 훈련 샘플로 구성된 훈련셋을 1000개 생성한다.

이를 위해 사이킷런의 ShuffleSplit 클래스를 이용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from sklearn.model_selection import ShuffleSplit

n_trees = 1000    # 결정트리 수. 즉, 결정숲 크기.
n_instances = 100 # 각 결정트리 훈련에 사용되는 훈련셋 크기

mini_sets = []    # 1000개의 결정트리 훈련에 사용될 미니 훈련셋(크기 100)과 타깃셋 튜플들의 리스트 저장

# 1000개의 미니 훈련셋에 포함될 샘플들의 인덱스를 무작위 선택하는 객체 생성
rs = ShuffleSplit(n_splits=n_trees, test_size=len(X_train) - n_instances,
                  random_state=42)

# split 메서드가 X_train 대상으로 1000개의 미니 훈련셋에 포함될 샘플들의 인덱스를 무작위 선택
for mini_train_index, mini_test_index in rs.split(X_train): 
    X_mini_train = X_train[mini_train_index] # 미니 훈련셋
    y_mini_train = y_train[mini_train_index] # 타깃셋
    
    mini_sets.append((X_mini_train, y_mini_train))
  • ShuffleSplit은 scikit-learn 라이브러리에서 제공하는 교차 검증 전략 중 하나로, 데이터를 무작위로 섞은 후에 훈련셋과 검증셋으로 나누는 역할을 한다.

b. 앞서 찾은 최적의 모델을 각 미니 훈련셋에 대해 추가 훈련한 다음 테스트셋에 대한 정확도의 평균값을 계산한다.

결과는 80% 정도.

  • clone() 함수: 모델 복제. 동일 모델을 반복해서 사용하지 않기 위해 사용.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
from sklearn.base import clone

forest = [clone(grid_search_cv.best_estimator_) for _ in range(n_trees)]

accuracy_scores = []

for tree, (X_mini_train, y_mini_train) in zip(forest, mini_sets):
    tree.fit(X_mini_train, y_mini_train)
    
    y_pred = tree.predict(X_test)
    accuracy_scores.append(accuracy_score(y_test, y_pred))

np.mean(accuracy_scores)
0.8056605
  • clone(grid_search_cv.best_estimator_)를 통해 최적의 결정트리 분류기를 복제하여 리스트에 추가한다.

c. 이번에는 그런데 1000개의 모델의 정확도의 평균이 아닌 1000개의 모델이 가장 많이 예측하는 값을 예측값으로 사용해보자.

1
2
3
4
5
6
# 1000개의 모델이 테스트셋에 대해 예측한 값들로 이뤄진 2차원 어레이
Y_pred = np.empty([n_trees, len(X_test)], dtype=np.uint8)

# 1000개의 모델이 테스트셋에 대해 예측한 값
for tree_index, tree in enumerate(forest):
    Y_pred[tree_index] = tree.predict(X_test)
  • 위 코드는 1000개의 모델이 테스트셋에 대해 예측한 값을 Y_pred 2차원 배열에 저장하는 역할을 수행한다.

아래 코드는 테스트셋에 포함된 샘플별로 1000개의 모델이 예측한 값(클래스)의 최빈값(mode)를 계산한다.

1
2
3
from scipy.stats import mode

y_pred_majority_votes, n_votes = mode(Y_pred, axis=0, keepdims=True)
1
print(f"mode: {y_pred_majority_votes}", f"count: {n_votes}", sep='\n')
mode: [[1 1 0 ... 0 0 0]]
count: [[949 908 963 ... 918 993 615]]

d. 이 방식으로 계산된 예측값을 이용하면 정확도가 87% 정도로 상승한다.

  • y_pred_majority_votes.reshape([-1])는 차원을 줄여 1차원 어레이로 변환한다.
1
accuracy_score(y_test, y_pred_majority_votes.reshape([-1]))
0.873
  • reshape([-1])는 배열을 1차원으로 변형하되 원본 배열의 크기에 맞게 자동으로 조정하는 역할을 한다.

e. 결론: 이와 같이 작은 모델 여러 개의 예측값 최빈값을 이용하는 방식을 앙상블 학습이라 한다.

결정트리를 이용한 앙상블 학습 모델 중에 하나가 다음에 배울 랜덤 포레스트(random forest) 모델이다.

댓글남기기