반응형

 

결정 트리

  • 분류와 회귀 작업 그리고 다중출력 작업도 가능한 머신러닝 알고리즘

 

결정 트리 학습과 시각화

  • DecisionTreeClassifier 시각화 예시
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier

iris = load_iris()
X = iris.data[:, 2:] # 꽃잎 길이와 너비
y = iris.target

tree_clf = DecisionTreeClassifier(max_depth=2, random_state=42)
tree_clf.fit(X, y)


from graphviz import Source
from sklearn.tree import export_graphviz

export_graphviz(
        tree_clf,
        out_file=os.path.join(IMAGES_PATH, "iris_tree.dot"),
        feature_names=iris.feature_names[2:],
        class_names=iris.target_names,
        rounded=True,
        filled=True
    )

Source.from_file(os.path.join(IMAGES_PATH, "iris_tree.dot"))

 

예측하기

  • 루트 노드(깊이가 0인 맨 꼭대기의 노드)에서 시작, petal length의 길이가 2.45cm보다 짧은지 검사
  • 만약 짧다면 왼쪽의 자식 노드로 이동, 이 경우가 리프 노드 이므로 추가적인 검사 수행하지 않음
  • 오른쪽 으로 이동한 것은 petal length가 2.45cm 보다 김, petal width가 1.75 보다 큰지 아닌지로 구분

결정 트리의 장점중 하나는 데이터 전처리가 거의 필요하지 않다는 것, 특성의 스케일을 맞추거나 평균을 원점에 맞추는 작업이 필요하지 않음

 

노드의 구성요소 설명

  • sample : 얼마나 많은 훈련 샘플이 적용되었는지 헤아린 것

  • value : 노드에서 각 클래스에 얼마나 많은 훈련 샘플이 있는지 알려줌

  • gini : 불순도를 측정한 값

    • 불순도 계산 공식

 

    • 위 그림은 결정트리의 결정경계를 시각화 한 것
    • 굵은 수직선이 루트 노드, 오른쪽에서 두번째 구분

결정 트리는 직관적이고 결정 방식을 이해하기 쉬움, 화이트 박스 모델

랜덤 포레스트나 신경망은 블랙박스 모델, 예측 성능이 뛰어나지만 예측을 만드는 연산 과정을 쉽게 확인가능 하지만 왜 그런 예측을 만드는지는 이해하기 어려움

 

클래스 확률 추정

  • 결정 트리는 한 샘플이 특정 클래스 k에 속할 확률을 추정할수 있음

클래스 확률 출력 예시

tree_clf.predict_proba([[5, 1.5]])
>> array([[0 , 0.90740741, 0.09259259]])

tree_clf.predict([[5, 1.5]])
>> array([1])

 

CART 훈련 알고리즘

  • 결정 트리를 훈련시키기 위해 CART 알고리즘을 사용

  • 훈련 세트를 하나의 특성 k의 임곗값

    를 사용해 두 개의 서브셋으로 나눔

  • 이후에 크기에 따른 가중치가 적용된 가장 순수한 서브셋으로 나눌수 있는

    짝을 찾음

  • 분류에 대한 CART의 비용 함수

    • max_depth 매개변수 수만큼 계속 둘로 나눔

 

계산 복잡도

  • 예측을 수행할때 결정 트리를 루트 노드에서 부터 리프 노드까지 탐색해야 함
  • 일반적으로 결정 트리는 거의 균형을 이루고 있기 때문에 결정 트리 탐색하기 위해서는
    개의 노드를 거쳐야 함
  • 각 노드는 하나의 특성값만 확인하기 때문에 예측에 필요한 전체 복잡도는 특성과 무관하게
    • 큰 훈련 세트를 다룰 때도 예측 속도가 빠름

 

지니 불순도 또는 엔트로피?

  • 기본적으로 지니 불순도가 사용, criterion 매개변수를 "entropy"로 지정하여 엔트로피 불순도를 사용할 수 있음

  • 분자가 안정되고 질서 정연하면 엔트로피가 0에 가까움

  • 모든 메시지가 동일할 때 엔트로피가 0이 됩니다.

  • 엔트로피 공식

  • 지니 불순도와 엔트로피는 둘다 큰 차이가 없음, 지니 불순도가 조금 더 계산이 빠르기 때문에 기본값으로 좋음, 다른 트리가 만들어지는 경우에는 지니 불순도가 좋음

 

