반응형

원본 링크

** 결정트리 관련 글에서 사용된 프레임워크에 대해 알아보자.



A Gentle Introduction to Chefboost for Applied Machine Learning

딥러닝이 미디어에서 가장 뜨거운 주제일지라도 결정트리(Decision Tree)는 실생활 문제를 지배한다. (저자는) Chefboost라는 프레임워크 기반 결정트리를 만들었다. 이 프레임워크는 ID3, C4.5, CART, Regression Trees 같은 일반적인 결정트리 알고리즘과 Adaboost, Random Forest, Gradient Boosting Trees같은 몇몇 발전된 방법을 지원한다.


Burger

이 글은 몇줄의 파이썬 코드로 이 알고리즘을 사용하는 방법을 보여주는 것이 목적이다. 알고리즘의 배경은 범위 밖이다. 이 알고리즘들의 수학적 배경이 궁금하다면 이전 작성글들을 참고하자.



가볍다

XGBoost나 LightBGM처럼 마켓에는 이미 강력한 gradient boosting framework가 있다. 그것들은 여러분이 데이터셋을 수치적 특성(numerical features)과 목표값(target values)로 바꾸는 것을 기대한다. 여기서는 단지 Chefboost에 데이터셋을 제공하기만 하면 된다. 데이터셋의 데이터타입이 범주적이건 수치적이건 중요하지 않다.

게다가, 구축되어 있는 결정트리는 전용 파이썬 파일로 저장되어 있고 단지 파이썬 if문만을 포함한다. 그렇기 때문에 구축되어 있는 결정트리를 쉽게 읽고 이해하고 조작할 수 있다.



설치

프레임워크를 설치하는 가장 쉬운 방법은 PyPi이다. 아래 명령만 실행하면 설치된다.


pip install chefboost

댜른 방법으로 pip를 사용하여 설치하는 것을 좋아하지 않는다면 프레임워크의 코드 저장소가 GitHub이다. 해야하는 것은 아래 명령을 실행하는 것이다. 또다른 방법은 github 저장소로 가서 zip을 다운로드 하는 것이다.


git clone https://github.com/serengil/chefboost.git



Hello, World!

ID3는 가장 오래되고 일반적인 결정트리 알고리즘중 하나이다. 이 알고리즘은 범주적 특성과 범주적 목표값을 기대한다. 데이터셋으로 dataset/golf.txt을 사용할 수 있다. 이 데이터셋은 전망(outlook), 온도(temperature), 습도(humidity), 바람(wind)같은 몇가지 특성을 바탕으로 이전 골프 경기 여부에 대한 결정(decision)을 저장한다.


import pandas as pd
df = pd.read_csv("dataset/golf.txt")


golf.txt

결정트리를 구축하여 fit 명령으로 조작한다. 데이터셋과 설정으로 알고리즘을 제공하기만 하면 된다.


from chefboost import Chefboost as chef
config = {'algorithm': 'ID3'}
model = chef.fit(df, config)

fit 명령을 호출하여 'output/rules' 폴더에 결정규칙(decision rules)을 구축한다. 구축된 트리는 우선 전망(outlook) 특성을 점검한다. 예를 들어, 전망이 흐리다면 골프 경기를 한다. 전망이 맑으면 습도를 점검한다. 맑고 습도가 보통이면 골프 경기를 한다. 반면에 맑고 습도가 높으면 골프 경기를 하지 않는다. 보이는 것과 같이 결정 트리의 결과를 쉽게 읽고 이해할 수 있다.


def findDecision(obj): #obj[0]: Outlook, obj[1]: Temp., obj[2]: Humidity, obj[3]: Wind
    if obj[0] == 'Sunny':
        if obj[2] == 'High':
            return 'No'
        elif obj[2] == 'Normal':
            return 'Yes'
    elif obj[0] == 'Rain':
        if obj[3] == 'Weak':
            return 'Yes'
        elif obj[3] == 'Strong':
            return 'No'
    elif obj[0] == 'Overcast':
        return 'Yes'



예측하기

결정 규칙이 구축되면 예측을 할 수 있다. predict 함수를 호출하여 앞에서 구축한 모델과 예측을 하기 위한 특성값을 전달한다.


feature = ['Sunny','Hot','High','Weak']
prediction = chef.predict(model, feature)

