시작에 앞서
해당 내용은 '<파이썬 머신러닝 완벽 가이드> 권철민 지음. 위키북스' 를 토대로 작성되었습니다. 보다 자세한 내용은 해당 서적에 상세히 나와있으니 서적을 참고해 주시기 바랍니다.
앙상블 학습(Ensemble Learning)
랜덤 포레스트
랜덤 포레스트는 배깅의 대표적인 알고리즘인데, 배깅은 같은 알고리즘으로 여러 개의 분류기를 만들어서 보팅으로 최종 결정하는 알고리즘이다.
랜덤 포레스트는 앙상블 알고리즘 중 비교적 빠른 수행 속도를 가지고 있으며, 다양한 영역에서 높은 예측 성능을 보이고 있다.
이 알고리즘은 여러 개의 결정 트리 분류기가 전체 데이터에서 배깅 방식으로 각자의 데이터를 샘플링해 개별적으로 학습을 수행한 뒤 최종적으로 모든 분류기가 보팅을 해 예측 결정을 하게 된다.
사이킷런은 RadomForestClassifier 클래스를 통해 랜덤 포레스트 기반의 분류를 지원한다.
[행동 인식 데이터 세트를 이용해 예측 수행]
새로운 주피터 노트북에서 진행하되, 재수행 시마다 동일한 예측 결과를 출력하기 위해, 그리고 사용자 행동 데이터 세트에 DataFrame을 반환하는 get_human_dataset() 함수를 가져오기 위해 기존의 예측 분석과 동일한 디렉터리에 생성한다.
기존에 진행했던 행동 인식 데이터 관련 내용은 하단 참고
(물론, 새로운 디렉터리에 수행해도 된다. 이러한 경우, 행동 인식 데이터 코드는 get_human_dataset() 함수 생성까지 동일하다 - 혹시 몰라서 하단에 코드를 남긴다.)
※ 물론, 사이킷런에서 앙상블의 랜덤 포레스트 분류기를 import 하는 것도 다르다 (하단 첫째 줄 참고)
# 랜덤 포레스트 (사용자 행동 인식 데이터 세트 활용)
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
# features.txt 파일에는 피처 이름 index와 피처명이 공백으로 분리되어 있음
# 이를 DataFrame으로 로드
feature_name_df = pd.read_csv('C:/Users/niceq/Documents/DataScience/Python ML Guide/human_activity/features.txt',
sep='\s+', header=None, names=['column_index', 'column_name'])
# 피처명 index를 제거하고, 피처명만 리스트 객체로 생성한 뒤 샘플로 10개만 추출
feature_name = feature_name_df.iloc[:, 1].values.tolist()
print('전체 피처명에서 10개만 추출:', feature_name[:10])
# 중복된 피처명 파악하기
feature_dup_df = feature_name_df.groupby('column_name').count()
print(feature_dup_df[feature_dup_df['column_index'] > 1].count())
feature_dup_df[feature_dup_df['column_index'] > 1].head()
# 중복된 피처명 파악하기
feature_dup_df = feature_name_df.groupby('column_name').count()
print(feature_dup_df[feature_dup_df['column_index'] > 1].count())
feature_dup_df[feature_dup_df['column_index'] > 1].head()
# get_human_dataset 함수 생성
import pandas as pd
def get_human_dataset():
# 각 데이터 파일은 공백으로 분리되어 있으므로 read_csv에서 공백 문자를 sep로 할당
feature_name_df = pd.read_csv('../human_activity/features.txt',
sep='\s+', header=None, names=['column_index', 'column_name'])
# 중복된 피처명을 수정하는 get_new_feature_name_df()를 이용, 신규 피처명 DF 생성
new_feature_name_df = get_new_feature_name_df(feature_name_df)
# DF에 피처명을 칼럼으로 부여하기 위헤 리스트 객체로 다시 변환
feature_name = new_feature_name_df.iloc[:, 1].values.tolist()
# 학습 피처 데이터세트와 테스트 피처 데이터를 DF로 로딩. 칼럼명은 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)
# 학습 레이블과 테스트 레이블 데이터를 DF로 로딩하고 칼럼명은 action 부여
y_train = pd.read_csv('../human_activity/train/y_train.txt', sep='\s+', header=None,names=['action'])
y_test = pd.read_csv('../human_activity/test/y_test.txt', sep='\s+', header=None, names=['action'])
# 로드된 학습/테스트용 DF 모두 반환
return X_train, X_test, y_train, y_test
X_train, X_test, y_train, y_test = get_human_dataset()
여기까지는 동일하고,
하단 내용을 입력하여 랜덤 포레스트를 통한 예측 성능 평가를 수행하면 된다.
# 결정 트리에서 사용한 get_human_dataset() 이용해 학습/테스트용 DF 반환
X_train, X_test, y_train, y_test = get_human_dataset()
# 랜덤 포레스트 학습 및 별도의 테스트 세트로 예측 성능 평가
rf_clf = RandomForestClassifier(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))
랜덤 포레스트 하이퍼 파라미터 및 튜닝
랜덤 포레스트 같은 트리 기반의 앙상블 알고리즘의 단점
- 하이퍼 파라미터가 많다. ▶ 튜닝을 위한 시간이 많이 소요된다.
- 튜닝을 위한 시간을 많이 소모했음에도 예측 성능이 향상되지 않는 경우가 많다.
※ 트리 기반 자체의 하이퍼 파라미터는 원래 많은데다가 배깅, 부스팅, 학습, 정규화 등을 위한 하이퍼 파라미터까지 추가되어 다른 머신러닝 알고리즘에 비해 많을 수 밖에 없다.
[랜덤 포레스트 하이퍼 파라미터]
- n_estimators: 랜덤 포레스트에서 결정 트리의 개수 지정 (디폴트 10개). 많을수록 좋은 성능을 기대할 수 있으나, 학습수행 시간 증가
- max_features: 최적의 분할을 위해 고려할 최대 피처 개수(디폴트 'auto' = 'sqrt') 전체 피처 중 전체 피처의 루트 만큼 선정 (예를 들어 전체 피처가 16개라면 분할을 위해 4개 참조)
- max_depth, min_samples_leaf, min_samples_split 등 결정 트리에서 과적합을 개선하기 위해 사용되는 파라미터 역시 랜덤 포레스트에서 동일하게 적용
[GridSearchCV를 이용해 랜덤 포레스트의 하이퍼 파라미터 튜닝]
(사용자 행동 데이터 세트 그대로 사용, n_estimators = 100, CV = 2)
# GridSearchCV를 이용해 랜덤 포레스트의 하이퍼 파라미터 튜닝
from sklearn.model_selection import GridSearchCV
params = {
'max_depth' : [8, 16, 24],
'min_samples_leaf' : [1, 6, 12],
'min_samples_split' : [2, 8, 16]
}
# RandomForestClassifier 객체 생성 후 GridSearchCV 수행
# 멀티 코어 환경에서는 n_jobs=-1 파라미터 추가 시 모든 CPU 코어를 이용해 학습 가능
rf_clf = RandomForestClassifier(n_estimators=100, 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_))
▶ max_depth 16, min_samples_leaf 6, min_samples_split 2 일 때 2개의 CV 세트에서 약 91.65%의 정확도가 측정되었다.
[추출된 최적 하이퍼 파라미터로 별도의 테스트 데이터 세트에서 예측 성능 측정]
# 추출된 최적 하이퍼 파라미터로 별도의 테스트 데이터 세트에서 예측 성능 측정
rf_clf1 = RandomForestClassifier(n_estimators=100, min_samples_leaf=6, max_depth=16,
min_samples_split=2, 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)))
피처의 중요도 시각화
RandomForestClassifier 역시 feature_importances_ 속성을 이용해 알고리즘이 선택한 피처의 중요도를 파악할 수 있다.
[피처의 중요도를 파악해 막대그래프로 시각화]
#피처의 중요도를 파악해 막대그래프로 시각화
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
ftr_importances_values = rf_clf1.feature_importances_
# Top 중요도로 정렬을 쉽게 하고, 시본(Seaborn)의 막대그래프로 쉽게 표현하기 위해 Series 변환
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()
▶ angle(X.gravityMean), tGravityAcc-mean()-Y, tGravityAcc-min()-X 등이 높은 피처 중요를 가지고 있다.
'[파이썬 Projects] > <파이썬 머신 | 딥러닝 & AI>' 카테고리의 다른 글
[파이썬] 분류 > 앙상블 - 4 : XG Boost (1) (0) | 2024.07.01 |
---|---|
[파이썬] 분류 > 앙상블 - 3 : GBM (0) | 2024.06.30 |
[파이썬] 분류: 앙상블 학습(Ensemble Learning) - 1 (0) | 2024.06.27 |
[파이썬 머신러닝] 결정트리 - 사용자 행동 인식 데이터 세트 (0) | 2024.06.23 |
[파이썬] 머신러닝 알고리즘: 결정 트리 - 3 (0) | 2024.06.23 |