머신러닝

[파이썬 머신러닝 완벽 가이드] - 4.1~4.6장

주니빙 2024. 11. 1. 05:59

4장 분류

 

4.1  분류의 개요

지도학습 : 레이블, 즉 명시적인 정답이 있는 데이터가 주어진 상태에서 학습하는 머신러닝 방식

 

지도학습의 대표적인 유형인 분류는 학습 데이터로 주어진 데이터의 피처와 레이블값(결정 값,클래스 값)을 머신러닝 알고리즘으로 학습해 모델을 생성하고, 이렇게 생성된 모델에 새로운 데이터 값이 주어졌을 때 미지의 레이블 값을 예측하는 것이다.

 

  • 분류를 구현하는 다양한 머신러닝 알고리즘
    1. 베이즈(Bayes) 통계와 생성 모델에 기반한 나이브 베이즈
    2. 독립변수와 종속변수의 선형 관계성에 기반한 로지스틱 회귀(Logistic Regression)
    3. 데이터 균일도에 따른 규칙 기반의 결정 트리(Decision Tree)
    4. 개별클래스 간의 최대 분류 마진을 효과적으로 찾아주는 서포트 벡터 머신(Support Vector Machine)
    5. 근접 거리를 기준으로 하는 최소 근접(Nearest Neighbor) 알고리즘
    6. 심층 연결 기반의 신경망(Neural Network)
    7. 서로 다른(또는 같은) 머신러닝 알고리즘을 결합한 앙상블(Ensemble)

 

4.2  결정 트리

결정 트리 : ML 알고리즘 중 직관적으로 이해하기 쉬운 알고리즘

데이터에 있는 규칙을 학습을 통해 자동으로 찾아내 트리 기반의 분류 규칙을 만드는 것

 

결정 트리 구조

  • 리프 노드 : 결정된 클래스 값
  • 서브 트리 : 새로운 규칙 조건마다 생성
  • 규칙 노드 : 규칙 조건이 되는 것

 

하지만 많은 규칙이 있다는 것 = 분류를 결정하는 방식이 더욱 복잡

⇒ 과적합으로 이어지기 쉽다. 즉,트리의 깊이(depth)가 갚어질수록 결정 트리의 예측 성능이 저히될 가능성이 높다.

가능한 한 적은 결정 노드로 높은 예측 정확도를 가지려면 데이터를 분류할 때 최대한 많은 데이터 세트가 해당 분류에 속할 수 있도록 결정 노드의 규칙이 정해져야 한다 ⇒ 어떻게 트리를 분할(Split)할 것인가가 중요 ⇒ 최대한 균일한 데이터 세트를 구성할 수 있도록 분할하는 것이 필요

 

균일도를 측정하는 대표적인 방법

  1. 엔트로피를 이용한 정보 이득
  2. 지니와 지니 계수

 

결정 트리 장단점

➕ 쉽다. 직관적이다.

➕ 피처의 스케일링이나 정규화 등의 사전 가공 영향도가 크지 않다.

➖ 과적합으로 알고리즘 성능이 떨어진다. 이를 극복하기 위해 트리의 크기를 사전에 제한하는 튜닝 필요.

 

결정 트리 모델의 시각화 : Graphviz 패키지 사용

사이킷런은 Graphviz 패키지와 쉽게 인터페이스할 수 있도록 export__graphviz( ) API를 제공

 

4.3  앙상블 학습

앙상블 학습을 통한 분류 : 여러 개의 분류기를 생성하고 그 예측을 결합함으로써 보다 정확한 최종 예측을 도출하는 기법

⇒ 단일 분류기보다 신뢰성이 높은 예측값을 얻음

앙상블 학습의 유형 : 보팅(Voting), 배깅(Bagging), 부스팅(Boosting)

 

보팅(Voting), 배깅(Bagging) : 분류기가 투표를 통해 최종 예측 결과를 결정하는 방식

보팅(Voting) : 선형 회귀, K 최근접 이웃, 서포트 벡터 머신 알고리즘

