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


보시는 바와 같이 트리는 이런 스무고개 방식으로 데이터를 선택한다는 것을 직관적으로도 볼 수 있다
결정트리의 장단점
장점
- 직관적이고 해석이 쉽다.
- 범주형 데이터와 연속형 데이터 모두 처리 가능하다.
- 데이터 전처리(정규화 등)가 거의 필요 없다.
- 결과 해석이 용이하다.
단점
- 과적합(Overfitting)의 위험
- 작은 변화에도 민감 (데이터가 조금만 달라져도 트리 구조가 크게 변화)
- 불균형 데이터에 약함
🎰 랜덤 포레스트
- 랜덤 포레스트(Random Forest)는 여러 개의 결정 트리를 조합하여 예측하는 앙상블 학습 알고리즘
- 개별 결정 트리의 약점을 보완하고 과적합문제를 줄이기 위해 사용
- 주로 분류와 회귀문제에 사용
주요 학습법
배깅 (Bagging: Bootstrap Aggregating):
- 동일한 알고리즘을 여러 번 반복 학습
- 복원 추출 후(중요!) 여러 개의 샘플링 된 데이터셋 생성(복원추출로 인한 중복 추출이 있다)
- 독립적 모델로 각각 학습
- 최종 예측은 Voting을 통해 이루어짐
- 병렬처리로 인한 과적합 발생이 적고 안정성이 보장
부스팅 (Boosting):
- 순차적으로 약한 학습기를 향상시키며 학습시키는 방법
- 이전 단계의 오류를 보완하며 새로운 모델을 학습
- 각 단계별 잘못 예측된 데이터는 더 높은 가중치를 부여한 이후 다음 학습기에 반영
- 알고리즘
- AdaBoost
- Gradient Boosting Machine(GBM)
- XGBoost
- LightGBM
- CatBoost
- 알고리즘
학습 순서
- n개의 랜덤한 부트스트랩(bootstrap) 샘플을 뽑는다(훈련 데이터셋에서 중복을 허용하면서 랜덤하게 n개의 샘플을 선택).
- 부트스트랩 샘플에서 결정 트리를 학습. 각 노드에서 다음과 같이 함
- 중복을 허용하지 않고 랜덤하게 d개의 특성을 선택
- 정보 이득과 같은 목적 함수를 기준으로 최선의 분할을 만드는 특성을 사용해서 노드를 분할
- 단계 1~2를 k번 반복
랜덤포레스트를 응용한 다양한 분류기 알고리즘은 추후 정리 예정 오늘은 간단한 정의만 정리하려함!
➢ KNN / K-최근접 이웃
- 최근접 이웃은 서로 가까운 포인트를 기반으로 유사한 결과를 묶는 것으로 작동
- 새로운 데이터가 주어졌을 때 특정 데이터셋의 가장 가까운 K개의 이웃을 찾아 이웃들의 레이블을 참고하여 예측
- 비모수적 알고리즘

작동원리
- 거리 계산 (Distance Measurement)
- 주어진 데이터 포인트와 기존 데이터 포인트 간의 거리를 계산
- 주로 사용되는 거리 측정 방법:
- 유클리드 거리 (Euclidean Distance)
- 맨해튼 거리 (Manhattan Distance)
- 코사인 유사도 (Cosine Similarity)
\(d(x, y) = \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2}\)
- K개의 이웃 선택
- 거리 계산 후, 가장 가까운 K개의 이웃을 선택
- K: 이웃의 수 (하이퍼파라미터)
- 다수결 투표 (Majority Voting, Classification)
- 분류 문제에서는 K개의 이웃 중 가장 많이 나타나는 클래스로 예측
- 회귀 문제에서는 K개의 이웃 값의 평균을 사용
- 결과 반환
- 최종 결과를 예측
💻 예제코드
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()

- KNN 모델에 다섯 개의 이웃을 지정했으므로 이 데이터셋에서 상기 그림과 같이 비교적 부드러운 결정 경계를 얻는 것을 확인
'머신러닝 교과서_파이토치편' 카테고리의 다른 글
| [머신러닝 교과서] 2. 분류를 위한 머신러닝 기법들 - 1 (Logistic Regression, SVM) (2) | 2024.12.26 |
|---|---|
| [머신러닝 교과서] 1. 퍼셉트론과 아달린(완전 배치 경사하강법, 미니 배치 경사하강법) (2) | 2024.12.08 |