본문 바로가기
머신러닝/PCA(Principal Component Analysis)

HAR using PCA

by 미생22 2024. 6. 4.
728x90

예전에 다뤘던 HAR 데이터로 PCA를 돌려보겠습니다.

이번에 다루는 HAR 데이터는 feature가 561개가 되었는데요,

이렇게 많은 feature를 줄이는 일이다보니 pca가 유용하게 쓰일 것 같습니다.

 

우선 데이터를 들고오겠습니다. train 데이터와 test 데이터가 나뉘어져있어서 각각 가져와야하고, column name도 features에서 따로 들고와야합니다.

import pandas as pd

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+', header=None)
X_test = pd.read_csv(X_test_url, sep='\s+', header=None)

X_train.columns = feature_name
X_test.columns = feature_name

 

y_train_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/HAR_dataset/train/y_train.txt'
y_test_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/HAR_dataset/test/y_test.txt'

y_train = pd.read_csv(y_train_url, sep='\s+', header=None)
y_test = pd.read_csv(y_test_url, sep='\s+', header=None)

 

X_train.shape, X_test.shape, y_train.shape, y_test.shape

((7352, 561), (2947, 561), (7352, 1), (2947, 1))

 

네 데이터들 갯수가 맞는지 확인했습니다.

이제 pca로 만드는 함수를 또 만들겠습니다.

from sklearn.decomposition import PCA

def get_pca_data(ss_data, n_components=2):
    pca = PCA(n_components=n_components)
    pca.fit(ss_data)

    return pca.transform(ss_data), pca

 

이렇게하면 scaling된 data를 pca에 fit 시키고 transform 시킨게 됩니다.

이제 HAR데이터를 pca에 fit, transform 시킵니다. 참고로 train 데이터를 pca 시키고 나중에 test 데이터를 transform 시킬겁니다. train 데이터는 오염되도 되지만 test 데이터는 오염되면 안됩니다.

 

HAR_pca, pca = get_pca_data(X_train, n_components=2)
HAR_pca.shape

(7352, 2)

 

이제 X_train을 통해 HAR_pca 데이터를 얻고, shape을 확인해봅니다. train 데이터 7352개 전체가 다 들어있고, 주성분 2개로 줄였으므로 2개가 있는걸 볼 수 있습니다.

이제 pca로 확인할 수 있는걸 살펴보겠습니다.

 

pca.mean_.shape, pca.components_.shape

((561,), (2, 561))

 

mean은 561개 feature 각각의 mean값이 들어있는 array이고, pca.components도 두개의 벡터가 각각의 feature만큼 방향을 갖는걸 볼 수 있네요.

 

cols = ['pca_' + str(n) for n in range(pca.components_.shape[0])]
cols

['pca_0', 'pca_1']

 

pca.components_.shape으로 주성분 개수만큼 column 이름을 짭니다.

pca.components_.shape이 (2, ~)니까 주성분 분석한 총 2개를 cols로 넣는다는 뜻입니다.

 

def get_pd_from_pca(pca_data, col_num):
    cols = ['pca_' + str(n) for n in range(pca.components_.shape[0])]
    return pd.DataFrame(pca_data, columns=cols)

 

이제 dataframe으로 만드는 함수에 넣고 이를 적용시켜보겠습니다.

action 컬럼을 만들어서 y_train 값도 넣어보겠습니다.

 

HAR_pca, pca = get_pca_data(X_train, n_components=2)
HAR_pd_pca = get_pd_from_pca(HAR_pca, pca.components_.shape[0])

HAR_pd_pca['action'] = y_train
HAR_pd_pca.head()

 

dataframe으로도 만들었으니, seaborn을 통해 action으로 잘 나누어지는지 시각적으로 확인해보겠습니다.

그래프는 pairplot을 사용합니다.

import seaborn as sns

sns.pairplot(HAR_pd_pca, hue='action', height=5, x_vars=['pca_0'], y_vars=['pca_1'])

561개를 2개로 줄인거니까 잘 구분이 안갈 수 있습니다...ㅎㅎ

explained raion랑 sum값을 프린트하는 함수를 또 만들어보겠습니다.

 

import numpy as np

def print_variance_ratio(pca):
    print('variance ratio :', pca.explained_variance_ratio_)
    print('sum of variance ratio :', np.sum(pca.explained_variance_ratio_))

 

print_variance_ratio(pca)

variance ratio : [0.6255444  0.04913023]
sum of variance ratio : 0.674674627048795

 

67%정도의 설명률을 보이네요.

components를 3개로 바꿔보겠습니다.

 

