본문 바로가기
Python/Sklearn

[Python] Ensemble "RandomForest"

by 씩2 2022. 3. 18.

이번 포스팅에서는 앙상블 기법중 하나인 랜덤 포레스트를 다뤄보도록 하겠습니다.

랜덤포레스트는 배깅에 속하는데 이는 여러개의 분류기를 만들어서 보팅으로 최종 결정하는 알고리즘 입니다.

랜덤포레스트의 기반은 의사결정나무(Decision Tree)이며 쉽고 직관적이라는 장점이 있습니다.

이번 포스팅에서 사용하는 데이터는 Human Activity Recognition Using 입니다.

UCI에가면 쉽게 다운로드 할 수 있습니다.

 

사용되는 모듈은 다음과 같습니다.

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import pandas as pd
import warnings
import pandas as pd
from sklearn.model_selection import GridSearchCV
warnings.filterwarnings('ignore')

우선 랜덤포레스트분류기가 사용됩니다.

또 일치되는 경고를 무시해주는 모듈도 같이 import해줍니다.

판다스의 경우는 이번 랜덤포레스트를 사용하는데 직접적으로 필요하진 않지만, 랜덤포레스트 분류를 마친뒤에 어떠한 성분이 주요하게 사용됬는지 알아보기 위해 임포트 해줍니다.

 

def get_new_feature_name_df(old_feature_name_df):
    feature_dup_df = pd.DataFrame(data=old_feature_name_df.groupby('column_name').cumcount(), columns=['dup_cnt'])
    feature_dup_df = feature_dup_df.reset_index()
    new_feature_name_df = pd.merge(old_feature_name_df.reset_index(), feature_dup_df, how='outer')
    new_feature_name_df['column_name'] = new_feature_name_df[['column_name', 'dup_cnt']].apply(lambda x : x[0]+'_'+str(x[1])
                                                                                           if x[1] >0 else x[0] ,  axis=1)
    new_feature_name_df = new_feature_name_df.drop(['index'], axis=1)
    return new_feature_name_df


def get_human_dataset():
    feature_name_df = pd.read_csv('./activity/features.txt', sep='\s+',
                                  header=None, names=['column_index', 'column_name'])

    new_feature_name_df = get_new_feature_name_df(feature_name_df)
    feature_name = new_feature_name_df.iloc[:, 1].values.tolist()
    X_train = pd.read_csv('./activity/train/X_train.txt', sep='\s+', names=feature_name)
    X_test = pd.read_csv('./activity/test/X_test.txt', sep='\s+', names=feature_name)
    y_train = pd.read_csv('./activity/train/y_train.txt', sep='\s+', header=None, names=['action'])
    y_test = pd.read_csv('./activity/test/y_test.txt', sep='\s+', header=None, names=['action'])
    return X_train, X_test, y_train, y_test

X_train, X_test, y_train, y_test = get_human_dataset()

이번 데이터의 경우는 테스트셋과 트레이닝 세트가 분리 되어있기때문에 따로 데이터 전처리 의 과정이 필요하지는 않습니다.

하지만 나중에 어떠한 성분이 주로 영향을 미치는지 확인하기 위해서 위처럼 코딩을 해주겠습니다.

첫번째 사용자 정의함수는 이 데이터는 같은이름을 가진 feature값들이 있습니다. 같은 이름을 가진 features들이 있을 경우 판다스에서 오류를 발생하기때문에 위처럼 _1,_2를 추가해주는 사용자 정의 함수를 만들었습니다.

 

rf_clf = RandomForestClassifier(random_state=0)
rf_clf.fit(X_train , y_train)
pred = rf_clf.predict(X_test)
accuracy = accuracy_score(y_test , pred)
print('랜덤 포레스트 정확도: {0:.4f}'.format(accuracy))

다음으로 랜덤포레스트를 만들어서 분류를 해보도록 하겠습니다.

결과 값은 다음과 같이 나왔습니다.

랜덤 포레스트 정확도: 0.9013

따로 조정을 하지 않았는데도 상당히 좋은 분류율을 보여줍니다.

 

params = {
    'n_estimators':[100],
    'max_depth' : [6, 8, 10, 12],
    'min_samples_leaf' : [8, 12, 18 ],
    'min_samples_split' : [8, 16, 20]}
rf_clf = RandomForestClassifier(random_state=0, n_jobs=-1)
grid_cv = GridSearchCV(rf_clf , param_grid=params , cv=2, n_jobs=-1 )
grid_cv.fit(X_train , y_train)
print('최적 하이퍼 파라미터:\n', grid_cv.best_params_)
print('최고 예측 정확도: {0:.4f}'.format(grid_cv.best_score_))

이제 하이퍼 파라미터 튜닝이 필요하겠습니다.

교차검증을 2번만 하는 이유는 시간상 줄였습니다. 양해 부탁드립니다.

최적 하이퍼 파라미터:
 {'max_depth': 10, 'min_samples_leaf': 8, 'min_samples_split': 8, 'n_estimators': 100}
최고 예측 정확도: 0.9180

자 이렇게 최적의 하이퍼 파라미터가 도출 되었습니다.

튜닝된 파라미터를 이용하여 다시 분류예측 해보도록 하겠습니다.

rf_clf1 = RandomForestClassifier(n_estimators=300, max_depth=10, min_samples_leaf=8, \
                                 min_samples_split=8, random_state=0)
rf_clf1.fit(X_train , y_train)
pred = rf_clf1.predict(X_test)
print('예측 정확도: {0:.4f}'.format(accuracy_score(y_test , pred)))
예측 정확도: 0.9165

예측 정확도가 91.65%로 이전의 튜닝 전보다 성능이 향상된 것을 확인 할 수 있네요.

마지막으로 어떤한 요소들이 랜덤포레스트가 분류할때 큰 영향을 미쳤는지 시각화 해보도록 하겠습니다.

ftr_importances_values = rf_clf1.feature_importances_
ftr_importances = pd.Series(ftr_importances_values,index=X_train.columns  )
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()

위처럼 입력해주면 위에서부터 20개의 주요성분들이 그래프로 출력되게됩니다.

결과는 다음과 같습니다.

이렇게 그래프로만들어 시각화하면 더 보기 쉽게 만들 수 있습니다.

이것으로 포스팅을 마치도록 하겠습니다.