본문 바로가기
Machine Learning

결정 트리 실습(사용자 행동 인식 데이터)

by rubyda 2020. 4. 19.
728x90

UCI에서 제공하는 사용자 행동 인식 데이터를 사용해서 결정 트리 알고리즘 실습을 해보겠습니다. 이 데이터는 사람들에게 스마트폰 센서를 장착시킨 후에 사람의 동작과 관련된 여러 가지 피처를 수집한 데이터입니다.


 

In

import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

# feature.txt 파일은 index와  피처명이 공백으로 분리되어 있어 다음과 같이 sep으로 할당시켜 불러와 줘야 함.
feature_name_df = pd.read_csv('./human_activity/features.txt', sep='\s+',
                             header=None, names = ['column_index', 'column_name'])
feature_name_df.head()

Out

 

In

# 피처명 index를 제거한 후에 피처명만 리스트 객체로 생성한 뒤 샘플로 10개만 추출 함.
feature_name = feature_name_df.iloc[:, 1].values.tolist()
feature_name[:10]

Out

 

데이터의 일부 전처리 방법은 생략하도록 하겠습니다.

 

In

import pandas as pd

def human_dataset():
    # 공백 데이터를 분리하게 위해 공백 문자를 sep로 할당시켜 줌.
    feature_name_df = pd.read_csv('./human_activity/features.txt',sep='\s+', header=None, names=['column_index',
                                                                                               'column_name'])
    
    # 피처명을 칼럼으로 부여해 주기 위해서 리스트 객체로 다시 변환하여 준다.
    feature_name = feature_name_df.iloc[:,1].values.tolist()
    
    # 학습 피처, 데스트 피처를 DataFrame으로 로딩하고, 칼럼명은 feature_name 으로 적용헤 준다.
    X_train= pd.read_csv('./human_activity/train/X_train.txt',sep='\s+',names=feature_name)
    X_test= pd.read_csv('./human_activity/test/X_test.txt',sep='\s+',names=feature_name)
                        
    # 학습 레이블과 테스트 레이블을 DataFrame으로 로딩하고, 칼럼명은 action으로 적용해 준다.
    y_train= pd.read_csv('./human_activity/train/y_train.txt',sep='\s+',names=['action'])
    y_test= pd.read_csv('./human_activity/test/y_test.txt',sep='\s+',names=['action'])
                        
    # 학습&테스트용 DataFrame을 모두 반환 시킴.
    return X_train, X_test, y_train, y_test
                        
X_train, X_test, y_train, y_test = human_dataset()

 

  • 데이터의 형태를 살펴보겠습니다.

In

print(X_train.info())

Out

학습 데이터 세트는 7352개의 레코드로 561개의 피처를 가지고 있습니다.

 

 

In

print(y_train['action'].value_counts())

Out

레이블 값의 비율은 비교적 고르게 분포되어 있음을 확인하였습니다.

 

  • 이제 사이킷런에서 제공하는 DecisionTreeClassifier을 사용해서 예측 분류를 해보겠습니다. 하이퍼 파리미터는 우선 디폴트 값으로 설정해 주겠습니다.

In

from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

# 예제 반복을 할때 동일한 예측 결과를 위해서 random_state를 설정해 준다.
dt_clf = DecisionTreeClassifier(random_state=156)
dt_clf.fit(X_train, y_train)
dt_pred=dt_clf.predict(X_test)
accuarcy=accuracy_score(y_test, dt_pred)
print('예측 정확도:{0:.4f}'.format(accuarcy))

Out

예측 정확도가 약 85.48%로 나왔습니다.

 

  • 이때의 하이퍼파라미터 값들을 추출해 보도록 하겠습니다.

In

print('기본 하이퍼 파라미터:\n', dt_clf.get_params())

Out

 

기본 파라미터들은 다음과 같습니다.

 

  • 이번에는 트리 깊이(Tree depth)을 조절해서 예측 정확도에 어떤 영향을 미치는지 알아보도록 하겠습니다.

  • 결정 트리는 리프 노드가 될 수 있는 적합한 수준이 될 때까지 지속해서 트리의 분할을 수행하면서 깊이가 깊어지게 됩니다.

  • max_depth값을 6, 8, 10, 12, 16, 20, 24로 계속 늘리면서 예측 성능을 측정해 보겠습니다.교차 검증은 5개 세트입니다

In

from sklearn.model_selection import GridSearchCV

params = {
    'max_depth': [6, 8, 10, 12, 16, 20, 24]
}

grid_cv=GridSearchCV(dt_clf, param_grid=params, scoring='accuracy', cv=5, verbose=1)
grid_cv.fit(X_train, y_train)
print('최고 평균 정확도:{0:.4f}'.format(grid_cv.best_score_))
print('최적 하이퍼 파라미터:',grid_cv.best_params_)

Out

max_depth가 8일 때 5개의 폴드 세트의 최고 평균 정확도가 약 85.26%로 나왔습니다.

 

  • 5개의 CV 세트에서 max_depth값에 따라 어떻게 예측 성능이 변했는지 확인해보겠습니다

