본문 바로가기

Study doc./Summary

머신러닝 입문자를 위한 모델 구조

* 해당 포스팅은 파이썬 머신러닝 완벽 가이드(권철민, 2019) 교재를 참고하여 공부하며 작성한 글입니다.

 

"내일 강수량을 예측해봐!"

"우리 고객이 언제 이탈할지 예측해봐!"

 

 

다음과 같은 업무를 부여받았다면 여러분은 어떻게 하시겠습니까?

날씨의 경우에는 작년 이맘때의 강수량과 지난 한 주간의 강수량 등을 고려해서 미래의 강수량을 예측해볼 수 있을 것 같습니다.

고객 이탈의 경우에는 이탈했던 사례들의 특성들을 분석하고 기존 고객의 특성과 비교하며 이탈 여부를 예측할 수 있을 것입니다.

 

과거 데이터들을 기반으로 미래를 예측한다는 말과 같은데요, 머신러닝/ 딥러닝이 있기 전까지는 수학적, 통계적 능력이 뛰어나신 분들만이 할 수 있는 영역이었습니다.

하지만 요즘에는 모든 프로세스를 컴퓨터가 연산하기 때문에 비전공자 분들도 쉽게 구현하실 수 있습니다.

 

그럼 오늘은 구현하기 위한 기본적인 지식과 구조에 대해서 다뤄보도록 하겠습니다!!

 


순서

  1. 기본 구조
    1. 사이킷런 라이브러리
    2. 모델링 기본 구조
  2. 데이터 분할 - train_test_split()
  3. 교차검증 
    1. KFold() - 균형 클래스
    2. StratifiedKFold() - 불균형 클래스
    3. cross_val_score()
  4. 교차검증 + 하이퍼 파라미터 튜닝 - GridSearchCV()

1. 기본 구조

1-1. 사이킷런 라이브러리

머신러닝은 대부분 사이킷런(scikit-learn, 이하 sklearn) 이라는 파이썬 라이브러리를 사용합니다 (사이킷런 외에도 텐서플로, 케라스 등 다양한 라이브러리가 존재하지만 머신러닝에서는 사이킷런이 가장 효율적입니다).

왜냐하면 머신러닝에 사용되는 대부분의 메서드가 사이킷런에 잘 구현되어있기 때문인데요, 그렇다면 어떻게 그 메서드를 라이브러리로부터 불러오는지 형태를 확인하고 바로 구조를 파악해보겠습니다.

 

사이킷런 라이브러리의 metrics 모듈에서 accuracy_score 메서드를 사용하겠다

 

1-2. 모델링 기본 구조

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split

# 1. 훈련데이터, 테스트데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size=0.2, random_state=11)

# 2. 사용할 알고리즘 객체 생성
dt_clf = DecisionTreeClassifier(random_state=11)

# 3. 훈련데이터를 이용하여 객체 학습
dt_clf.fit(X_train, y_train)

# 4. pred 변수에 y_test 예측값 넣기
pred = dt_clf.predict(X_test)

# 5. 예측값과 실제값의 비교 점수 (여기선 정확도)
accuracy_score(y_test, pred)

 

* predict VS transform

지도학습 : fit (학습) -> predict (예측)

비지도학습 : fit (데이터 구조 변환) -> transform (비지도학습작업)

 

 

 

2. 데이터 분할 - train_test_split()

모델링의 기본 구조에서 보셨듯 가장 먼저 훈련데이터와 테스트데이터를 분할해주어야 합니다.

사이킷런 라이브러리에 있는 train_test_split() 메서드를 통해 쉽게 분할할 수 있습니다.

 

# 라이브러리
from sklearn.model_selection import train_test_split

# 데이터와 레이블 분류
data = dataset['data']
target = dataset['target']

# 나누기
x_train, x_test, y_train, y_test = train_test_split(data, target, test_size = 0.2, shuffle = True, stratify = target, random_state = 77)

 

  • test_size [default = 0.25]
  • shuffle [default = True] : 나누기 전에 데이터를 섞어줄 건지
  • stratify [default = None] : 클래스의 불균형 유지할건지
  • random_state : 분할 데이터셋 고정

 

* 만약 데이터를 train, validation, test 로 나누고 싶다면 train_test_split 를 두 번 사용하면 됩니다.

 

x_train_val, x_test, y_train_val, y_test = train_test_split(data, target, test_size = 0.2, shuffle = True, stratify = target, random_state = 77)
x_val, x_test, y_val, y_test = train_test_split(x_train_val, y_train_val, test_size = 0.2, shuffle = True, stratify = target, random_state = 77)

 

