Py) ML - 의사결정나무

Py) ML - 의사결정나무

Python에서 의사결정나무(Decision Tree) 분석을 하는 방법을 알아보자.


※ 본 내용에서 사용하는 model_classification_machine_failure.csv, model_regression_ins_charges.csv 파일은 별도로 다운로드 받아야 한다.
model_classification_machine_failure.csv 다운받기 [클릭]
model_regression_ins_charges.csv 다운받기 [클릭]

이론

공통

대표적인 머신러닝 지도학습 모델인 의사결정나무(Decision Tree)는 분류(Classification)와 회귀(Regression) 문제에 모두 사용할 수 있다.

분류 모델

분류를 위해 사용되는 모델이며 종속변수에 2개 이상의 범주가 있는 경우에 사용한다. 이 때 각 범주는 0부터 1씩 증가하는 등차수열의 정수로 표현하는 것을 권장한다.

의사결정나무 분류모델(분류 나무)을 구현하기 위해서는 sklearn 라이브러리의 DecisionTreeClassifier() 클래스를 사용한다. 해당 클래스의 공식 문서에서 안내하는 파라미터는 다음과 같다.

[criterion]: 유형 - str, 기본값 - “gini”

  • 설명: 분할 품질 측정 기준
  • 입력값 범위: {“gini”, “entropy”, “log_loss”}

[splitter]: 유형 - str, 기본값 - “best”

  • 설명: 노드 분할 전략
  • 입력값 범위: {“best”, “random”}

[max_depth]: 유형 - int, 기본값 - None

  • 설명: 트리의 최대 깊이
  • 입력값 범위: int, None

[min_samples_split]: 유형 - int or float, 기본값 - 2

  • 설명: 내부 노드를 분할하는데 필요한 최소 샘플 수
  • 입력값 범위: int, float
    ※ 만약 실수(float)가 입력될 경우 ceil(min_samples_split * n_samples) 공식으로 처리됨

[min_samples_leaf]: 유형 - int or float, 기본값 - 1

  • 설명: 잎사귀 노드에 있어야 할 최소 샘플 수
  • 입력값 범위: int, float

[min_weight_fraction_leaf]: 유형 - float, 기본값 - 0.0

  • 설명: 잎사귀 노드에 있어야 할 최소 가중치 비율
  • 입력값 범위: float

[max_features]: 유형 - int or float or str, 기본값 - None

  • 설명: 각 분할에서 고려할 최대 특성 수
  • 입력값 범위: int, float, {“sqrt”, “log2”}, None

[random_state]: 유형 - int, RandomState instance or None, 기본값 - None

  • 설명: 난수 seed 설정
  • 입력값 범위: int, RandomState instance, None
    ※ RandomState instance: np.random.RandomState이며 난수 생성 상태를 더 세밀하게 제어 가능

[max_leaf_nodes]: 유형 - int, 기본값 - None

  • 설명: 잎사귀 노드의 최대 수
  • 입력값 범위: int, None

[min_impurity_decrease]: 유형 - float, 기본값 - 0.0

  • 설명: 분할을 수행하기 위한 불순도 감소 최소량
  • 입력값 범위: float

[class_weight]: 유형 - dict or list of dict or str, 기본값 - None

  • 설명: 클래스 가중치
  • 입력값 범위: dict, list of dict, “balanced”, None

[ccp_alpha]: 유형 - non-negative float, 기본값 - 0.0

  • 설명: 최소 비용 복잡성 가지치기(Minimal Cost-Complexity Pruning)의 복잡성 매개변수
  • 입력값 범위: non-negative float

[monotonic_cst]: 유형 - array-like of shape (n_features), 기본값 - None

  • 설명: 특성(feature)의 단조성(monotonicity) 제약(constraint)
  • 입력값 범위: array-like of shape (n_features), None

회귀 모델

수치형 종속변수를 예측하는 모델이며 종속변수가 연속적인 수치형 데이터인 경우에 사용한다.

의사결정나무 회귀모델(회귀 나무)을 구현하기 위해서는 sklearn 라이브러리의 DecisionTreeRegressor() 클래스를 사용한다. 해당 클래스의 공식 문서에서 안내하는 파라미터는 대부분 DecisionTreeClassifier() 클래스와 같으며 그 중 입력값이 다른 “criterion” 파라미터에 대한 설명은 다음과 같다.

[criterion]: 유형 - str, 기본값 - “sqared_error”

  • 설명: 분할 품질 측정 기준
  • 입력값 범위: {“squared_error”, “friedman_mse”, “absolute_error”, “poisson”}

예제 코드

분류 모델

먼저 다음과 같이 라이브러리와 데이터를 준비하고 사용하는 데이터와 관련된 전처리 코드는 [Py) 전처리 - ML 분류모델용 - 01] 게시글을 참고하자.
model_classification_machine_failure.csv 다운받기 [클릭]

1
2
3
4
5
6
7
8
import pandas as pd

from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score # 분류모델 평가(Accuracy)
from sklearn.metrics import f1_score # 분류모델 평가(F1 score)

