이번 포스팅에서는 머신러닝 모델링할때 주의해야할 과적합이 무엇인지, 그리고 과적합을 해결하는 방법에 대해 알아보겠습니다.
Overfitting (과대적합)
- 일반화 (Generalization)
- 모델이 새로운 데이터셋(테스트 데이터)에 대하여 정확히 예측하면 이것을 (훈련데이터에서 테스트데이터로) 일반화 되었다고 말한다.
- 모델이 훈련 데이터로 평가한 결과와 테스트 데이터로 평가한 결과의 차이가 거의 없고 좋은 평가지표를 보여준다.
- 과대적합 (Overfitting)
- 모델이 훈련 데이터에 대한 예측성능은 너무 좋지만 일반성이 떨어져 새로운 데이터(테스트 데이터)에 대해선 성능이 좋지 않은 것을 Overfitting이라고 한다.
- 이는 모델이 훈련 데이터 세트의 특징을 너무 맞춰서 학습 되었기 때문에 일반화 되지 않아 새로운 데이터셋(테스트세트)에 대한 예측 성능이 떨져 발생한다.
- 과소적합 (Underfitting)
- 모델이 훈련 데이터과 테스트 데이터셋 모두에서 성능이 안좋은 것을 말한다.
- 모델이 너무 간단하여 훈련 데이터에 대해 충분히 학습하지 못해 데이터셋의 패턴들을 다 찾아내지 못해서 발생한다.
Overfitting(과대적합)의 원인
- 모델이 너무 복잡한 경우
- Overfitting을 줄이기 위한 규제 하이퍼파라미터 설정
- Feature 개수 줄이기
- 데이터의 문제
- 데이터 전처리를 통해 질 좋은 데이터를 만든다.
- 데이터를 더 수집한다.
- 현실적으로 어려운 경우가 많다.(비용과 시간의 문제)
Overfitting 확인
- 위스콘시 암환자 데이터 사용
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
X, y = cancer.data, cancer.target
X_train, X_test, y_train, y_test =\
train_test_split(X, y, stratify=y, random_state=1)
from sklearn.tree import DecisionTreeClassifier
#모델 생성
dt = DecisionTreeClassifier()
#학습
dt.fit(X_train, y_train)
# ==> DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
# max_depth=None, max_features=None, max_leaf_nodes=None,
# min_impurity_decrease=0.0, min_impurity_split=None,
# min_samples_leaf=1, min_samples_split=2,
# min_weight_fraction_leaf=0.0, presort='deprecated',
# random_state=None, splitter='best')
from sklearn.metrics import accuracy_score
pred_train = dt.predict(X_train) #학습데이터로 분류 예측
pred_test = dt.predict(X_test) #테스트데이토 분류 예측
print('Train 정확도:', accuracy_score(y_train, pred_train))
print('Test 정확도:', accuracy_score(y_test, pred_test))
Train 정확도: 1.0
Test 정확도: 0.9370629370629371
# 결정트리의 트리구조 시각화 - graphviz 이용
from sklearn.tree import export_graphviz
from graphviz import Source
g = export_graphviz(dt, #학습이 끝난 결정트리객체
out_file=None,
feature_names = cancer.feature_names,
class_names = cancer.target_names,
rounded=True,
filled=True)
graph = Source(g)
graph
Overfitting (과대적합) 해결 방법
1. Decision Tree 복잡도 제어(규제)
- Decision Tree 모델을 복잡하게 하는 것은 노드가 너무 많이 만들어 지는 것이다.
- 노드가 많이 만들어 질수록 훈련데이터셋에 과대적합된다.
- 적절한 시점에 트리 생성을 중단해야 한다.
- 규제 관련 하이퍼파라미터
- max_depth: 트리의 최대 깊이(질문수)
- max_leaf_nodes: Leaf node 의 최대 개수를 제한
- min_samples_leaf: leaf 노드가 되기 위한 sample 수 제한
- min_samples_split: 나누는 최소 샘플 수
# max_depth: 작은 값일 수록 단순한 모델이 된다.
dt2 = DecisionTreeClassifier(max_depth=3)
dt2.fit(X_train, y_train)
pred_train2 = dt2.predict(X_train)
pred_test2 = dt2.predict(X_test)
print('Train:', accuracy_score(y_train, pred_train2))
print('Test:', accuracy_score(y_test, pred_test2))
Train: 0.971830985915493
Test: 0.9440559440559441
from sklearn.tree import export_graphviz
from graphviz import Source
g = export_graphviz(dt2, #학습이 끝난 결정트리객체
out_file=None,
feature_names = cancer.feature_names,
class_names = cancer.target_names,
rounded=True,
filled=True)
graph = Source(g)
graph
2. GridSearch (격자탐색)
- GridSearch란 하이퍼파리미터에 넣을 수 있는 값을 순차적으로 입력한 다음에 가장 높은 성능을 보이는 하이퍼파라미터를 찾는 방법
- 적당한 max depth를 찾는것이 핵심이다.
max_depth_list = range(1,20)
# 학습/테스트 데이터셋의 정확도들 저장할 리스트
train_acc_list = []
test_acc_list = []
for max_depth in max_depth_list:
tree = DecisionTreeClassifier(max_depth=max_depth)
tree.fit(X_train, y_train)
pred_train = tree.predict(X_train)
pred_test = tree.predict(X_test)
train_acc_list.append(accuracy_score(y_train, pred_train))
test_acc_list.append(accuracy_score(y_test, pred_test))
import pandas as pd
d = {
"max_depth":max_depth_list,
"Train정확도":train_acc_list,
"Test정확도":test_acc_list
}
acc_df = pd.DataFrame(d)
acc_df.head()
import matplotlib.pyplot as plt
acc_df.set_index('max_depth').plot(figsize=(10,7))
plt.xticks(max_depth_list)
plt.ylabel('정확도')
plt.show()
Grid Search 를 이용한 하이퍼파라미터 튜닝
- 하이퍼 파라미터 (Hyper Parameter)
- 머신러닝 모델을 생성할 때 사용자가 직접 설정하는 값
- 머신러닝 모델에 따라 다르기는 하지만 많은 하이퍼파라미터들을 변경할 수 있다.
- 하이퍼 파라미터 튜닝
- 하이퍼 파라미터의 설정에 따라 모델의 성능이 달라진다.
최적의 하이퍼파라미터 찾기
- 만족할 만한 하이퍼파라미터들의 값의 조합을 찾을 때 까지 일일이 수동으로 조정
- GridSearch 사용
- GridSearchCV()
- 시도해볼 하이퍼파라미터들을 지정하면 모든 조합에 대해 교차검증 후 제일 좋은 성능을 내는 하이퍼파라미터 조합을 찾아준다.
- 적은 수의 조합의 경우는 괜찮지만 시도할 하이퍼파라미터와 값들이 많아지면 너무 많은 시간이 걸린다.
- GridSearchCV()
- Random Search 사용
- RandomizedSearchCV()
- GridSeach와 동일한 방식으로 사용한다.
- 모든 조합을 다 시도하지 않고 각 반복마다 임의의 값만 대입해 지정한 횟수만큼만 평가한다.
- RandomizedSearchCV()
GridSearchCV 매개변수및 결과조회
- 주요 매개변수
- estimator: 모델객체 지정
- params : 하이퍼파라미터 목록을 dictionary로 전달 '파라미터명':[파라미터값 list] 형식
- scoring: 평가 지표
- cv : 교차검증시 fold 개수.
- n_jobs : 사용할 CPU 코어 개수 (None:1(기본값), -1: 모든 코어 다 사용)
- 메소드
- fit(X, y) : 학습
- predict(X): 제일 좋은 성능을 낸 모델로 predict()
- predict_proba(X): 제일 좋은 성능을 낸 모델로 predict_proba() 호출
- 결과 조회 변수
- cv_results_ : 파라미터 조합별 결과 조회
- best_params_ : 가장 좋은 성능을 낸 parameter 조합 조회
- best_estimator_ : 가장 좋은 성능을 낸 모델 반환
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier()
param_grid = {
'max_depth':[4,5,6,7],
'max_leaf_nodes':[3,5,7,9,10],
'criterion':['entropy'] #기본값 말고 다른값을 사용할 경우.
}
gs = GridSearchCV(dt,
param_grid=param_grid,
scoring='accuracy',
cv = 3,
n_jobs=-1)
gs.fit(X_train, y_train)
RandomizedSearchCV
- 주요 매개변수
- estimator: 모델객체 지정
- param_distributions : 하이퍼파라미터 목록을 dictionary로 전달 '파라미터명':[파라미터값 list] 형식
- n_iter : 파라미터 검색 횟수
- scoring: 평가 지표
- cv : 교차검증시 fold 개수.
- n_jobs : 사용할 CPU 코어 개수 (None:1(기본값), -1: 모든 코어 다 사용)
- 메소드
- fit(X, y) : 학습
- predict(X): 제일 좋은 성능을 낸 모델로 predict()
- predict_proba(X): 제일 좋은 성능을 낸 모델로 predict_proba() 호출
- 결과 조회 변수
- cv_results_ : 파라미터 조합별 결과 조회
- best_params_ : 가장 좋은 성능을 낸 parameter 조합 조회
- best_estimator_ : 가장 좋은 성능을 낸 모델 반환
from sklearn.model_selection import RandomizedSearchCV
dt = DecisionTreeClassifier()
param = {
'max_depth':range(1, 21),
'max_leaf_nodes':range(5, 101, 5),
'criterion':['entropy','gini']
}
# 800
n_iter = 80 #기본 :10
rs = RandomizedSearchCV(dt,
param_distributions=param,
n_iter=n_iter,
cv=5,
n_jobs=-1)
rs.fit(X_train, y_train)
3. Pipeline (파이프라인)
- 여러 단계의 머신러닝 프로세스 (전처리의 각 단계, 모델생성, 학습) 처리 과정을 설정하여 한번에 처리되도록 한다.
- 파이프라인은 여러개의 변환기와 마지막에 변환기 또는 추정기를 넣을 수 있다. (추정기-Estimator는 마지막에 만 올 수 있다.)
- 전처리 작업 파이프라인 : 변환기들로만 구성
- 전체 프로세스 파이프 라인 : 마지막에 추정기를 넣는다
Pipeline 생성 및 학습
- (이름, 변환기) 를 리스트로 묶어서 전달한다.
- 마지막에는 추정기가 올 수있다.
- pipeline.fit()
- 각 순서대로 각 변환기의 fit_transform()이 실행되고 결과가 다음 단계로 전달된다. 마지막 단계에서는 fit()만 호출한다.
- 보통 마지막이 추정기일때 사용
- pipeline.fit_transform()
- fit()과 동일하나 마지막 단계에서도 fit_transform()이 실행된다.
- 보통 전처리 작업 파이프라인(모든 단계가 변환기)일 때 사용
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
# 정규화 -> SVM 학습
pipe = [
('scaler', StandardScaler()),
('svm', SVC())
]
pipeline = Pipeline(pipe, verbose=True)
print(pipeline.steps)
pred_train = pipeline.predict(X_train)
pred_test = pipeline.predict(X_test)
accuracy_score(y_train, pred_train)
0.9882629107981221
accuracy_score(y_test, pred_test)
0.9790209790209791
GridSearch에서 Pipeline 사용
- 하이퍼파라미터 지정시 파이프라인
프로세스이름__하이퍼파라미터
형식으로 지정한다.
pipe = [
('scaler', StandardScaler()),
('svm', SVC())
]
pipeline = Pipeline(pipe, verbose=True)
param_grid = {
'svm__C':[0.01, 0.1,1,10,100],
'svm__gamma':[0.01, 0.1,1,10,100]
}
gs = GridSearchCV(pipeline, param_grid=param_grid, cv=5)
gs.fit(X_train, y_train)
gs.best_params_ # {'svm__C': 10, 'svm__gamma': 0.01}
make_pipeline() 함수를 이용한 파이프라인 생성을 편리하게 하기
from sklearn.pipeline import make\_pipeline
pipeline2 = make\_pipeline(StandardScaler(),
SVC())
print(pipeline2.steps)
728x90
반응형
'Data Analysis & ML > Machine Learning' 카테고리의 다른 글
[Machine Learning][머신러닝][지도학습] SVM(Support Vector Machine) (0) | 2020.09.01 |
---|---|
[Machine Learning][머신러닝][지도학습] K-최근접 이웃(KNN) (0) | 2020.09.01 |
[Machine Learning][머신러닝] Classification(분류) 평가지표 (0) | 2020.08.28 |
[Machine Learning][머신러닝] 데이터 전처리(범주형/연속형) (5) | 2020.08.27 |
[Machine Learning][머신러닝] 데이터셋 나누기와 교차검증 (0) | 2020.08.26 |