의사결정나무는 해석이 쉽기 때문에, 유용한 알고리즘이다. 우연히 범주형 데이터를 기준으로 의사결정나무를 만들어야 할 필요성이 생겼다. 타겟값이 있는 것은 아니고, 범주형 데이터를 기준으로 카테고리 비중이 가장 차이나는 애들부터 나눠달라는 요구사항이 있었다. 이에 의사결정나무 알고리즘을 이용하면 쉽게 분류할 수 있을 것 같아서 만들어보았다. 오늘은 범주형 의사결정나무 알고리즘 만들기에 대해서 알아보도록 하겠다.

 

 

의사결정나무



일단 가지치는 기준을 정해야 한다. 가지를 치는 기준은 각 카테고리별로 비중을 구한 후에 이 비중의 표준편차가 가장 크거나 작은 칼럼을 기준으로 가지치기를 하도록 하였다.

이에 대한 함수를 하나 만든 후에는 이를 재귀적 호출하여 가장 끝에까지 나눠지도록 한다. 해당 함수가 make_tree라는 함수이다.

의사결정나무는 첫 번째 가지부터 딕셔너리로 만든다. 다음 가지가 값(value)으로 들어가 있는 형태이다. 트리를 이쁘게 출력하는 방법을 고민해봤는데, pyprnt 패키지를 이용해서 딕셔너리를 이쁘게 출력하는 방법이 가장 쉽고 좋을 듯 했다.
( 참조: 파이썬 리스트와 딕셔너리를 이쁘게 시각화 조회하는 방법! )


트리의 카운트를 세는 것이 조금 불편해서, 가지의 count를 세는 make_cout함수도 만들어보았다.

 


예를 들어 아래와 같은 데이터를 넣었다고 하면, 카테고리값별로 가장 차이가 많이 나는 칼럼부터 순서대로 가지를 친다.

 

입력 데이터

 

 

분류한 결과는 아래와 같다.

 

분류결과

 

 

사용한 코드는 아래와 같다.

 

import pandas as pd

def cal_std(df, c):
    """
    group비율의 표준편차를 구한다.
    """
    df_gr = df.groupby(c)[c].count()
    df_gr = df_gr/len(df)
    
    return df_gr.std()

def feature_to_split(df, method):
    """
    method: min, max
    분류할 특성을 찾는다. 표준편차가 가장 적거나 큰 걸로
    """
    col_list = df.columns
    var_list = list()
    for c in col_list:
        var = cal_std(df, c)
        var_list.append(var)
        
    if method == 'min':
        res_std_col = col_list[var_list.index(min(var_list))]
    elif method == 'max':
        res_std_col = col_list[var_list.index(max(var_list))]
        
    return res_std_col

def split_data(df, method):
    """
    method에서 지정한 방법으로 데이터셋 분리
    """
    c = feature_to_split(df, method)
    var_list = set(df[c])
    var_dict = dict()
    for v in var_list:
        var_dict.update({v : df.loc[df[c]==v]})
    
    split_df = {c:var_dict}
    return split_df, c

def make_tree(df, n, method='min'):
    """
        df: 데이터프레임
        n: tree depth    
    """
    if n==0:
        return df
    
    split_df, split_col = split_data(df, method)
    
    for c in split_df[split_col]:
        split_df[split_col].update({c : make_tree(split_df[split_col][c], n-1, method)})
        
    return split_df

def make_count(output):
    """
        생성한 트리의 가지별 count를 구한다.
    """
    key_list = output.keys()
    for k in key_list:
        if isinstance(output[k], pd.DataFrame)==True:
            output.update({k:len(output[k])})
        else:
            make_count(output[k])
            
    return output

if __name__=="__main__":
    df = pd.DataFrame({'col1': [1,1,2,2,2], 'col2': [1,1,1,1,9], 'col3': [8,9,9,9,9]})
    df.head()

    output = make_tree(df, 3, method = 'max')
    output_cnt = make_count(output)
    print(output_cnt)
    
    import pyprnt
    pyprnt.prnt(output_cnt)

 

 

오늘은 이렇게 범주형 의사결정나무 알고리즘 만들기에 대해서 알아보았다. 혹시 위와 같은 작업이 필요한 사람이 있다면 도움이 되었기를 바란다.

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기

댓글을 달아 주세요

">