단 이 방법은 정확히 데이터를 6:2:2로 나누는게 아닙니다.

검증 데이터는 전체의 20%가 아닌 전체의 80% 중에서 20%이기 때문에, 정확히 얘기하면 전체의 16% 입니다.

 

 

 

3. 교차검증

한 번의 테스트로 모델의 성능을 평가하는것은 성급한 결정일 수 있습니다.

운 좋게 분할된 테스트 데이터가 불균형하거나 테스트 데이터에만 잘 맞는 모델이 선택될 수 있기 때문인데, 

그 해결방법으로 교차검증이 있습니다. 한번 알아볼까요?

3-1. KFold() - 균형 클래스

훈련데이터를 k개로 쪼갠뒤 하나씩 번갈아가며 테스트셋으로 지정하는 방법입니다.

이렇게 되면 운에 따라 결정되는 것이 아닌, 일반적인 성능 평가를 할 수 있습니다.

 

# 라이브러리
from sklearn.model_selection import KFold

# 테스트 셋 분리
x_data, x_test, y_data, y_test = train_test_split(data, target, test_size = 0.2, shuffle = True, stratify = target, random_state = 77)

# 객체 생성
k_fold = KFold(n_splits=3, shuffle=True, random_state=777)

# 인덱스 사용
for train_idx, val_idx in k_fold.split(x_data):
   x_train, y_train = x_data.iloc[train_idx], y_data.iloc[train_idx]
   x_val, y_val = x_data.iloc[val_idx], y_data.iloc[val_idx]

 

 

3-2. StratifiedKFold() - 불균형 클래스

클래스의 비율을 균등하게 해주는 메서드 입니다. 

예를 들어 암 환자 진단의 경우, 전체 데이터에서 암 환자의 경우가 아주 소수이기 때문에 무작위로 데이터를 분할할 경우 일반적이지 못한 결과가 나올수 있습니다.

 

# 라이브러리
from sklearn.model_selection import StratifiedKFold

# 테스트 셋 분리
x_data, x_test, y_data, y_test = train_test_split(data, target, test_size = 0.2, shuffle = True, stratify = target, random_state = 77)

# 객체 생성
s_kfold = StratifiedKFold(n_splits=3, shuffle=True, random_state=777)

# 인덱스 사용
for train_idx, val_idx in s_kfold.split(x_data, y_data): # 클래스 비율을 알아야 하기 때문에 레이블 데이터도 넣어야 함
   x_train, y_train = x_data.iloc[train_idx], y_data.iloc[train_idx]
   x_val, y_val = x_data.iloc[val_idx], y_data.iloc[val_idx]

 

3-3. cross_val_score()

estimator가 classifier의 경우 교차검증법이 stratifiedKFold, regression의 경우 KFold로 자동 적용됩니다 (회귀의 경우 stratifiedKFold가 불가능하기 때문).

 

from sklearn.model_selection import cross_val_score

# scores에 교차검증의 수만큼의 값이 들어있음
# 교차검증의 평균 점수를 구하고 싶다면 np.mean(scores)
scores = cross_val_score(dt_clf, X_train, y_train, scoring='accuracy', cv=5)

 

 

 

4. 교차검증 + 하이퍼 파라미터 튜닝 - GridSearchCV()

교차 검증과 더불어 최적의 파라미터까지 한 번에 찾을 수 있는 메서드도 있습니다.

매 교차검증마다 모든 파라미터 조합을 적용시켜 성능을 비교하는 방법인데요, 그렇기 때문에 연산량이 많고 시간이 오래걸린다는 단점이 있습니다.

구조를 한번 살펴볼까요?

 

from sklearn.model_selection import GridSearchCV

# 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size=0.2, random_state=11)

# 객체 생성
dt_clf = DecisionTreeClassifier(random_state=11)

# 실험해볼 파라미터 저장
parameters = {'max_depth':[1,2,3], 'min_samples_split':[2,3]}

# 교차검증과 파라미터의 정보를 생성했던 객체에 저장
grid_gtree = GridSearchCV(dt_clf, param_grid = parameters, cv=3, refit=True) # refit : 최적의 파라미터를 입력된 estimator 객체에 재학습시킨다

# 교차검증 진행 및 최적의 파라미터 찾기
grid_gtree.fit(X_train, y_train)

# 결과
pd.DataFrame(grid_gtree.cv_result_) # 종합결과
grid_gtree.best_params_ # 최적의 파라미터
grid_gtree.best_score_ # 최고의 점수
grid_gtree.best_estimator_ # 최적의 파라미터와 훈련데이터로 학습된 객체, 바로 predict 사용가능