머신러닝 교과서_파이토치편

[머신러닝 교과서] 2. 분류를 위한 머신러닝 기법들 - 2 (트리구조, KNN)

cheorish 2024. 12. 26. 00:58

이전 시간 이후에 남은 분류기들

🌲 결정 트리

  • 일련의 질문에 대한 결정을 통해 데이터를 분해하는 모델(스무고개라고 생각하면 쉽다)

직관적 그림

출처 : https://thebook.io/080223/

  • 설명
    • 루트 노드(Root Node): 트리의 시작점
    • 내부 노드(Internal Node): 특정 특성(feature)에 따라 데이터를 분할
    • 잎 노드(Leaf Node): 최종 예측값(클래스 레이블 또는 회귀값)을 나타냄 (그래프에는 없지만 최종 값이라고 보면 된다)
    • 가지(Branch): 노드 간의 연결 경로
  • 결정 트리의 작동원리
    • 특성 선택 (Feature Selection):
      • 가장 잘 데이터를 분할할 수 있는 최적의 특성을 선택
      • 주로 정보 이득(Information Gain), **지니 계수(Gini Index)**를 사용
    • 데이터 분할 (Splitting):
      • 선택된 특성에 따라 데이터를 두 개 이상의 그룹으로 분할
    • 재귀적 분할 (Recursive Partitioning)
      • 각 그룹에 대해 동일한 과정을 반복
    • 종료 조건 (Stopping Criteria):
      • 더 이상 분할할 수 없을 때 분할을 중지
      • 트리의 깊이가 너무 깊어지지 않도록 제약

결정 트리의 평가 척도

1. 정보이득

  • 분할을 통해 불확실성이 얼마나 감소했는지 측정(불순도라고도 함)
  • 수식 :

\( IG = H(parent) - \sum_{i=1}^{k} \frac{|D_i|}{|D|} H(D_i) \)

  • 수식 별 의미
    • \(IG\) : 정보 이득 (Information Gain)
    • \(H(parent)\) : 부모 노드의 엔트로피
    • \(\sum\) : 시그마(합산) 기호
    • \(\frac{|D_i|}{|D|}\) : 데이터 비율 (자식 노드 샘플 수 / 전체 샘플 수)
    • \(H(D_i)\) : 자식 노드의 엔트로피

2. 엔트로피

  • 데이터의 불확실성을 측정함
  • 수식 :
    • \(H\) = \(- \sum_{i=1}^{n} p_i \log_2(p_i)\)
  • 수식 별 의미
    • \(p_i\): 클래스 i에 속할 확률

3. 지니 불순도

  • 랜덤으로 샘플을 선택했을 때 잘못 분류될 확률을 측정
  • 수식 :
    • \(G\) = \(1 - \sum_{i=1}^{n} p_i^2\)
  • 수식 별 의미
    • \(p_i\): 클래스 i에 속할 확률

결정트리를 만들어보자!

# 필요한 라이브러리 불러오기
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from matplotlib.colors import ListedColormap

# 데이터 로드 및 전처리
iris = load_iris()
X = iris.data[:, [2, 3]]  # 꽃잎 길이와 너비만 사용
y = iris.target

# 학습 및 테스트 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=1, stratify=y
)

# 결정 트리 모델 학습
tree_model = DecisionTreeClassifier(criterion='gini', max_depth=4, random_state=1)
tree_model.fit(X_train, y_train)

# 학습 및 테스트 데이터를 결합
X_combined = np.vstack((X_train, X_test))
y_combined = np.hstack((y_train, y_test))

# 결정 경계 시각화 함수
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
    # 마커와 컬러맵 설정
    markers = ('s', 'x', 'o')
    colors = ('red', 'blue', 'lightgreen')
    cmap = ListedColormap(colors[:len(np.unique(y))])
    
    # 경계 영역 그리기
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())
    
    # 샘플 포인트 그리기
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], 
                    y=X[y == cl, 1],
                    alpha=0.8, 
                    c=colors[idx],
                    marker=markers[idx],
                    label=f'Class {cl}',
                    edgecolor='black')
    
    # 테스트 샘플 강조
    if test_idx:
        X_test, y_test = X[test_idx, :], y[test_idx]
        plt.scatter(X_test[:, 0], X_test[:, 1],
                    c='yellow', edgecolor='black', alpha=1.0,
                    linewidth=1, marker='o',
                    s=100, label='Test Set')

# 결정 경계 시각화
plot_decision_regions(X_combined,
                      y_combined,
                      classifier=tree_model,
                      test_idx=range(105, 150))

