본문 바로가기

Theory/MachineLearning

머신러닝을 이용한 Human Activity Recognition 실습

사람의 몸에 스마트폰(에 있는 자이로, 가속도센서 데이터)을 붙여서 데이터를 얻어서 그로부터 사람의 행동을 센서데이터 확인하려는 연구가 있습니다. 이 연구는 대부분 (딥러닝을 포함한) 머신러닝 분야에서 활발한듯 합니다.

그런 데이터를 이번에 하나 가지고 살짝 실습해 보려고 합니다.

UCI에서 방금이야기한 Human Activity Recognition (HAR) 데이터를 배포하고 있습니다. 읽어보면 2012년 데이터이고 이때 사용한 기기는 삼성 갤럭시2라고 되어 있습니다. 이 데이터가 zip으로 되어 있어서 이를 제 github 계정에 압축을 풀어서 다시 올려놓았습니다.

왜냐면 오늘 글은 구글 Colab으로 읽을거여서 그냥 편하게 데이터를 url로 읽기 위해서 입니다.

이 데이터는 위의 특징을 가집니다^^

데이터의 라벨은 위 그림의 6가지 행동입니다.

예를 들어 위의 가속도 센서 데이터는 sitting 동작을 측정한 것입니다. 이것만 봐도 센서 데이터로 행동을 파악하는 과정은 단순한 코드로는 아마 어려울 겁니다. 이런 분야는 확실히 머신러닝의 영역인것 같습니다. UCI에서 배포하는 데이터는 시간영역의 데이터는 아닙니다. 시간 영역과 주파수 영역의 여러 통계적 지표를 제공하고 있습니다.

데이터는 위 동영상과 같은 과정으로 얻었다고 합니다. 자원봉사자 30명이 동원되었다고 하네요^^

import pandas as pd
import matplotlib.pyplot as plt

url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/'+\
                                    'master/dataset/HAR_dataset/features.txt'
feature_name_df = pd.read_csv(url, sep='\s+', header=None, 
                              names=['column_index','column_name'])

feature_name = feature_name_df.iloc[:, 1].values.tolist()

X_train_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/'+\
                                'master/dataset/HAR_dataset/train/X_train.txt'
X_test_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/' +\
                                'master/dataset/HAR_dataset/test/X_test.txt'

X_train = pd.read_csv(X_train_url, sep='\s+', names=feature_name)
X_test = pd.read_csv(X_test_url, sep='\s+', names=feature_name)

먼저 데이터를 읽겠습니다. 제 github의 데이터를 읽고, 무려 561개나 되는 feature의 이름을 별도로 처리(feature_name)하고 이미 훈련용과 테스트용으로 나눠져서 데이터가 배포되므로 따로따로 읽었습니다. 

그리고 크기와 구조를 확인할 수 있습니다. 7352개의 훈련용 데이터셋과 2947개의 테스트데이터셋이 있습니다. 특징 데이터에서 t로 시작하는 것은 시간영역에서의 값, f로 시작하는 것은 주파수 영역에서의 값입니다.

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

dt_clf = DecisionTreeClassifier(random_state=13, max_depth=4)

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

grid_cv = GridSearchCV(dt_clf, param_grid=params, scoring='accuracy', 
                       cv=5, return_train_score=True)

grid_cv.fit(X_train , y_train)

cv_results_df = pd.DataFrame(grid_cv.cv_results_)
cv_results_df[['param_max_depth', 'mean_test_score', 'mean_train_score']]

이제 결정나무에 max_depth를 6부터 24까지 변화시켜가면서 GridSearchCV를 적용했습니다. 그 결과를 pandas의 DataFrame으로 정리를 해보죠.

훈련용 데이터에서 높은 결과가 나타난 24 depth 보다는 검증용 데이터(표기는 test_score지만) 데이터에서 높은 결과가 나온 8 depth를 선택하는 것이 자연스러운 이야기겠죠?^^

max_depths = [ 6, 8 ,10, 12, 16 ,20, 24]

for depth in max_depths:
    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 =', depth, ', Accuracy =', accuracy)

실제 따로 제공되는 테스트용 데이터에 적용해 보죠.

결과를 보니 확실히 Max_Depth가 8일때가 더 좋다고 할 수 있겠습니다.^^

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier

params = {
    'max_depth' : [ 6, 8 ,10],
    'n_estimators' : [50, 100, 200],
    'min_samples_leaf' : [8, 12],
    'min_samples_split' : [8, 12]
}

rf_clf = RandomForestClassifier(random_state=13, n_jobs=-1)
grid_cv = GridSearchCV(rf_clf, param_grid=params, cv=2, n_jobs=-1)
grid_cv.fit(X_train, y_train)

cv_results_df = pd.DataFrame(grid_cv.cv_results_)

target_col = ['rank_test_score', 'mean_test_score', 'param_n_estimators', 'param_max_depth']
cv_results_df[target_col].sort_values('rank_test_score').head()

이번에는 랜덤포레스트에 적용해 보겠습니다.

아예 점수로 정렬해서 확인해 보겠습니다. 랜덤포레스트의 경우는 나무 100그루(^^)가 성능이 좋네요^^.

반응형