minhui study

머신러닝의 이해와 지도학습을 이용한 분류(의사결정나무) 본문

Python/챗봇

머신러닝의 이해와 지도학습을 이용한 분류(의사결정나무)

minhui 2020. 7. 9. 19:34

의사결정나무 Decision tree

의사결정나무는 데이터 분포를 나누는 지도학습의 분류에 해당하는 모델

연속적인 질문을 통해 예측 결과를 제공하는 예측 모델로서 사람이 조건에 따라 행동하고 판단하는 것을 머신러닝에

응용한 것이 의사결정나무다.  즉, 의사결정에 필요한 규칙을 나무 형태로 분류해 나가는 분석 기법을 말한다.

 

https://thebook.io/006723/ch10/03/01/

알고리즘 해석이 용이하다.

   : 처리 결과를 해석하기가 쉬운 점이 의사결정나무의 가장 큰 장점이다. 의사결정나무 모델을 이용하여 데이터를 예측하는 경우도 있고 데이터가 분류되어가는 과정에서 분류의 기준이 되는 중요한 아이템을 찾는 경우에도 쓰일 수 있다. 

 

수치형, 범주형 데이터도 적용이 가능하다.

   : 입력 데이터로 숫자 데이터나 범주 데이터 등 다양한 데이터 형식을 사용할 수 있다.

예를 들어 고객 성별 등의 카테고리 데이터와 구매 금액 등의 수치 데이터를 모두 모델링 시 변수로 사용할 수 있다. 

 

필요한 전처리가 적다.

   : 의사결정나무는 데이터를 어떤 기준으로 분할되는지 쉽게 볼 수 있고 그중에서 어떤 특징으로 분할하는 게 가장 효과적인지도 알 수 있다. 

 

과적합되기 쉽다.

  : 이것은 부정적인 특징인데, 의사결정나무는 아무래도 모델링시에 이용된 데이터에 대해 과적합되기 쉽다. 그래서 훈련용 데이터를 검토해서 이상값이나 예외값을 정제하는 등 대책이 필요하다.

 

'예측'과 '회귀'도 가능하다.

  : 예를 들어 마케팅의 대상 여부에 대한 예측으로도 쓰일 수 있지만 그 목적을 바꿔서 성공적인 마케팅을 하기 위해 영향을 가장 많이 주는 변수를 찾는 데도 쓸 수 있다.

 

 

 

의사결정나무의 대표 알고리즘

 

1) CART(Classification and Regression Tress)

 

카트 알고리즘은 의사결정나무 방법론 중 가장 잘 알려진 방법론 가운데 하나로 지니 계수 또는 분산의 감소량을 사용해 나무의 가지를 이진 분리한다.

(범주형 변수에 대해서는 지니 계수를 사용하고, 연속형 변수에 대해서는 분산의 감소량을 사용한다.)

의사결정나무는 지니 계수가 높은 조건을 잧고 자식 트리 노드에 걸쳐 반복적으로 분할한다. 모든 데이터가 특정 분류에 속하게 된다면 분할을 멈춘고 이런 절차로 의사결정나무의 가지가 만들어진다.

 

* 지니 계수 : 머신러닝에서는 데이터의 속성들이 많이 일치하면 1이 되고 반대로 속성들이 제 각기 다른 형태이면 0이 된다. 의사결정나무는 지니 계수가 높은 속성을 기준으로 분할한다. 즉 데이터의 속성이 비슷한 것끼리 묶으면서 분류하는 것이다.

 

2) C4.5(C5.0)

C4.5(C5.0)의 전신인 ID3는 분할의 평가 기준으로 정보 이득을 사용했지만 C4.5(C5.0)은 이득 비율을 이용한다. 이진 분류에 국한되지 않는 것이 CART와 큰 차이다. 카트에서는 2가지밖에 분기할 수 없지만, C4.5는 3가지 분기가 가능하다.

 

 

 

 

사이킷런으로 시작하는 의사결정나무

이제 대표적인 머신러닝 오픈소스 라이브러리인 사이킷런(Scikit-learn)을 이용해 의사결정나무를 직접 실습해보자

python, numpy, scipy, scikit-learn까지 다 설치한 후 다음과 같은 코드의 파일 이름을 version_check.py로 한 후 파일을 작성한 위치에서 cmd창에 python version_check.py를 입력하여 화면이 제대로 출력된다면 사이킷런이 정상적으로 설치가 되었다는 것을 알 수 있다. 

import sys
print("Python 버전: {}".format(sys.version))

import numpy as np
print("NumPy 버전: {}".format(np.__version__))