규제 매개변수

  • 결정 트리는 훈련 데이터에 대한 제약 사항이 거의 없음

  • 제한을 두지 않으면 트리가 훈련 데이터에 아주 가깝게 맞추려고 해서 대부분 과대적합되기 쉬움

  • 결정 트리는 모델 파라미터가 전혀 없는 것이 아니라 훈련 되기 전에 파라미터 수가 결정되지 않음 - 비파라미터 모델

    • 모델 구조가 데이터에 맞춰져서 고정되지 않고 자유로움
  • 선형모델과 같은 파라미터 모델은 미리 정의된 모델 파라미터 수를 가지므로 자유도가 제한되고 과대적합될 위험이 줄어듦, 대신 과소 적합 위험은 커짐

  • 과대적합 방지를 위해 결정 트리의 자유도를 제한할 필요가 있음, 이를 규제라고 함

    • sklearn에서는 max_depth 매개변수로 조절, max_depth를 줄이면 모델을 규제하게 되고 과대적합의 위험이 감소
  • DecisionTreeClassifier는 결정 트리의 형태를 제한하는 다른 매개변수가 몇개 존재

    • min_samples_split : 분할되기 위해 노드가 가져야 하는 최소 샘플 수
    • min_samples_leaf : 리프노드가 가지고 있어야 할 최소 샘플 수
    • min_weight_fraction_leaf : min_samples_leaf와 같지만 가중치가 부여된 전체 샘플 수에서의 비율
    • max_leaf_nodes : 리프 노드의 최대 수
    • max_features : 각 노드에서 분할에 사용할 특성의 최대 수
    • min으로 시작하는 매개변수를 증가시키거나 max로 시작하는 매개변수를 감소시키면 모델에 규제가 커짐
    • 왼쪽은 기본, 오른쪽은 min_samples_leaf = 4
    • 왼쪽 모델은 과대적합되었고 오른쪽 모델은 일반화 성능이 더 좋음

제한 없이 결정 트리를 훈련시키고 불필요한 노드를 가지치기하는 알고리즘 존재

순도를 높이는 것이 통계적으로 큰 효과가 없다면 리프 노드 바로 위의 노드 제거가능

  • 카이제곱 검증
    • 우연히 상승된 성능인지 검증 p-값을 통해 5% 보다 높으면 불필요 간주, 가지치기는 불필요한 노드가 모두 제거 될때까지 계속됨

 

회귀

  • 결정 트리는 회귀 문제에서도 사용 가능
  • sklearn의 DecisionTreeRegressor를 사용

결정트리 회귀 예시

from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor(max_depth=2, random_state=42)
tree_reg.fit(X, y)

  • 각 노드에서 클래스를 예측하는 대신 어떤 값을 예측한다는 점
  • 인 값을 넣으면 결과적으로
    인 리프노드에 도달
    • 각 영역의 예측값은 항상 그 영역에 있는 target 값의 평균
    • 예측값과 가능한 많은 샘플이 가까이 있도록 영역 분할
    • 분류와 같이 회귀에서도 결정 트리가 과적합 되기 쉬움, 규제가 없다면 위 그림에서 왼쪽과 같음

 

불안정성

  • 결정 트리가 장점이 많음, 결정 트리는 이해하고 해석하기 쉽고, 사용하기 편하고, 여러 용도로 사용할 수 있으며, 성능도 뛰어남
  • 결정트리는 계단 모양의 결정 경계를 생성 -> 훈련 세트의 회전에 민감
      • 위 그림에서 왼쪽을 45도 회전한것이 오른쪽, 결과적으로 결정트리가 불규칙해짐
      • 해결방법은 훈련 데이터를 더 좋은 방향으로 회전시키는 PCA 기법을 사용
    • 훈련 데이터에 있는 작은 변화에도 매우 민감

 

연습 문제

 

1. 백만 개의 샘플을 가진 훈련 세트에서 (규제 없이) 훈련시킨 결정 트리의 깊이는 대략 얼마일까요?

m개의 리프 노드를 포함한 균형이 잘 잡힌 이진 트리의 깊이는 log2(m)을 반올림한 것과 같음log2(m)=log(m)/log(2)