배깅(Bagging) : 단일 ML 알고리즘(결정 트리)

 

보팅(Voting) 유형 : 하드 보팅 & 소프트 보팅

  • 하트 보팅 : 다수결 원칙과 비슷
  • 소프트 보팅 : 분류기들의 레이블 값 결정 확률을 모두 더하고 이를 평균해서 이들 중 확률이 가장 높은 레이블 값을 최종 보팅 결괏값으로 선정

 

보팅 분류기(Voting Classifier)

사이킷런은 보팅 방식의 앙상블을구현한 VotingClassifier 클래스를 제공

import pandas as pd

from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

cancer = load_breast_cancer()

data_df = pd.DataFrame(cancer.data, columns=cancer.feature_names)
data_df.head(3)

 

estimators 는 리스트 값으로 보팅에 시용될 여러 개의 Classifier 객체들을 튜플 형식으로 입력받으며 voting은 ‘hard’ 시 하드 보팅, ‘soft’ 시 소프트 보팅 방식을 적용하라는 의미(기본은 ‘hard’)

# 개별 모델은 로지스틱 회귀와 KNN 임. 
lr_clf = LogisticRegression(solver='liblinear')
knn_clf = KNeighborsClassifier(n_neighbors=8)

# 개별 모델을 소프트 보팅 기반의 앙상블 모델로 구현한 분류기 
vo_clf = VotingClassifier( estimators=[('LR',lr_clf),('KNN',knn_clf)] , voting='soft' )

X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, 
                                                    test_size=0.2 , random_state= 156)

# VotingClassifier 학습/예측/평가. 
vo_clf.fit(X_train , y_train)
pred = vo_clf.predict(X_test)
print('Voting 분류기 정확도: {0:.4f}'.format(accuracy_score(y_test , pred)))

# 개별 모델의 학습/예측/평가.
classifiers = [lr_clf, knn_clf]
for classifier in classifiers:
    classifier.fit(X_train , y_train)
    pred = classifier.predict(X_test)
    class_name= classifier.__class__.__name__
    print('{0} 정확도: {1:.4f}'.format(class_name, accuracy_score(y_test , pred)))

보팅 분류기가 정확도가 조금높게 나타남

보팅으로 여러 개의 기반 분류기를 결합한다고해서 무조건 기반 분류기보다 에측 성능이 향상되지는 않으며 데이터의 특성과 분포 등 다양한 요건에 따라 오히려 기반 분류기 중 가장 좋은 분류기의 성능이 보팅 했을 때보다 나을 수도 있다.

 

4.4  랜덤 포레스트

배깅의 대표적인 알고리즘은 랜덤 포레스트

 

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

랜덤 포레스트의 기반 알고리즘은 결정 트리로서, 결정 트리의 쉽고 직관점인 장점을 그대로 가지고 있다.

 

랜덤 포레스트는 여러 개의 결정 트리 분류기가 전체 데이터에서 배깅 방식으로 각자의 데이터를 샘플링해 개별적으로 학습을 수행한 뒤 최종적으로 모든 분류기가 보팅을 통해 예측 결정을 하게 된다.

부트스트래핑 분할 방식 : 여러 개의 데이터 세트를 중첩되게 분리하는 것

이렇게 데이터가 중첩된 개별 데이터 세트에 결정 트리 분류기를 각각 적용하는 것이 랜덤 포레스트

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

 

❗️사용자 행동 인식 데이터 데이터 출처: https://archive.ics.uci.edu/ml/datasets/human+activity+recognition+using+smartphones

