IT 프로그래밍/PYTHON

4-4 랜덤포레스트

mjmjpp 2024. 3. 3. 09:57

1. 랜덤포레스트의 개요 및 실습

배깅(bagging)의 대표적인 알고리즘 : 랜덤 포레스트

랜덤포레스트

- 앙상블 알고리즘 중 비교적 빠른 수행속도를 가지며 다양한 영역에서 높은 예측 성능을 보임

랜덤포레스트의 기반 알고리즘은 결정트리, 결정트리의 장점인 쉽고 직관적인 점을 그대로 갖고 있음

-여러 결정 트리 분류기가 전체 데이터에서 배깅 방식으로 각자의 데이터를 샘플링하여 개별적으로 학습을 수행한 후

최종적으로 모든 분류기가 보팅을 통해 예측 결정을 하게 됨

랜덤포레스트- 각각의 개별적인 결정 트리가 학습하는 dataset이 전체 dataset에서 일부가 중첩되게 샘플링된 dataset

-> 여러개의 dataset을 중첩되게 분리하는 것을 부트스트래핑(bootstrapping)분할 방식이라 함

bagging이 bootstrapping의 줄임말

부트 스트랩은 통계학에서 여러개의 작은 dataset을 임의로 만들어 개별 평균의 분포도를 측정하는 목적등을 위한 샘플링방식을 지칭, 랜덤포레스트의 subset데이터는 이러한 부트스트래핑으로 데이터가 임의로 만들어짐

-subset의 데이터는 개별데이터들의 중첩을 허용하고 데이터 수는 전체 dataset의 수와 동일하게 만들어짐

 

사이킷런은 RandomForestClassifier 클래스를 통해 랜덤포레스트 기반의 분류를 지원

사용자 행동 인식 dataset을 이용해서 예측을 수행

 

import pandas as pd

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
import pandas as pd

def get_human_dataset( ):
    
    # 각 데이터 파일들은 공백으로 분리되어 있으므로 read_csv에서 공백 문자를 sep으로 할당.
    feature_name_df = pd.read_csv('C:/Users/PMJ/UCI HAR Dataset/features.txt',sep='\s+',
                        header=None,names=['column_index','column_name'])
    
    # 중복된 피처명을 수정하는 get_new_feature_name_df()를 이용, 신규 피처명 DataFrame생성. 
    new_feature_name_df = get_new_feature_name_df(feature_name_df)
    
    # DataFrame에 피처명을 컬럼으로 부여하기 위해 리스트 객체로 다시 변환
    feature_name = new_feature_name_df.iloc[:, 1].values.tolist()
    
    # 학습 피처 데이터 셋과 테스트 피처 데이터을 DataFrame으로 로딩. 컬럼명은 feature_name 적용
    X_train = pd.read_csv('C:/Users/PMJ/UCI HAR Dataset/train/X_train.txt',sep='\s+', names=feature_name)
    X_test = pd.read_csv('C:/Users/PMJ/UCI HAR Dataset/test/X_test.txt',sep='\s+', names=feature_name)
    
    # 학습 레이블과 테스트 레이블 데이터을 DataFrame으로 로딩하고 컬럼명은 action으로 부여
    y_train = pd.read_csv('C:/Users/PMJ/UCI HAR Dataset/train/y_train.txt',sep='\s+',header=None,names=['action'])
    y_test = pd.read_csv('C:/Users/PMJ/UCI HAR Dataset/test/y_test.txt',sep='\s+',header=None,names=['action'])
    
    # 로드된 학습/테스트용 DataFrame을 모두 반환 
    return X_train, X_test, y_train, y_test


X_train, X_test, y_train, y_test = get_human_dataset()
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import pandas as pd
import warnings
warnings.filterwarnings('ignore')

# 결정 트리에서 사용한 get_human_dataset( )을 이용해 학습/테스트용 DataFrame 반환
X_train, X_test, y_train, y_test = get_human_dataset()

# 랜덤 포레스트 학습 및 별도의 테스트 셋으로 예측 성능 평가
rf_clf = RandomForestClassifier(n_estimators=100, random_state=0, max_depth=8)
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.9196

 

2. 랜덤포레스트 하이퍼 파라미터 및 튜닝

트리기반의 앙상블 알고리즘의 단점

-hyperparameter가 너무 많아 튜닝시간이 너무 많이 소모, 많은 시간을 소모하여 튜닝을 한후에도 예측 성능이 크게 상향되지 않음, 그나마 랜덤 포레스트가 적은 편에 속하는데 결정트리를 사용하여 hyper parameter가 대부분 동일하기 때문

  • n_extimate : 랜덤 포레스트에서 결정 트리의 개수를 지정한다. default는 10개이고, 많이 설정할수록 좋은 성능을 기대할 수 있지만 계속 증가시킨다고 성능이 무조건 향상되는 것은 아니다. 또한 늘릴수록 학습 수행 시간이 오래 걸리는 것도 감안해야 한다.
  • max_features : 결정 트리에 사용되는 max_features 파라미터와 동일하다. 하지만 RandomForestClassifier의 기본 max_features는 'None'이 아니라 'auto'로 성절되어 있고, 'sqrt'와 동일하다. 따라서 랜덤 포레스트의 트리를 분할하는 feature를 참조할 때 전체 feature가 아니라 sqrt(전체 feature 수)만큼 참조한다.
  • max_depth나 min_samples_leaf와 같이 결정트리에서 과적합을 개선하기 위해 사용되는 parameter가 랜덤 포레스트에도 똑같이 적용된다.

* GridSearchCV를 통한 parameter 튜닝

from sklearn.model_selection import GridSearchCV

params = {
    'max_depth': [8, 16, 24],
    'min_samples_leaf' : [1, 6, 12],
    'min_samples_split' : [2, 8, 16]
}#27번실행
# RandomForestClassifier 객체 생성 후 GridSearchCV 수행
rf_clf = RandomForestClassifier(n_estimators=100, random_state=0, n_jobs=-1)#n_jobs=-1모든process를 사용하겠다
grid_cv = GridSearchCV(rf_clf , param_grid=params , cv=2, n_jobs=-1 )#cv=2 총 54번 학습하고 테스트
grid_cv.fit(X_train , y_train)

print('최적 하이퍼 파라미터:\n', grid_cv.best_params_)
print('최고 예측 정확도: {0:.4f}'.format(grid_cv.best_score_))
최적 하이퍼 파라미터:
 {'max_depth': 16, 'min_samples_leaf': 6, 'min_samples_split': 2}
최고 예측 정확도: 0.9165

최적화parameter로 약91.65의 정확도가 나왔다. 이 hyper parameter를 그대로 사용해도 되고 n_estimator증가시키거나 따른 파라미터들을 조정하여 다시학습한후 예측 성능을 측정해도 된다.

그후에 feature의 중요도를 막대그래프로 시각화 해볼 수 있다.

ftr_importances_values = rf_clf1.feature_importances_#feature_importances_: 컬럼별로 피쳐에 대한 중요성보여줌
ftr_importances = pd.Series(ftr_importances_values,index=X_train.columns)#시리즈로 만들어줌
ftr_importances.sort_values(ascending=False)[:20]#높으낪부터 내림차순으로 정리

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

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