import scipy as sp
print("SciPy 버전: {}".format(sp.__version__))

import sklearn
print("scikit-learn 버전: {}".format(sklearn.__version__))

 

 

 

붓꽃 데이터를 활용한 의사결정나무 구현해보기

사이킷런에서 의사결정나무 알고리즘은 tree모듈의 DecisionTreeClassifier이라는 클래스로 구현되어 있다.

사이킷런은 머신러닝 알고리즘이 내장되어 있을 뿐만 아니라 의사결정나무의 구조를 DOT 파일 확장자로 출력하는 특수한 기능이 있다. 그 기능을 사용하여 나무 구조를 시각화해보자

 

그 전에 붓꽃 데이터에 정보가 어떻게 들어가있는지 확인해보았다.

from sklearn.datasets import load_iris
dataset = load_iris()

print(dataset['data'])
print(dataset['target'])
print(dataset['target_names'])
print(dataset['feature_names'])

 

 

 

첫 줄을 보면 6.3 / 3.4 / 5.6 / 2.4 이렇게 4개의 데이터가 있는 걸 볼 수 있는데 이것은 각각 sepal length, sepal width, petal length, petal width를 나타낸다.

 

그리고 target은 0: Setosa, 1:Versicolour, 2:Virginica로 숫자로 바꾸어 저장되어 있다.

 

 

 

다음은 붓꽃 데이터를 이용해서 의사결정나무를 만드는 코드이다.

*참고로 사이킷런은 외부 웹 사이트에서 파일을 다운로드 할 필요가 없는 몇 개의 표준 데이터 세트를 제공하고 그 중에 하나가 붓꽃 데이터이다.

# -*- coding: utf-8 -*-
# sklearn 모듈 임포트
from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree

def main():
    #iris 데이터 로드(붓꽃 데이터) [1번]
    dataset = datasets.load_iris()

    features = dataset.data
    targets = dataset.target

    #꽃입의 길이와 넓이 정보만 특징으로 사용 [2번]
    petal_features = featurses[:, 2:]

    #의사결정모델 클래스 생성 [3번]
    cIris = DecisionTreeClassifier(criterion='entropy', max_depth=3)
    #모델을 학습 [4번]
    cIris.fit(petal_features, targets)

    #DOT 언어의 형식으로 결정 나무의 형태를 출력
    with open('iris-dtree.dot', mode='w') as f:
        tree.export_graphviz(cIris, out_file=f)

if __name__=='__main__':
        main()

[1번] : 사이킷런은 기본적으로 iris 즉, 붓꽃 데이터를 포함하고 있다. 이 데이터는 load_iris()함수를 통해 읽어올 수 있다.

 

[2번] : features에 iris데이터를 가져온 후 features 정보 중에서 꽃잎길이와 너비만 가져와서 petal_features변수에 대입한다. targets에는 iris품종 데이터가 0: Setosa, 1:Versicolour, 2:Virginica로 숫자로 바꾸어 저장되어 있다.

 

[3번] : DecisionTreeClassifier는 사이킷런에서 제공하는 의사결정나무 모델이다. 이를 통해 Tree모델을 학습한다.

criterion = 'entropy'는 엔트로피를 불순도 계산방법으로 적용한다는 의미이다.

DecisionTreeClassifier가 지원하는 불순도 계산방법은 지니 계수와 엔트로피이다. 기본값은 지니 계수이고, max_depth는 가지의 깊이다. 

criterion = 'gini' 

 : 지니 계수는 분류를 잘못하는 확률을 최소화하기 위한 목적으로 오분류의 척도로 사용된다. 

트리의 모든 가능한 분할 방법에서 지니 계수를 측정한 후 가장 낮은 것을 선택하는 방식이다.

criterion = 'entropy'

: 엔트로피는 혼잡도라고 불리는데 일반적으로 학습을 시작하는 단계에서 분류하고자 하는 것들이 여러 가지로 섞여 있어서 엔트로피가 높은 상태지만 이를 정리하면서 엔트로피를 줄여나가 최종적으로 0에 근접하게 하는 방식이다.

 

[4번] : fit()이라는 함수에 원인에 해당하는 독립변수와 결과값에 해당하는 종속변수를 넣으면 놀랍게도 학습이 완료된다.

 

 

이 코드의 결과인 iris-dtree.dot파일을 그래프비즈를 이용해서 이미지 데이터로 변환하면 결과는 다음과 같다.

iris 의사결정나무 차트 실행 결과 화면(iris-dtree.png)

- X[0] : 꽃잎 길이

- Samples : 최초 샘플 50*3=150개

- X[1] : 꽃잎 폭

 

 

