의사결정나무는 SVM과 마찬가지로 범용적인 머신러닝 알고리즘입니다. 여러 의사결정나무 분류기를 모아서 더 강력한 머신러닝 알고리즘이 되는 것이 랜덤 포레스트입니다. 이들 모두 기본적이지만 매우 강력한 도구로, 단순하고 유연하여 여전히 많은 사랑을 받고 있습니다.
- 의사결정나무
1.1 의사결정나무란?
의사결정나무를 IF/ELSE 문으로 구성된 깊이 중첩된 이진 트리 구조라고 생각할 수 있습니다. 예를 들어, 붓꽃 데이터셋에서 꽃잎 길이와 너비를 기준으로 종을 분류하는 경우를 살펴보겠습니다.
다음은 간단한 의사결정나무 구조입니다:
- 꽃잎 길이가 2.45보다 작으면 setosa,
- 그렇지 않으면 꽃잎 너비가 1.75보다 작으면 versicolor,
- 나머지는 virginica입니다.
따라서 임의의 붓꽃 샘플에 대해 우리는 의사결정나무의 루트 노드에서 리프 노드까지 순회하면서 붓꽃의 종을 결정할 수 있습니다.
1.2 의사결정나무 코드 실습
데이터셋을 불러오고 모델을 학습시킵니다:
import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
# 데이터셋 로드
df = pd.read_csv('https://example.com/iris.csv')
# 의사결정나무 모델
X = df[['petal_length', 'petal_width']].to_numpy()
y = df['species']
tree_clf = DecisionTreeClassifier(max_depth=2, random_state=42)
tree_clf.fit(X, y)
의사결정나무 시각화:
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(12,8))
plot_tree(tree_clf, filled=True);
루트 노드의 총 인스턴스 수는 150개이며, value = [50, 50, 50]으로 각 종별로 50개씩 분포되어 있음을 알 수 있습니다. 오른쪽 리프 노드(value = [0, 1, 45])에서는 0개의 setosa, 1개의 versicolor, 45개의 virginica 인스턴스가 있습니다.
Gini 계수는 다음과 같이 계산됩니다:
$$ G_i = 1 - \sum_{k=1}{n}{p2_{i,k}} $$
예를 들어, virginica 노드의 Gini 계수는 1-((0/46)**2 + (1/46)**2 + (45/46)**2) ≈ 0.043입니다.
- 랜덤 포레스트
2.1 대수의 법칙과 랜덤 포레스트
랜덤 포레스트는 의사결정나무들을 무작위로 조합하여 만들어집니다. 이를 통해 개별 의사결정나무보다 더 효과적인 모델을 얻을 수 있습니다.
대수의 법칙에 따르면, 충분히 많은 횟수의 시도를 통해 평균값이 안정적으로 나타납니다. 즉, 품질보다 수량을 늘려 모델의 성능을 향상시킬 수 있습니다.
2.2 랜덤 포레스트 코드 실습
2.2.1 새로운 데이터셋 사용
필요한 라이브러리를 추가합니다:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
데이터셋을 불러옵니다:
df = pd.read_csv("https://example.com/penguins_size.csv")
df = df.dropna()
df.head()
페인귄 데이터셋은 다음과 같은 특징과 레이블을 포함하고 있습니다:
- 특징: 섬(island), 부리 길이(culmen_length_mm), 부리 깊이(culmen_depth_mm), 날개 길이(flipper_length_mm), 체중(body_mass_g), 성별(sex)
- 레이블: 종(species): Chinstrap, Adélie, Gentoo
2.2.2 데이터 관찰
sns.pairplot(df, hue='species')
2.2.3 전처리
X = pd.get_dummies(df.drop('species', axis=1), drop_first=True)
y = df['species']
X.head()
2.2.4 데이터 학습
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=101)
model = RandomForestClassifier(n_estimators=10, max_features='auto', random_state=101)
model.fit(X_train, y_train)
from sklearn.metrics import accuracy_score
preds = model.predict(X_test)
accuracy_score(y_test, preds)
랜덤 포레스트 분류기로 학습한 결과 정확도는 약 97%입니다.
2.2.5 그리드 서치와 AdaBoost(추가)
AdaBoost를 사용하여 의사결정나무 분류기를 결합하고 그리드 서치로 최적 파라미터를 찾습니다:
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import AdaBoostClassifier
ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), random_state=101)
ada_clf.fit(X_train, y_train)
param_grid = {'n_estimators': [10, 15, 20, 25, 30], 'learning_rate': [0.01, 0.1, 0.5, 1], 'algorithm': ['SAMME', 'SAMME.R']}
grid = GridSearchCV(ada_clf, param_grid)
grid.fit(X_train, y_train)
print("최적 파라미터: ", grid.best_params_, " 최고 점수: ", grid.best_score_)