본문 바로가기

Machine Learning/코드 실습

Decision Tree 실습

앞에서 정리했던 Decision Tree를 sklearn으로 실습해보자.

2023.12.04 - [Machine Learning] - Decision Tree

 

 

먼저 기본적인 패키지를 import 해준다

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

 

seaborn을 통해 titanic 데이터를 로드하고 간단한 전처리를 수행한다.

titanic = sns.load_dataset('titanic')

# nan이 대부분인 컬럼 제거
titanic.drop(columns='deck', inplace=True)

# 그 밖의 nan값이 포함된 샘플 제거
titanic.dropna(inplace=True)

# 중복된 값 제거
titanic.drop_duplicates(inplace=True)

 

추가적으로 데이터 타입이 object, category, bool인 feature에 대해서 label encoding을 통해 정수로 바꿔준다.

from sklearn.preprocessing import LabelEncoder

dtypes = titanic.dtypes
string_columns = [col for col in dtypes.index if dtypes[col] == 'object' or dtypes[col] == 'category' or dtypes[col] == 'bool']

for col in string_columns:
  le = LabelEncoder()
  titanic[col] = le.fit_transform(titanic[col])

 

전처리된 데이터를 확인해보면 다음과 같다.

titanic.head()

 

alive 컬럼의 경우 survived와 값이 동일하다. data leakage이므로 학습 데이터에서 해당 컬럼을 제거한다.

from sklearn.model_selection import train_test_split

target = 'survived'
x = titanic.drop(columns=[target, 'alive'])
y = titanic[target]
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)

 

depth를 1부터 20까지 달리하면서 train, test 데이터의 loss를 확인하여 과적합되지 않는 적절한 depth를 알아보자.

이 과정이 이전 글에서 배웠던 pre-pruning이다.

 

그리고 분류 모델을 학습할 때 class_weight을 꼭 지정해주는 것이 좋다. 안그러면 클래스 불균형 문제의 경우 모델이 majority 클래스로 과도하게 예측할 가능성이 높다.

from sklearn.tree import DecisionTreeClassifier
from sklearn.utils.class_weight import compute_class_weight
from sklearn.metrics import log_loss

train_loss = []
test_loss = []
cw = compute_class_weight(class_weight="balanced", classes=np.array([0, 1]), y=y.values)
class_weight = dict(zip([0, 1], cw))

for depth in range(1, 21):
  model = DecisionTreeClassifier(
      max_depth=depth,
      class_weight=class_weight,
      random_state=42
  )
  model.fit(x_train, y_train)
  
  train_loss.append(log_loss(y_train, model.predict_proba(x_train)))
  test_loss.append(log_loss(y_test, model.predict_proba(x_test)))

 

이를 train_loss와 test_loss를 plot해보면 depth가 3인 경우가 가장 좋은 모델이라고 볼 수 있다.

plt.plot(range(1, 21), train_loss, label='train')
plt.plot(range(1, 21), test_loss, label='test')
plt.axvline(x=3, color='red', linestyle='--', label='best depth')
plt.xlabel('depth')
plt.ylabel('loss')
plt.legend()
plt.grid()
plt.show()

다음과 같이 feature importance도 확인할 수 있다.

feature_importances = pd.Series(model.feature_importances_, index=x.columns)
feature_importances = feature_importances.sort_values(ascending=False)

sns.barplot(x=feature_importances.values, y=feature_importances.index)
plt.show()

 

다음과 같이 트리를 시각화하는 것도 가능하다.

import graphviz
from sklearn.tree import export_graphviz

model = DecisionTreeClassifier(
    max_depth=3,
    class_weight=class_weight,
    random_state=42
)
model.fit(x_train, y_train)

export_graphviz(model,
                out_file='tree.dot',
                filled=True,
                rounded=True,
                feature_names=x.columns,
                class_names=['dead', 'survived']
                )

with open('tree.dot') as file_reader:
    dot_graph = file_reader.read()

graphviz.Source(dot_graph)

 

  • DecisionTreeClassifier의 split criterion의 default 값이 gini이기 때문에 gini를 기준으로 split을 수행하였다.
  • 자식 노드로 분기할 때 feature importance 값이 큰 adult male, class, fare, age를 기준으로만 분기한 것을 확인할 수 있다.

DecisionTreeClassifier의 자세한 파라미터는 sklearn document에서 확인할 수 있다.

https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html

 

sklearn.tree.DecisionTreeClassifier

Examples using sklearn.tree.DecisionTreeClassifier: Release Highlights for scikit-learn 1.3 Classifier comparison Plot the decision surface of decision trees trained on the iris dataset Post prunin...

scikit-learn.org

'Machine Learning > 코드 실습' 카테고리의 다른 글

KNN  (0) 2023.11.25