게다가 데이터셋에서 커스텀 예측을 할 수 있다. 아래 예제는 훈련셋에서 첫번째 아이텀의 특성을 찾아 예측한다.


prediction = chef.predict(model, df.iloc[0])

확실히 데이터프레임의 모든 아이템에 대한 예측을 위해 for 루프를 구성할 수 있다.


for index, instance in df.iterrows():
    prediction = chef.predict(model, instance)

ID3 알고리즘은 가장 지배적인 특성을 찾기 위해 정보 이익(information gain)을 사용한다.



C4.5 Algorithm

C4.5 알고리즘은 수치적 특성값을 다룰 수 있지만 여전히 범주적 목표값을 요구한다. dataset/golf2.txt가 이 형식이다.


df = pd.read_csv("dataset/golf2.txt")


golf2.txt

ID3과 유사하게 결정트리 구축을 위한 알고리즘을 언그하기만 하면 된다.


config = {'algorithm': 'C4.5'}
model = chef.fit(df.copy(), config)

C4.5 알고리즘은 수치적 특성을 이진 분할 지점으로 변환한다. 예를 들어 온도는 원시데이터에서 수치값이다. 결정 규칙은 온도가 83보다 크거나 같은지 또는 83보다 작은지 처음 단계에서 점검한다. 온도값은 실제 이 규칙으로 논리값(boolean - true/false)로 바뀐다.

def findDecision(obj): #obj[0]: Outlook, obj[1]: Temp., obj[2]: Humidity, obj[3]: Wind
    if obj[1] <=83:
        if obj[0] == 'Rain':
            if obj[3] == 'Weak':
                return 'Yes'
            elif obj[3] == 'Strong':
                return 'No'
        elif obj[0] == 'Sunny':
            if obj[2] > 65:
                if obj[3] == 'Weak':
                return 'Yes'
                elif obj[3] == 'Strong':
                return 'Yes'
        elif obj[0] == 'Overcast':
            return 'Yes'
    elif obj[1] > 83:
        return 'No'

C4.5 알고리즘은 가장 지배적인 특성을 찾기 위해 이익 비율(gain ratio)를 사용한다.



CART Algoritms

C4.5와 유사하게 CART 알고리즘은 수치적/범주적 특성을 모두 다룰 수 있지만 목표값은 범주형이어야만 한다. 이전과 마찬가지로 알고리즘을 지정하기 만하면 된다.


config = {'algorithm': 'CART'}

CART 알고리즘은 매 단계에서 지배적인 특성을 찾기 위해 Gini index를 사용한다.


Genie in Aladdin



Regression Trees

이전 알고리즘은 단지 문자열 목표변수만을 다룰 수 있었다. 회귀 트리(Regression tree)는 목표변수가 수치형이어야 한다. dataset/golf4.txt가 이러한 형식이다. 이,전 데이터셋은 yes/no로 골프 경기 진행 결정을 저장했지만 여기서는 저장된 몇가지 특성을 바탕으로 골프 경기 참가자의 수를 저장한다.


df = pd.read_csv("dataset/golf4.txt")


golf4.txt

프레임워크는 수치형 목표값을 포함하는 데이터셋에 대해 다른 알고리즘을 지정하더라도 적용하기 위한 Regression Tree 알고리즘을 결정할 수 있다.


config = {'algorithm': 'Regression'}

결정 규칙은 회귀 트리에서 수치값으로 반환된다.


def findDecision(obj): #obj[0]: Outlook, obj[1]: Temp., obj[2]: Humidity, obj[3]: Wind
    if obj[0] == 'Sunny':
        if obj[1]&amp;amp;amp;amp;amp;amp;lt;=83:
            return 37.75
        elif obj[1]&amp;amp;amp;amp;amp;amp;gt;83:
            return 25
    elif obj[0] == 'Rain':
        if obj[3] == 'Weak':
            return 47.666666666666664
        elif obj[3] == 'Strong':
            return 26.5
    elif obj[0] == 'Overcast':
        return 46.25

회귀 트리는 가장 지배적인 특성을 찾기 위해 표준 편차(standard deviation)를 사용한다.



Advanced Methods

