지도학습: 레이블(Label), 즉 명시적인 정답이 있는 데이터가 주어진 상태에서 학습하는 머신러닝 방식
지도학습의 대표 유형인 '분류(Classification)'
분류는 다양한 머신러닝 알고리즘으로 구현 가능하다.
e.g. 나이브 베이즈, 로지스틱 회귀, 결정 트리, 서포트 벡터 머신, 신경망, 앙상블 등
앙상블 (Ensemble): 서로 다른/같은 알고리즘을 단순히 결합한 형태도 존재, 일반적으로는 배깅(Bagging)과 부스팅(Boosting) 방식으로 나뉜다.
: 데이터에 있는 규칙을 학습을 통해 자동으로 찾아내 트리 기반의 분류 규칙을 만드는 것
데이터의 어떤 기준을 바탕으로 규칙을 만들어야 가장 효율적인 분류가 될 것인가가 알고리즘의 성능을 크게 좌우한다.
Decision node = 규칙 조건, Leaf node = 결정된 클래스 값
❗많은 규칙이 있다 → 분류를 결정하는 방식이 복잡해진다 → 과적합으로 이어지기 쉽다
❗트리의 깊이가 깊어질수록 결정 트리의 예측 성능이 저하될 가능성 ↑
→ 데이터를 분류할 때 최대한 많은 데이터 세트가 해당 분류에 속할 수 있도록 Decision node의 규칙이 정해져야 한다
→ 균일한 데이터 세트를 구성할 수 있도록 분할하는 것이 필요
❓균일한 데이터 세트란?
- 데이터를 판단하는 데 있어 상대적으로 더 적은 정보가 필요한, 쉽게 예측할 수 있도록 된 데이터 세트 (e.g. 모두 검은 공)
- 정보 이득(Information Gain) 지수, 지니 계수로 균일도 측정
- 정보 이득 지수가 높거나, 지니 계수가 낮은 조건을 찾아 데이터 세트 분할
DecisionTreeClassifier
: 결정 트리 알고리즘을 구현한, 분류(Classification)를 위한 클래스
min_samples_split
: 노드를 분할하기 위한 최소한의 샘플 데이터 수, 과적합 제어 시 사용됨 (작게 설정 → 분할되는 노드 ↑ → 과적합 가능성 ↑)
min_samples_leaf
: 분할될 경우 왼쪽과 오른쪽 브랜치 노드에서 가져야 할 최소한의 샘플 데이터 수
max_features
: 최적의 분할을 위해 고려할 최대 피처 개수
max_depth
: 트리의 최대 깊이
max_leaf_nodes
: 말단 노드의 최대 개수
from sklearn.tree import export_graphviz
export_graphviz(dt_clf, out_file="tree.dot", class_names=iris_data.target_names,
feature_names=iris_data.feature_names, impurity=True, filled=True)
import graphviz
with open("tree.dot") as f:
dot_graph = f.read()
graph = graphviz.Source(dot_graph)
graph
# 이미지로 저장
# graph.render(filename='test_img', directory='C:/Users/splen/Desktop', format='png')
[결과 및 설명]
petal length(cm) <= 2.45
와 같은 피처의 조건: 자식 노드를 만들기 위한 규칙 조건, 이런 조건이 없으면 리프 노드
value = [ ]
는 클래스 값 기반의 데이터 건수, 위의 경우에 label 0/1/2 클래스에 대한 각각의 데이터 개수를 의미
gini
: value = [ ]
에서 주어진 데이터 분포에서의 지니 계수 (낮으면 좋음)
samples
: 현 규칙에 해당하는 데이터 건수
class
: 현 데이터에서 가장 많은 건수의 데이터가 속한 클래스, 예측 클래스
각 노드의 색깔은 데이터의 레이블 값 의미
색깔이 짙을수록 지니 계수 ↓, 해당 레이블에 속하는 샘플 데이터 ↑
완벽하게 클래스 값을 구별하기 위해 트리 노드를 계속해서 만들어 나감 → 모델이 쉽게 과적합되는 문제
따라서 결정 트리 알고리즘을 제어하는 대부분의 하이퍼 파라미터는 복잡한 트리가 생성되는 것을 막기 위한 용도이다.
결정트리는 어떠한 속성을 규칙 조건으로 선택하느냐가 중요한 요건이다.
feature_importances_
로 ndarray 형태로 피처 순서대로 중요도 값을 리턴
make_classification()
함수: 분류를 위한 테스트용 데이터 쉽게 생성 가능, 호출 시 반환되는 객체는 피처 데이터 세트 & 클래스 레이블 데이터 세트from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
%matplotlib inline
plt.title("3 Class values with 2 features sample data creation")
# 피처 2개, 클래스 3가지 유형의 분류 샘플 데이터 생성
X_features, y_labels = make_classification(n_features=2, n_redundant=0, n_informative=2, n_classes=3,
n_clusters_per_class=1, random_state=0)
# 2개의 피처로 2차원 좌표 시각화, 각 클래스 값은 다른 색깔로 표시
plt.scatter(X_features[:, 0], X_features[:, 1], marker='o', c=y_labels, s=25, edgecolor='k')
[output]
[트리 생성 제약 없는 경우]
from sklearn.tree import DecisionTreeClassifier
dt_clf = DecisionTreeClassifier(random_state=156).fit(X_features, y_labels)
visualize_boundary(dt_clf, X_features, y_labels)
[트리 생성 조건 제약한 경우]
# min_samples_leaf=6 으로 트리 생성 조건을 제약한 결정 경계 시각화
dt_clf = DecisionTreeClassifier(min_samples_leaf=6, random_state=156).fit(X_features, y_labels)
visualize_boundary(dt_clf, X_features, y_labels)
❗이상치(Outlier)란, 보통 관측된 데이터의 범위에서 많이 벗어난 아주 작은 값이나 큰 값을 말한다.
❗파라미터 vs. 하이퍼파라미터
➡️ 파라미터는 학습의 대상으로, 학습 알고리즘을 통해 자동적으로 학습하게 된다. 하이퍼파라미터는 경험, 데이터의 특성 등에 근거해 사용자가 설정하는 값이다.
GridSearchCV
from sklearn.model_selection import GridSearchCV
# 최대 깊이 6, 8, ... 로 변화시키면서 예측 성능 확인
params = {
'max_depth' : [6, 8, 10, 12, 16, 20, 24],
'min_samples_split' : [16] # 고정값
}
grid_cv = GridSearchCV(dt_clf, param_grid=params, scoring='accuracy', cv=5, verbose=1)
grid_cv.fit(X_train, y_train)
print('GridSearchCV 최고 평균 정확도 수치: {0:.4f}'.format(grid_cv.best_score_))
print('GridSearchCV 최적 하이퍼 파라미터:', grid_cv.best_params_)
max_depth
가 8일 때 5개 폴드 세트의 최고 평균 정확도 결과가 약 85.49%인 것으로 나타난다.
Fitting 5 folds for each of 7 candidates, totalling 35 fits
GridSearchCV 최고 평균 정확도 수치: 0.8549
GridSearchCV 최적 하이퍼 파라미터: {'max_depth': 8, 'min_samples_split': 16}
feature_importances_
이용하여 피처 중요도 확인 & 그래프로 나타내기: 여러 개의 분류기(Classifier)르 생성하고 그 예측을 결합함으로써 보다 정확한 최종 예측을 도출하는 기법
VotingClassifier
클래스 제공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)))
배깅의 대표적인 알고리즘
여러 개의 결정 트리 분류기가 전체 데이터에서 배깅 방식으로 각자의 데이터를 샘플링해 개별적으로 학습을 수행한 뒤, 최종적으로 모든 분류기가 보팅을 통해 예측 결정을 하게 된다.
부트스트래핑(Bootstraping) 분할 방식: 개별 트리가 학습하는 데이터 세트는 전체 데이터에서 일부가 중첩되게 샘플링된 데이터 세트이다.
Sklearn에서 RandomForestClassifier
제공
트리 기반 앙상블 알고리즘의 단점 중 하나는 하이퍼 파라미터가 너무 낳고 그로 인해 튜닝을 위한 시간이 많이 소모된다는 것이다.
랜덤 포레스트 하이퍼 파라미터
n_estimators
: 결정 트리 개수max_features
, max_depth
, min_samples_leaf
, min_samples_split
와 같은 결정 트리 파라미터와 똑같이 적용GridSearchCV
로 랜덤 포레스트의 하이퍼 파라미터 튜닝을 할 수 있다.