In

# GridSearchCV 객체의 cv_result_ 속성을 사용
cv_results_df = pd.DataFrame(grid_cv.cv_results_)
# param_max_depth, maan_test_score 추출
cv_results_df[['param_max_depth','mean_test_score']]

Out

mean_test_score은 5개 CV 세트에서 검증용 데이터 세트의 정확도 평균 수치를 의미합니다.

 

mean_test_score는 max_depth가 8일때 0.852로 정확도가 정점입니다. 이를 넘어가게 되면 정확도가 계속 떨어지게 됩니다.

 

  • 다음은 별도의 데이터 세트에서 결정 트리의 정확도를 측정해 보도록 하겠습니다.

In

from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
max_depth = [6, 8, 10, 12, 16, 20, 24]
# max_depth 값을 변화시키면서 학습과 테스트 세트에서의 예측 성능을 측정한다.
for depth in max_depth :
    dt_clf = DecisionTreeClassifier(max_depth = depth, random_state = 156)
    dt_clf.fit(X_train, y_train)
    pred = dt_clf.predict(X_test)
    accuracy = accuracy_score(y_test, pred)
    print('max_depth = {0} 정확도 : {1:.4f}'.format(depth, accuracy))

Out

결과를 보면 max_depth가 8일때 약 87.07으로 가장 높은 정확도를 나타내고 있습니다. 그리고 max_depth가 8을 넘어가는 순간 정확도가 계속 감소하는 것을 알 수 있습니다.

 

앞의 예제와 마찬가지로 깊이가 깊어질수록 테스트 데이터 세트의 정확도는 떨어지게 됩니다.
결정 트리는 깊이가 깊어질수록 과적합의 위험성이 있기 때문에 하이퍼 파라미터를 이용해서 깊이를 제어하는 것이 중요합니다.

 

  • 이번에는 max_depthmin_samples_split를 같이 변경하면서 정확도 성능을 확인해 보겠습니다.

In

params = {
    'max_depth' : [8, 12, 16, 20],
    'min_samples_split' : [16, 24]
}

grid_cv = GridSearchCV(dt_clf, param_grid=params, scoring='accuracy', cv=5, verbose = 1)
grid_cv.fit(X_train, y_train)
print('GridSearchCV 최고 평균 정확도: {0:.4f}'.format(grid_cv.best_score_))
print('GridSearchCV 최적 하이퍼 파라미터 : ', grid_cv.best_params_)

Out

max_depth가 8, min_samples_split이 16일때 가장 최고의 정확도로 약 85.5%를 나타냅니다.

 

  • 이제 테스트 데이터 세트에 해당 하이퍼 파라미터를 적용해 보도록 하겠습니다.

In

best_df_clf = grid_cv.best_estimator_
pred1 = best_df_clf.predict(X_test)
accuracy = accuracy_score(y_test, pred1)
print('결정 트리 예측 정확도 : {0:.4f}'.format(accuracy))

Out

max_depth가 8, min_samples_split이 16일때 테스트 데이터 세트의 예측 정확도는 약 87.17%로 확인되었습니다.

 

  • 이제 결정 트리에서 각 피저의 중요도를 feature_importances_ 속성을 이용해서 알아보도록 하겠습니다.

In

# 중요도가 높은 순으로 Top 20 피처를 막대그래프로 표현한다.

import seaborn as sns
ftr_importances_values = best_df_clf.feature_importances_

ftr_importances = pd.Series(ftr_importances_values, index = X_train.columns)
# 중요도값 순으로 Series를 정렬
ftr_top20 = ftr_importances.sort_values(ascending=False)[:20]
plt.figure(figsize=(8, 6))
plt.title('Feature importances Top 20')
sns.barplot(x = ftr_top20, y = ftr_top20.index)
plt.show()

Out

 

그래프에서 가장 높은 중요도를 가진 TOP5의 피처들이 규칙을 생성하는데 매우 중요한 영향을 미치는 것을 알 수 있습니다.

 

 

  • 결정 트리 시각화

In

feature_names = X_train.columns.tolist()
target_name = X_test.columns.tolist()

 

시각화에 필요한 파라미터를 위해 피처명과 레이블 명을 따로 저장하여 줍니다.

 

from sklearn.tree import DecisionTreeClassifier
from sklearn import tree


from sklearn.tree import export_graphviz

dt_dot_data = tree.export_graphviz(dt_clf, out_file = 'tree1',
                                  feature_names = feature_names,
                                  class_names = target_name,
                                  filled = True, rounded = True,
                                  special_characters = True)
import graphviz

with open('tree1') as f:
    dot_graph=f.read()
graphviz.Source(dot_graph)

Out

다음과 같이 출력이 됩니다.

그럼 결정 트리 실습 포스팅을 마치도록 하겠습니다. 감사합니다. 화이팅!

 

 

 

 

 

Reference


파이썬 머신러닝 완벽가이드