# 그래프 설정
plt.xlabel('Petal length [cm]')
plt.ylabel('Petal width [cm]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

출처 : https://thebook.io/080311/0174/
출처 : https://thebook.io/080311/
보시는 바와 같이 트리는 이런 스무고개 방식으로 데이터를 선택한다는 것을 직관적으로도 볼 수 있다

결정트리의 장단점

장점

  • 직관적이고 해석이 쉽다.
  • 범주형 데이터와 연속형 데이터 모두 처리 가능하다.
  • 데이터 전처리(정규화 등)가 거의 필요 없다.
  • 결과 해석이 용이하다.

단점

  • 과적합(Overfitting)의 위험
  • 작은 변화에도 민감 (데이터가 조금만 달라져도 트리 구조가 크게 변화)
  • 불균형 데이터에 약함

🎰 랜덤 포레스트

  • 랜덤 포레스트(Random Forest)는 여러 개의 결정 트리를 조합하여 예측하는 앙상블 학습 알고리즘
  • 개별 결정 트리의 약점을 보완하고 과적합문제를 줄이기 위해 사용
  • 주로 분류회귀문제에 사용

주요 학습법

배깅 (Bagging: Bootstrap Aggregating):

  • 동일한 알고리즘을 여러 번 반복 학습
  • 복원 추출 후(중요!) 여러 개의 샘플링 된 데이터셋 생성(복원추출로 인한 중복 추출이 있다)
  • 독립적 모델로 각각 학습
  • 최종 예측은 Voting을 통해 이루어짐
    • 병렬처리로 인한 과적합 발생이 적고 안정성이 보장

부스팅 (Boosting):

  • 순차적으로 약한 학습기를 향상시키며 학습시키는 방법
  • 이전 단계의 오류를 보완하며 새로운 모델을 학습
  • 각 단계별 잘못 예측된 데이터는 더 높은 가중치를 부여한 이후 다음 학습기에 반영
    • 알고리즘
      • AdaBoost
      • Gradient Boosting Machine(GBM)
      • XGBoost
      • LightGBM
      • CatBoost

학습 순서

  1. n개의 랜덤한 부트스트랩(bootstrap) 샘플을 뽑는다(훈련 데이터셋에서 중복을 허용하면서 랜덤하게 n개의 샘플을 선택).
  2. 부트스트랩 샘플에서 결정 트리를 학습. 각 노드에서 다음과 같이 함
    • 중복을 허용하지 않고 랜덤하게 d개의 특성을 선택
    • 정보 이득과 같은 목적 함수를 기준으로 최선의 분할을 만드는 특성을 사용해서 노드를 분할
  3. 단계 1~2를 k번 반복

랜덤포레스트를 응용한 다양한 분류기 알고리즘은 추후 정리 예정 오늘은 간단한 정의만 정리하려함!


➢ KNN / K-최근접 이웃

  • 최근접 이웃은 서로 가까운 포인트를 기반으로 유사한 결과를 묶는 것으로 작동
  • 새로운 데이터가 주어졌을 때 특정 데이터셋의 가장 가까운 K개의 이웃을 찾아 이웃들의 레이블을 참고하여 예측
  • 비모수적 알고리즘

출처: https://thebook.io/080223/

작동원리

  1. 거리 계산 (Distance Measurement)
    • 주어진 데이터 포인트와 기존 데이터 포인트 간의 거리를 계산
    • 주로 사용되는 거리 측정 방법:
      • 유클리드 거리 (Euclidean Distance)
      • 맨해튼 거리 (Manhattan Distance)
      • 코사인 유사도 (Cosine Similarity)

\(d(x, y) = \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2}\)

  1. K개의 이웃 선택
    • 거리 계산 후, 가장 가까운 K개의 이웃을 선택
    • K: 이웃의 수 (하이퍼파라미터)
  2. 다수결 투표 (Majority Voting, Classification)
    • 분류 문제에서는 K개의 이웃 중 가장 많이 나타나는 클래스로 예측
    • 회귀 문제에서는 K개의 이웃 값의 평균을 사용
  3. 결과 반환
    • 최종 결과를 예측

💻 예제코드

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=5, p=2,
                            metric='minkowski')
knn.fit(X_train_std, y_train)
plot_decision_regions(X_combined_std, y_combined,
                       classifier=knn, test_idx=range(105,150))
plt.xlabel('Petal length [standardized]')
plt.ylabel('Petal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

 

출처 : https://thebook.io/080311

 

  • KNN 모델에 다섯 개의 이웃을 지정했으므로 이 데이터셋에서 상기 그림과 같이 비교적 부드러운 결정 경계를 얻는 것을 확인