HAR_pca, pca = get_pca_data(X_train, n_components=3)
HAR_pd_pca = get_pd_from_pca(HAR_pca, pca.components_.shape[0])

HAR_pd_pca['action'] = y_train
HAR_pd_pca.head()

 

print_variance_ratio(pca)

variance ratio : [0.6255444  0.04913023 0.04121467]
sum of variance ratio : 0.7158893015785941

 

71%까지 올라가네요.. 이번에는 10개로 해보겠습니다.

 

HAR_pca, pca = get_pca_data(X_train, n_components=10)
HAR_pd_pca = get_pd_from_pca(HAR_pca, pca.components_.shape[0])

HAR_pd_pca['action'] = y_train
HAR_pd_pca.head()

 

print_variance_ratio(pca)

variance ratio : [0.6255444  0.04913023 0.04121467 0.01874956 0.0169486  0.01272069
 0.01176685 0.01068973 0.00969379 0.00858014]
sum of variance ratio : 0.8050386654039386

 

80%까지 상승하는 것을 볼 수 있습니다.

혹시 전에 GridSearchCV의 결과가 시간이 길게 나왔다면, 지금은 어떨까요? 얼마나걸릴까요?

 

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

 

GridSearchCV는 params로 key로 옵션을 줬었죠. 저희는 RandomForest 분류기를 사용하기 때문에 max_depth, n_estimators, min_samples_leaf, min_samples_split을 옵션을 주겠습니다.

 

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(HAR_pca, y_train.values.reshape(-1,))

 

cv_results_df = pd.DataFrame(grid_cv.cv_results_)
cv_results_df.columns

Index(['mean_fit_time', 'std_fit_time', 'mean_score_time', 'std_score_time',
       'param_max_depth', 'param_min_samples_leaf', 'param_min_samples_split',
       'param_n_estimators', 'params', 'split0_test_score',
       'split1_test_score', 'split2_test_score', 'split3_test_score',
       'split4_test_score', 'mean_test_score', 'std_test_score',
       'rank_test_score'],
      dtype='object')

 

이 중에서 제일 중요한 rank_test_score와 mean_test_score, 그리고 param_n_estimators, param_max_depth를 보겠습니다.

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()

1등으로 나오는 parameter가 84.8%의 test score를 보이네요.

이렇게 얻어지는 best_params를 살펴보겠습니다.

 

grid_cv.best_params_

{'max_depth': 10,
 'min_samples_leaf': 8,
 'min_samples_split': 8,
 'n_estimators': 200}

 

grid_cv.best_score_

0.8486173041616375

 

이제 test 데이터에 적용해서 accuracy를 확인해보겠습니다.

from sklearn.metrics import accuracy_score

rf_clf_best = grid_cv.best_estimator_
rf_clf_best.fit(HAR_pca, y_train.values.reshape(-1,))

pred1 = rf_clf_best.predict(pca.transform(X_test))
#X_train 데이터로 fit 시켰던 pca를 가지고 X_test를 transform 시키는 겁니다. X_test는 오염되면 안되므려 fit_transform도 시키면 안되고 무조건 transform 만 시켜야합니다.

accuracy_score(y_test, pred1)

0.8571428571428571

 

X_train 데이터로 fit 시켰던 pca를 가지고 X_test를 transform 시키는 겁니다. X_test는 오염되면 안되므려 fit_transform도 시키면 안되고 무조건 transform 만 시켜야합니다.

시간이 많이 걸렸던 xgboost는 pca 데이터를 어떻게 처리할까요?

 

from xgboost import XGBClassifier

evals = [(pca.transform(X_test), y_test)] #이거는 cross validation 할 때, evaluation test set을 잡아줘야 하는데 이걸 test 데이터로 잡겠다는 뜻입니다.
xgb = XGBClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)
xgb.fit(HAR_pca, y_train.values.reshape(-1,), early_stopping_rounds=10, eval_set=evals)

저번에도 XGBoost는 오류가 났었는데 이번에도 오류가 나네요. 강의에서는 잘 돌아갑니다.

10초 안으로 걸렸다고 하네요.

 

accuracy_score(y_test, xgb.predict(pca.transform(X_test)))

이렇게해서 xgboost도 accuracy를 확인할 수 있습니다.

 

728x90

'머신러닝 > PCA(Principal Component Analysis)' 카테고리의 다른 글

비지도학습 (Clustering)  (0) 2024.06.05
MNIST using PCA and kNN  (1) 2024.06.04
PCA - eigenface  (0) 2024.06.01
PCA - wine 데이터  (0) 2024.06.01
PCA - iris 데이터  (0) 2024.06.01