30명에게 스마트폰 센서를 장착한 뒤 사람의 동작과 관련된 여러 가지 Feature를 수집한 것

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('/Users/choejunhee/Documents/ecc 스터디/머신러닝 스터디/human_activity/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('/Users/choejunhee/Documents/ecc 스터디/머신러닝 스터디/human_activity/train/X_train.txt',sep='\\s+', names=feature_name )
    X_test = pd.read_csv('/Users/choejunhee/Documents/ecc 스터디/머신러닝 스터디/human_activity/test/X_test.txt',sep='\\s+', names=feature_name)
    
    # 학습 레이블과 테스트 레이블 데이터을 DataFrame으로 로딩하고 컬럼명은 action으로 부여
    y_train = pd.read_csv('/Users/choejunhee/Documents/ecc 스터디/머신러닝 스터디/human_activity/train/y_train.txt',sep='\\s+',header=None,names=['action'])
    y_test = pd.read_csv('/Users/choejunhee/Documents/ecc 스터디/머신러닝 스터디/human_activity/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(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))

 

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

# 하이퍼 파라미터 그리드 설정
params = {
    'max_depth': [8, 16, 24],
    'min_samples_leaf': [1, 6, 12],
    'min_samples_split': [2, 8, 16]
}

# RandomForestClassifier 객체 생성
rf_clf = RandomForestClassifier(n_estimators=100, random_state=0, n_jobs=-1)

# GridSearchCV 객체 생성
grid_cv = GridSearchCV(rf_clf, param_grid=params, cv=2, n_jobs=-1)

# y_train을 1차원 배열로 변환
y_train = y_train.values.ravel()

# GridSearchCV 수행
grid_cv.fit(X_train, y_train)

# 결과 출력
print('최적 하이퍼 파라미터 :\\n', grid_cv.best_params_)
print('최고 예측 정확도: {0:.4f}'.format(grid_cv.best_score_))

 

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

 

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)
fig1 = plt.gcf()
plt.show()
plt.draw()
fig1.savefig('rf_feature_importances_top20.tif', format='tif', dpi=300, bbox_inches='tight')

 

4.5  GBM

부스팅 알고리즘 : 여러 개의 약한 학습기를 순차적으로 학습-예측하면서 잘못 예측한 데이터에 가중치를 부여를 통해 오류를 개선해 나가면서 학습하는 방식

부스팅의 구현 : 에이다 부스트(AdaBoost)와 그래디언트 부스트(Gradient Boost)

from sklearn.ensemble import GradientBoostingClassifier
import time
import warnings
warnings.filterwarnings('ignore')

X_train, X_test, y_train, y_test = get_human_dataset()

# GBM 수행 시간 측정을 위함. 시작 시간 설정.
start_time = time.time()

gb_clf = GradientBoostingClassifier(random_state=0)
gb_clf.fit(X_train , y_train)
gb_pred = gb_clf.predict(X_test)
gb_accuracy = accuracy_score(y_test, gb_pred)

print('GBM 정확도: {0:.4f}'.format(gb_accuracy))
print("GBM 수행 시간: {0:.1f} 초 ".format(time.time() - start_time)

 

4.6  XGBoost(eXtra Gradient Boost)

XGBoost : 트리 기반의 앙상블 학습에서 가장 각광받고 있는 알고리즘

  • XGBoost의 주요 장점
    1. 뛰어난 예측 성능
    2. GBM 대비 빠른 수행시간
    3. 과적합 규제(Regularization)
    4. Tree pruning(나무 가지치기)
    5. 자체 내장된 교차 검증
    6. 결손값 자체 처리

 

XGBoost 설치하기

 

파이썬 래퍼 XGBoost 하이퍼 파라미터

  • 일반 파라미터 : 일반적으로 실행 시 스레드 개수나 silent 모드 등의 선택을 위한 파라미터로 디폴트 파라미터 값을 바꾸는 경우는 거의 없다
  • 부스터 파라미터 : 트리 최적화. 부스팅, reqularization 등과 관련 파라미터 등을 지칭
  • 학습 태스크 파라미터 : 학습 수행 시의 객체 함수, 평가를 위한 지표 등을 설정하는 파라미터

 

파이썬 래퍼 XGBoost 적용 - 위스콘신 유빌밤 예측

파이썬 래퍼 XGBoost 적용 - 위스콘신 유빌밤 예측.ipynb
0.16MB