이진 결정 트리를 제한을 두지 않고 훈련시키면 훈련 샘플마다 하나의 리프 노드가 되므로 어느 정도 균형이 잘 잡힌 트리가 된다. 따라서 훈련 세트에 백만 개 샘플이 있다면 결정 트리의 깊이는

log2(106)=20 이 됨

 

2. 한 노드의 지니 불순도가 보통 그 부모보다 작을까요, 아니면 클까요? 일반적으로 작거나 클까요, 아니면 항상 작거나 클까요?

한 노드의 지니 불순도는 일반적으로 부모의 불순도 보다 낮다. 이는 자식의 지니 불순도의 가중치 합이 최소화되는 방향으로 각 노드를 분할하는 CART 훈련 알고리즘의 비용 함수 때문

 

3. 결정 트리가 훈련 세트에 과대적합되었다면 max_depth를 줄이는 것이 좋을까요?

모델에 규제를 가해야하기 때문에 max_depth를 낮추는 것이 좋음, 차수 줄이기

 

4. 결정 트리가 훈련 세트에 과소적합되었다면 입력 특성의 스케일을 조정하는 것이 좋을까요?

결정 트리는 훈련 데이터의 스케일이나 원점에 맞추어져 있는지 상관하지 않음, 스케일 조절이 무의미

 

5. 백만 개의 샘플을 가진 훈련 세트에 결정 트리를 훈련시키는 데 한 시간이 걸렸다면, 천만 개의 샘플을 가진 훈련 세트에 결정 트리를 훈련시키는 데는 대략 얼마나 걸릴까요?

결정 트리 훈련의 계산 복잡도는 O(n×mlog(m))

훈련 세트의 크기에 10을 곱하면 훈련 시간 10×log(10m)/log(m)

m=10**6이면, k= 11.7시간

 

6. 십만 개의 샘플을 가진 훈련 세트가 있다면 presort=True로 지정하는 것이 훈련 속도를 높일까요?

훈련 세트가 수천 개 이하의 샘플 정도로 작을 경우에만 presort=True로 지정했을 때, 데이터를 미리 정렬하여 훈련 속도를 높일 수 있다. 하지만 훈련 세트가 클 경우에는 속도가 많이 느려짐

 

7. moons 데이터셋에 결정 트리를 훈련시키고 세밀하게 튜닝해보세요.

from sklearn.datasets import make_moons

X, y = make_moons(n_samples=10000, noise=0.4, random_state=42)

from sklearn.model_selection import train_test_split

# 훈련세트 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)


from sklearn.model_selection import GridSearchCV

# 매개변수 찾기
params = {'max_leaf_nodes': list(range(2, 100)), 'min_samples_split': [2, 3, 4]}
grid_search_cv = GridSearchCV(DecisionTreeClassifier(random_state=42), params, verbose=1, cv=3)

grid_search_cv.fit(X_train, y_train)


from sklearn.metrics import accuracy_score

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

>> 0.8695

 

8. 랜덤 포레스트를 만들어보세요.

from sklearn.model_selection import ShuffleSplit

n_trees = 1000
n_instances = 100

mini_sets = []

# 훈련 세트의 서브셋 1000개 + 무작위 선택한 100개 샘플
rs = ShuffleSplit(n_splits=n_trees, test_size=len(X_train) - n_instances, random_state=42)
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))


# 최적의 매개변수를 사용해 각 서브셋에 결정 트리를 훈련
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.80544999

# 각 테스트 세트 샘플에 대해 1,000개의 결정 트리 예측을 만들고 다수로 나온 예측만 선택
Y_pred = np.empty([n_trees, len(X_test)], dtype=np.uint8)

for tree_index, tree in enumerate(forest):
    Y_pred[tree_index] = tree.predict(X_test)


from scipy.stats import mode
y_pred_majority_votes, n_votes = mode(Y_pred, axis=0)


accuracy_score(y_test, y_pred_majority_votes.reshape([-1]))
>> 0.872

반응형

'Study > Self Education' 카테고리의 다른 글

핸즈온 머신러닝 - 8  (0) 2024.06.18
핸즈온 머신러닝 - 7  (0) 2024.06.18
핸즈온 머신러닝 - 5  (0) 2024.06.17
핸즈온 머신러닝 - 4  (2) 2024.06.17
핸즈온 머신러닝 - 3  (1) 2024.06.15