앞에서는 일반적인 결정 트리 알고리즘을 알아보았다. 발전된 알고리즘은 다양한 관점에서 이러한 일반적인 결정 트리 알고리즘을 사용한다.



Random Forest

결정 트리는 대규모 데이터셋에서 오버피팅되는 경항이 있다.

회사내 똑똑한 사람을 상상해 보자. 그는 모든 사업 절차를 알고 모두가 그에게 질문한다. 반면, 수평적인 조직에서 모든 직원은 하나의 사업 절차를 안다. 직원들은 함께 모일 수 있고 그들의 지식을 기반으로 모든 질문에 대답할 수 있다. 회사내 똑똑한 사람을 일반적인 결정 트리 알고리즘으로 생각할 수 있고 수평적인 조직은 random forest가 된다.

데이터셋은 하위 데이터셋으로 분할되고 이 하위 데이터셋에서 여러개의 결정 트리를 구축한다. 이런 경우 모든 결정 트리는 질문에 yes 또는 no 같은 몇가지 답변을 한다. 더 많은 답변을 가진 분류는 최종 답변이 된다. 동점 경기를 피하기 위해 데이터셋은 소수(prime number)로 분할된다.

수백개의 인스턴스를 가진 dataset/car.data를 데이터셋으로 사용할 수 있다.


df = pd.read_csv("dataset/car.data")


car.data

랜덤 포레스트 개선은 가능하다. 이 경우에는 여러개의 ID3 결정 트리를 만든다.


config = {'algorithm': 'ID3', 'enableRandomForest': True, 'num_of_trees': 5}
model = chef.fit(df.copy(), config)

이 경우 5가지 다른 결정 규칙(rules_0.py to rules_4.py)이 생성된다. 모든 결정 규칙은 몇백줄로 구성된다. predict 함수를 호출하여 모든 하위 결정트리의 예측을 하면 지배적인 답변을 반환한다.


prediction = chef.predict(model, ['vhigh','vhigh','2','2','small','low'])



Gradient Boosting

Gradient Boosted Trees는 현자(the sage)를 만든다. 모든 데이터셋을 제공하고 회귀 트리를 구축한다. 이것의 오류(error)를 바탕으로 또다른 결정 트리를 구축한다. 두번째 회귀 트리의 오류를 바탕으로 세번째를 구축한다. 이것을 여러번 반복한다. 최종 예측은 각 결정 트리 결과의 합이 된다.


Rafiki as a Sage in The Lion King

오류는 반복하는 동안 감소하고 더 정확하게 예측된다.


Gradient boosted trees

Gradinet Boosting은 오로지 회귀 문제에서만 가능하다는 것을 기억하자. 분류문제에 적용하려면 프레임워크는 데이터셋을 먼저 회귀로 바꾸고 오류를 부스팅한다.


config = {'enableGBM': True, 'epochs': 7, 'learning_rate': 1}

predict 함수는 구축된 결정 트리를 호출하고 최종 예측을 반환한다.


prediction = chef.predict(model, ['Sunny',85,85,'Weak'])



랜덤포레스트와 Gradient Boosting과는 반대로 Adaboost는 일반적인 결정 트리 알고리즘을 사용할 수 없다. 이것은 1레벨 결정트리인 결정 스텀프(decision stump)를 실행한다. 이것을 키에 근거한 성별을 예측하는 것으로 생각할 수도 있다. 누군가의 키가 1.7미터보다 크면 남성이고 아니면 여성이다. 이 결정 스텀프는 실패할 것이지만 51% 정확도를 갖는다. Adaboost는 여러개의 결정 스텀프를 만들고 몇가지 가중치를 설정한다.


config = {'enableAdaboost': True, 'num_of_weak_classifier': 3}
model = chef.fit(pd.read_csv("dataset/adaboost.txt"), config)


Decision stumps and weights

prediction = chef.predict(model, [4, 3.5])

최종 예측은 각 결정 스텀프의 가중치의 합과 결정 스텀프의 예측을 곱한 것이 된다.


Adaboost prediction

기본 아이디어는 약한 분류기(weak classifier)가 모여서 강력한 분류기(strong classifier)가 되는 것이다. 약한 노동자들이 모여 무거운 바위를 옮기는 것으로 생각할 ㅜㅅ도 있다.


Moving a heavy rock



반응형

+ Recent posts