df_machine = pd.read_csv("data/model_classification_machine_failure.csv")
df_machine.head(2)
id is_failure type_H type_L type_M temp_air temp_process speed torque tool_wear Xgrp
0 55100 0 0.0 1.0 0.0 0.399154 1.352290 -0.877336 0.926149 1.084815 train
1 49876 0 0.0 1.0 0.0 0.001026 -0.266219 -0.482743 0.596147 -0.889909 train

“Xgrp” 변수을 기준으로 학습과 평가 데이터세트로 나눈 후 학습에 불필요한 “id”, “Xgrp” 변수를 제거한다.

1
2
3
4
5
6
df_train = df_machine.loc[df_machine["Xgrp"] == "train", ]
df_test = df_machine.loc[df_machine["Xgrp"] == "test", ]
df_train = df_train.drop(columns = ["id", "Xgrp"]).reset_index(drop = True)
df_test = df_test.drop( columns = ["id", "Xgrp"]).reset_index(drop = True)

df_train.head(2)
is_failure type_H type_L type_M temp_air temp_process speed torque tool_wear
0 0 0.0 1.0 0.0 0.399154 1.352290 -0.877336 0.926149 1.084815
1 0 0.0 1.0 0.0 0.001026 -0.266219 -0.482743 0.596147 -0.889909

DecisionTreeClassifier() 클래스를 사용하여 모델의 최대 깊이(max_depth)를 5로 설정한 후 학습을 진행한다. 여기서 필요시 각 파라미터를 조정하여 학습을 진행할 수 있다.

1
2
3
4
5
6
model_c = DecisionTreeClassifier(max_depth = 5, random_state = 123) # 모델 생성
model_c.fit(X = df_train.drop(columns = "is_failure"), # 모델 학습
y = df_train["is_failure"])
pred = model_c.predict(df_test.drop(columns = "is_failure")) # 모델 예측
pred[:4]
## array([0, 0, 0, 0], dtype=int64)

학습된 모델을 평가하기 위해 Accuracy와 F1-score를 계산해본다.

1
2
3
4
5
accuracy_score(y_true = df_test["is_failure"], y_pred = pred)
## 0.9759599332220368

f1_score(y_true = df_test["is_failure"], y_pred = pred)
## 0.5135135135135135

회귀 모델

먼저 다음과 같이 라이브러리와 데이터를 준비하고 사용하는 데이터와 관련된 전처리 코드는 [Py) 전처리 - ML 회귀모델용 - 01] 게시글을 참고하자.
model_regression_ins_charges.csv 다운받기 [클릭]

1
2
3
4
5
6
7
8
import pandas as pd

from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error # 회귀모델 평가(MSE, RMSE)
from sklearn.metrics import mean_absolute_percentage_error # 회귀모델 평가(MAPE)

df_ins = pd.read_csv("data/model_regression_ins_charges.csv")
df_ins.head(2)
id charges gender is_smoker age bmi children region_B region_C region_D Xgrp
0 10182 4796 0 0 0.326087 0.641916 0.2 0.0 0.0 0.0 train
1 11118 12949 1 0 0.826087 0.476190 0.8 0.0 0.0 0.0 train

“Xgrp” 변수을 기준으로 학습과 평가 데이터세트로 나눈 후 학습에 불필요한 “id”, “Xgrp” 변수를 제거한다.

1
2
3
4
5
6
df_train = df_ins.loc[df_ins["Xgrp"] == "train", ]
df_test = df_ins.loc[df_ins["Xgrp"] == "test", ]
df_train = df_train.drop(columns = ["id", "Xgrp"]).reset_index(drop = True)
df_test = df_test.drop( columns = ["id", "Xgrp"]).reset_index(drop = True)

df_train.head(2)
charges gender is_smoker age bmi children region_B region_C region_D
0 4796 0 0 0.326087 0.641916 0.2 0.0 0.0 0.0
1 12949 1 0 0.826087 0.476190 0.8 0.0 0.0 0.0

DecisionTreeRegressor() 클래스를 사용하여 이웃의 수(n_neighbors)를 3으로 설정한 후 학습을 진행한다. 여기서 필요시 각 파라미터를 조정하여 학습을 진행할 수 있다.

1
2
3
4
5
6
model_r = DecisionTreeRegressor(max_depth = 5, random_state = 123) # 모델 생성
model_r.fit(X = df_train.drop(columns = "charges"), # 모델 학습
y = df_train["charges"])
pred = model_r.predict(df_test.drop(columns = "charges")) # 모델 예측
pred[:4]
## array([24252.2, 12285.43037975, 8349.57894737, 5649.07894737])

학습된 모델을 평가하기 위해 RMSE와 MAPE를 계산해본다.

1
2
3
4
5
mean_squared_error(y_true = df_test["charges"], y_pred = pred) ** 0.5
## 5442.427723823824

mean_absolute_percentage_error(y_true = df_test["charges"], y_pred = pred)
## 0.3681418251194161
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×