이 결과를 보면 지도학습의 분류가 어떤 기준으로 데이터를 분류했고 어떤 특성이 분류하기에 가장 효과적인지를 시각적으로 볼 수 있지만 나무의 깊이가 깊어질수록 분기의 가짓수가 많아지고 더 깊어지면 한눈에 보기가 힘들어지고 분석도 힘들어지는 단점도 있다.

 

 

 

 

의사결정나무로 유방암 분류해보기

이번에는 유방암을 판단하는 속성을 보고 암을 추정하는 분류기를 만들어보자(이것도 이미 사이킷런에 들어있는 데이터 세트이다.)

이 유방암 데이터에는 종양에 대해 30개 항목의 요소가 특징량으로 담겨 있고 각 종양은 양성과 음성으로 되어 있으며 30개 항목을 기반으로 종양이 암인지 아닌지 예측할 수 있다.

 

[ cancer.py ] 

# -*- coding: utf-8 -*-
# sklearn 모듈 임포트
from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree
from sklearn.model_selection import train_test_split

def main():
    #iris 데이터 로드 [1번]
    cancer = datasets.load_breast_cancer()

    #데이터를 훈련, 테스트 데이터로 나누기 [2번]
    x_train, x_test, y_train, y_test = train_test_split(cancer['data'], cancer['target'], stratify=cancer['target'], test_size=0.2, random_state=42)

    #의사결정모델 클래스를 생성
    cancer_model = DecisionTreeClassifier(criterion='entropy', max_depth=3)

    #모델을 학습
    cancer_model.fit(x_train, y_train)
    print("훈련 점수: {:.3f}".format(cancer_model.score(x_train, y_train)))
    print("테스트 점수: {:.3f}".format(cancer_model.score(x_test, y_test)))

    #DOT 언어의 형식으로 결정 나무의 형태를 출력
    with open('cancer-dtree.dot', mode='w') as f:
        tree.export_graphviz(cancer_model, out_file=f, feature_names=cancer['feature_names'], class_names=["cancer", "not cancer"])

if __name__=='__main__':
    main()       

 

[1번] : 사이킷런은 기본으로 유방암 데이터를 포함하고 있다. 이 데이터는 load_breast_cancer()함수를 통해 읽어올 수 있다.

[2번] :  model_selection 모듈 내의 train_test_split()라는 함수를 이용해서 데이터 세트 내의 훈련 데이터와 테스트 데이터로 나누어서 학습한다. 구성비가 다른 불균형 데이터의 경우 stratify옵션을 활성화하는 것이 좋다 그 이유는 만약 테스트 데이터와 훈련 데이터에 존재하는 타깃 값들의 비율이 다르다면 이는 학습 결과와 성능에 모두 잘못된 영향을 주기 때문이다. test_size는 테스트용 데이터의 비율을 지정하는 인자로 0.2를 설정하면 20%의 데이터를 무작위로 골라 테스트용으로 할당한다. 디폴트값은 25%이다. 

[3번] : fit()이라는 함수에 훈련 데이터인 X_train, y_train데이터를 넣으면 학습이 완료된다.

 

실행 결과는 다음과 같다.

- 종양에 대한 특성의 이름 중에서 worst radius가 가장 많은 영향을 주고 있다.

- 그다음은 worst concavw points와 texture error로 분류되었음을 알 수 있다.

- 클래스를 통해 암인지 그렇지 않은지를 쉽게 판단할 수 있다.

 

 

지금까지 붓꽃 데이터와 유방암 데이터를 이용해 구현한 의사결정나무 알고리즘의 처리 흐름을 정리해보자

 

1. 분류에 필요한 파이썬 모듈과 데이터 세트를 준비한다. 사이킷런에 포함되어 있는 데이터 세트를 사용한다.

2. 분석할 데이터 세트의 특성을 확인하고, 각 데이터의 특징과 레이블을 확인한다. 또한 데이터의 내용을 확인한 후 트레이닝 및 검증용 데이터를 분할한다.

3. 의사결정나무의 변수를 조정한다. 변수를 조정함으로써 모델링의 정확도를 높일 수 있다.

4. 모델의 내용을 시각화한다. 시각화 과정은 의사결정나무 분석 결과를 이해하기에 가장 좋은 방법으로 반드시 진행해야 하며 시각화된 내용을 보고 특징량 중 어떤 특징량이 얼마나 데이터 분할에 기여했는지를 확인한다.

 

 


 

 


< 출처 또는 참고자료 >

실무가 훤히 보이는 머신러닝과 딥러닝 (마창수, 최재철 지음)

 

Comments