'll Hacker
[ML 실습] 8일차 복습- 사이킷런 기반 FrameWork 익히기 본문
Estimator 이해 및 fit( ), predict( ) 메서드
fit( )⏩ML 모델 학습 시키는 메서드.
predict( )⏩학습된 모델의 예측하는 메서드.
모든 사이킷런 클래스는 fit( )과 predict( )만을 이용하여 학습과 예측을 하는 것이 포인트‼️
분류 알고리즘을 구현한 클래스를 Classifier
회귀 알고리즘을 구현한 클래스를 Regressor
Classifier + Regressor = Estimator
cross_val_score( ), GridSearchCV 와 같은 하이퍼 파라미터 튜닝 지원하는 클래스의 경우,
이 Estimator를 인자로 받는다.

사이킷런의 주요 모듈
| 예제 데이터 | sklearn.datasets | 사이킷런에 내장되어 예제로 제공하는 데이터 세트 |
| 피처 처리 | sklearn.preprocessing | 데이터 전처리에 필요한 다양한 가공 기능 제공 (문자열을 숫자형 코드 값으로 인코딩, 정규화, 스케일링 등) |
| sklearn.feature_selection | 알고리즘에 큰 영향을 미치는 피처를 우선순위대로 셀렉션 직업을 수행하는 다양한 기능 제공 | |
| sklearn.feature_extraction | 텍스트 데이터나 이미지 데이터의 벡터화된 피처를 추출하는데 사용됨. 예를 들어, 텍스트 데이터에서 Count Vectorizer나 Tf-Idf Vectorizer 등을 생성하는 기능 제공. 텍스트 데이터 피처 추출 = sklearn.feature_extraction.text 모듈 이미지 데이터 피처 추출 = sklearn.feature_extraction.image 모듈 |
| 피처 처리 & 차원 축소 | sklearn.decomposition | 차원 축소와 관련한 알고리즘을 지원하는 모듈. PCA, NMF, Truncated SVD 등을 통해 차원 축소 기능을 수행 가능 |
| 데이터 분리, 검증 & 파라미터 튜닝 | sklearn.model_selection | 교차 검증을 위한 학습용/테스트용 분리, 그리드 서치로 최적 파라미터 추출 |
| 평가 | sklearn.metrics | 분류, 회귀, 클러스터링, 페어와이즈에 대한 다양한 성능 측정 방법 제공 |
| ML 알고리즘 | sklearn.ensemble | 앙상블 알고리즘 제공 랜덤 포레스트, 에이다 부스트, 그래디언트 부스팅 등을 제공 |
| sklearn.linear_model | 주로 linear regression, Ridge, Lasso 및 Logistic regression 등 회귀 관련 알고리즘을 지원 또한 SGD(Stochastic Gradient Descent) 관련 알고리즘도 제공 | |
| sklearn.naive_bayes | 나이브 베이즈 알고리즘 제공, 가우시안 NB, 다항 분포 NB 등 | |
| sklearn.neighbors | 최근접 이웃 알고리즘 제공, K-NN 등 | |
| sklearn.svm | 서포트 벡터 머신 알고리즘 제공 | |
| sklearn.tree | 의사 결정 트리 알고리즘 제공 | |
| sklearn.cluster | 비지도 클러스터링 알고리즘 제공 (K-평균, 계층형, DBSCAN 등) |
| 유틸리티 | sklearn.pipeline | 피처 처리 등의 변환과 ML 알고리즘 학습, 예측 등을 함께 묶어서 실행할 수 있는 유틸리티 제공 |
Model Selection 모듈
model_selection 모듈은 학습 데이터와 테스트 데이터 세트를 분리하거나 교차 검증 분할 및 평가, 그리고 Estimator의 하이퍼 파라미터를 튜닝하기 위한 다양한 함수와 클레스를 제공한다.
학습/테스트 데이터 세트 분리 - train_test_split( )
분리안한 상태의 코드 ⏬
import sklearn
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
iris = load_iris()
dt_clf = DecisionTreeClassifier()
train_data = iris.data
train_label = iris.target
dt_clf.fit(train_data, train_label)
# 학습 데이터 세트로 예측 수행
pred = dt_clf.predict(train_data)
print('예측 정확도:',accuracy_score(train_label,pred))

예측 결과가 100퍼센트인 이유는 이미 학습한 학습 데이터 세트를 기반으로 예측했기 때문이다.
따라서 예측을 수행하는 데이터 세트는 학습을 수행한 학습용 데이터 세트가 아닌 전용의 테스트 데이터 세트이어야한다.
형식: train_test_split(피처 데이터 set, 레이블 데이터 set, 전체 데이터 set 中 test set 비율, 난수발생값)
회색 글자는 선택적으로 파라미터를 받는다. 해당 파라미터는 다음과 같다:
- test_size : 전체 데이터에서 테스트 데이터 세트 크기를 얼마로 샘플링할 것인가를 결정한다. (디폴트: 0.25(25%))
- train_size : 전체 데이터에서 학습용 데이터 세트 크기를 얼마로 샘플링할 것인가를 결정한다. 잘 사용하진 않음
- shuffle : 데이터를 분리하기 전에 데이터를 미리 섞을지를 결정한다. (디폴트: True)
- random_state : 홏ㄹ할 때마다 동일한 학습/테스트용 데이터 세트를 생성하기 위해 주어지는 난수 값이다.
train_test_split( )의 반환값은 튜플 형태이다.
파이썬 튜플 형태?
소괄호로 묶어서 표현하거나 ,(쉼표)를 이용해서 표현한다.
ex)
tuple1 = (1, 2, 3)
tuple2 = 1, 2, 3
tuple3 = 1,
print tuple1
print tuple2
prtin tuple3
출력:
(1, 2, 3)
(1, 2, 3)
(1, )
튜플은 직접적으로 원소를 변경할 수 없다.
ex)
tuple = (1,2,3,4,5)
tuple[2] = 10 # 에러남...!
붓꽃 데이터 세트를 train_test_split( )을 이용해 테스트 데이터 세트를 전체의 30%로, 학습 데이터 세트를 70%로 분리, rand_state=121로 변경해 데이터 세트를 변경시켜보기
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
dt_clf = DecisionTreeClassifier()
iris_data = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size = 0.3, random_state=121)
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
print('예측 정확도:{0:.4f}'.format(accuracy_score(y_test,pred)))

교차검증에 대한 개념
학습데이터와 이에 대한 예측 성능을 평가하기 위한 별도의 테스트 데이터가 필요하다.
하지만, 이 방법도 Overfitting에 취약하다.
Overfitting이란?
모델이 학습 데이터에만 과도하게 최적화되어, 실제 예측을 다른 데이터로 수행할 경우에는 예측 성능이 과도하게 떨어지는 것을 말한다.
이에 대비하여 교차검증이 필요하다. ML은 데이터에 기반하고 데이터는 이상치, 분포도, 다양한 속성값, 피처 중요도 등 여러 가지 ML에 영향을 미치는 요소를 가지고 있다. 특정 ML 알고리즘에서 최적으로 동작할 수 있도록 데이터를 선별해 학습한다면 실제 데이터 양식과는 많은 차이가 있을 것이고 결국 성능 저하가 될 것이다.
교차검증은 이러한 데이터 편중을 막기 위해서 별도의 여러 세트로 구성된 학습 데이터 세트와 검증 데이터 세트에서 학습과 평가를 수행하는 것이다. 이 결과에 따라 하이퍼 파라미터 튜닝 등의 모델 최적화를 더욱 손쉽게 할 수 있다.

K 폴드 교차 검증 Process

사이킷런에서 K 폴드 교차 검증 프로세스를 구현하기 위해 KFold와 StratifiedKFold 클래스를 제공한다.
KFold 클래스 사용 실습
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold
import numpy as np
iris = load_iris()
features = iris.data
label = iris.target
dt_clf = DecisionTreeClassifier(random_state=156)
# 5개의 폴드 세트로 분리하는 KFold 객체와 폴드 세트별 정확도를 담을 리스트 객체 생성.
kfold = KFold(n_splits=5)
cv_accuracy = []
print('붓꽃 데이터 세트 크기:',features.shape[0])

전체 붓꽃 데이터는 모두 150개인 것을 확인할 수 있다.
n_iter = 0 # n_iter는 현재 몇번째 교차 검증인지 세는 역할
# KFold 객체의 split()를 호출하면 폴드별 학습용, 검증용 테스트의 로우 인덱스를 array로 반환
for train_index, test_index, in kfold.split(features):
#kfold.split()으로 반환된 인덱스를 이용해 학습용, 검증용 테스트 데이터 추출
X_train, X_test = features[train_index], features[test_index]
y_train, y_test = label[train_index], label[test_index]
# 학습 및 예측
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
n_iter += 1
# 반복 시마다 정확도 측정
accuracy = np.round(accuracy_score(y_test,pred),4)
train_size = X_train.shape[0]
test_size = X_test.shape[0]
print('\n#{0} 교차 검증 정확도 :{1}, 학습 데이터 크기:{2}, 검증 데이터 크기:{3}'.format(n_iter,accuracy, train_size, test_size))
print('#{0} 검증 세트 인덱스:{1}'.format(n_iter, test_index))
cv_accuracy.append(accuracy)
# 개별 iteration별 정확도를 합하여 평균 정확도 계산
print('\n## 평균 검증 정확도:',np.mean(cv_accuracy))

위 코드는 생성된 KFold 객체의 split( )을 호출해 전체 붓꽃 데이터를 5개의 폴드 데이터 세트로 분리한다.
따라서 학습용 데이터 세트는 이중 4/5인 120개, 검증 데이터 세트는 1/5인 30개로 분할된다.
KFold 객체는 split( )을 호출하면 학습용/검증용 데이터로 분할할 수 있는 인덱스를 반환한다. 실제로 학습용/검증용 데이터 추출은 반환된 인덱스를 기반으로 개발 코드에서 직접 수행해야한다. 5개의 폴드 세트를 생성하는 KFold 객체의 split( )을 호출해 교차검증 수행 시마다 학습과 검증을 반복해 예측 정확도를 측정한다. 그리고 split( )이 어떤 값을 실제로 반환하는지도 확인해 보기 위해 검증 데이터 세트의 인덱스도 추출
StratifiedKFold 클래스 사용 실습
Stratified KFold 는 불균형한 분포도를 가진 레이블(결정 클래스) 데이터 집합을 위한 K 폴드 방식이다.
불균형한 분포도를 가진 레이블 데이터 집합은 특정 레이블 값이 특이하게 많거나 매우 적어서 값의 분포가 한쪽으로 치우치는 것을 말한다. (이걸 어떻게 확인...?)
예를 들면, 대출 사기 데이터를 예측한다고 가정, 데이터 세트는 1억건이고, 레이블은 대출사기:1, 정상대출:0으로 구성돼있다. 레이블 값으로 1이 특정 개별 반복별 학습/테스트 데이터 세트에는 상대적으로 많이 들어있고, 다른 반복 학습/테스트 데이터 세트에는 그렇지 못한 결과가 발생한다. 대출 사기 레이블이 1인 레코드는 비록 건수는 작지만 알고리즘이 대출 사기를 예측하기 위한 중요한 피처 값을 가지고 있기 때문에 매우 중요한 데이터 세트이다. 따라서 원본 데이터와 유사한 대출 사기 레이블 값의 분포를 학습/테스트 세트에도 유지하는게 중요하다.
이때 사용하는 것이 StratifiedKFold이다. 이것은 원본 데이터의 레이블 분포를 먼저 고려한 뒤 이 분포와 동일하게 학습과 검증 데이터 세트를 분배한다.
KFold클래스 사용할 때 단점⏬
import pandas as pd
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
iris_df['label']=iris.target
iris_df['label'].value_counts()

kfold = KFold(n_splits=3)
n_iter=0
for train_index, test_index in kfold.split(iris_df):
n_iter += 1
label_train = iris_df['label'].iloc[train_index]
label_test=iris_df['label'].iloc[test_index]
print('## 교차 검증: {0}'.format(n_iter))
print('학습 레이블 데이터 분포:\n',label_train.value_counts())
print('검증 레이블 데이터 분포:\n',label_test.value_counts())

KFold할 때는 데이터를 무작위로 분할하기 때문에, 클래스(=레이블=target 변수=목표변수) 비율이 불균형할 경우 문제가 발생한다. 즉, 레이블은 정답(출력값, Y)을 의미하는 데이터셋의 목표변수(target)인데, 이것은 Supervised Learning에서 모델이 예측해야하는 값이다. 보통 y 또는 label 같은 이름으로 저장되는데, 목표변수가 예를 들면 임신 성공: 1, 임신 실패: 0이라고 하면 임신성공 타겟변수가 너무 많아버리면 학습이 제대로 이루어지지 않고 검증 결과가 신뢰할 수 없게 될 수 있다. 그래서 학습 데이터 세트와 검증 데이터 세트에 동일한 클래스(=레이블=target변수=목표변수) 분포를 유지해야한다.
Stratified KFold 클래스를 사용⏬
레이블 데이터 분포도에 따라 학습/검증 데이터를 나누기 때문에 split( ) 메서드에 인자로 피처 데이터 세트뿐만 아니라 레이블 데이터 세트도 반드시 필요하다.
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=3)
n_iter=0
for train_index, test_index in skf.split(iris_df, iris_df['label']):
n_iter +=1
label_train=iris_df['label'].iloc[train_index]
label_test=iris_df['label'].iloc[test_index]
print('## 교차검증: {0}'.format(n_iter))
print('학습 레이블 데이터 분포:\n', label_train.value_counts())
print('검증 레이블 데이터 분포:\n', label_test.value_counts())


출력 결과를 보며 학습 레이블과 검증 레이블 데이터 값의 분포도가 거의 동일하게 할당됐음을 알 수 있다. 전체 150개의 데이터에서 학습으로 100개, 검증으로 50개가 교차 검증 단계별로 할당된 것을 볼 수 있다.
다음은 StratifiedKFold를 이용해 데이터를 분리 한 코드이다:
df_clf = DecisionTreeClassifier(random_state=156)
skfold = StratifiedKFold(n_splits=3)
n_iter=0
cv_accuracy=[]
# StratifiedKFold의 split() 호출 시 반드시 레이블 데이터 세트도 추가 입력 필요
for train_index, test_index in skfold.split(features,label):
# split()으로 반환된 인덱스를 이용해 학습용, 검증용 테스트 데이터 추출
X_train, X_test = features[train_index], features[test_index]
y_train, y_test = label[train_index], label[test_index]
# 학습 및 예측
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
# 반복 시마다 정확도 측정
n_iter+=1
accuracy=np.round(accuracy_score(y_test,pred),4)
train_size = X_train.shape[0]
test_size = X_test.shape[0]
print('\n#{0} 교차 검증 정확도:{1}, 학습 데이터 크기: {2}, 검증 데이터 크기: {3}'.format(n_iter, accuracy,train_size,test_size))
print('#{0} 검증 세트 인덱스:{1}'.format(n_iter,test_index))
cv_accuracy.append(accuracy)
# 교차 검증별 정확도 및 평균 정확도 계산
print('\n## 교차 검증별 정확도:',np.round(cv_accuracy, 4))
print('## 평균 검증 정확도:',np.round(np.mean(cv_accuracy),4))

일반적으로 분류에서의 교차 검증은 KFold가 아니라 StratifiedKFold로 분할되어야한다.
회귀에서는 StratifiedKFold가 지원되지 않는다. 회귀는 이산값 형태의 레이블이 아니라 연속된 숫자값이기 떄문에 결정값별로 분포를 정하는 의미가 없다.
cross_val_score( )
이전에는 KFold로 데이터를 학습하고 예측하는 코드를 보면 먼저, 폴드 세트를 설정하고 for 루프에서 반복으로 학습 및 테스트 데이터의 인덱스를 추출한 뒤 반복적으로 학습과 예측ㅇㄹ 수행하고 예측 성능을 반환해다면,
cross_val_score( )은 한번에 수행해주는 API이다.
형식: cross_val_score(estimator, X, y=None, scoring=None, cv=None, n_jobs=1, verbose=0, fit_params=None, pre_dispatch='2*n_jobs')
- estimator = Classifier or Regressor
- X = 피처 데이터 세트
- y = 레이블 데이터 세트
- scoring = 예측 성능 평가 지표
- cv = 교차 검증 폴드 수
cross_val_score( ) 수행 후 반환 값은 scoring 파라미터로 지정된 성능 지표 측정값을 배열 형태로 반환한다.
import sklearn
import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score, cross_validate
from sklearn.datasets import load_iris
iris_data = load_iris()
dt_clf = DecisionTreeClassifier(random_state=156)
data=iris_data.data
label=iris_data.target
#성능지표는 정확도(accuracy), 교차검증 세트는 3개
scores=cross_val_score(dt_clf,data,label,scoring='accuracy',cv=3)
print('교차 검증별 정확도:',np.round(scores,4))
print('평균 검증 정확도:',np.round(np.mean(scores),4))

cross_val_score( ) API는 내부에서 Estimator를 학습(fit), 예측(predict), 평가(evaluation) 시켜주므로 간단하게 교차검증 수행가능하다.
GridSearchCV - 교차검증, 최적 하이퍼 파라미터 튜닝 한번에 수행가능
Classifier나 Regressor와 같은 알고리즘에 사용되는 하이퍼 파라미터를 순차적으로 입력하면서 최적의 파라미터를 도출할 수 있는 방안을 제공한다. 데이터 세트를 cross-validation을 위한 학습/테스트 세트로 자동으로 분할한 뒤에 하이퍼 파라미터 그리드에 기술된 모든 파라미터를 순차적으로 적용해 최적의 파라미터를 찾을 수 있게 해준다. 그래서 오래 걸린다.
GridSearchCV클래스 생성자 파라미터:
- estimator = classifier, regressor, pipeline
- param_grid = key + 리스트 값을 가지는 딕셔너리가 주어진다. estimator의 튜닝을 위해 파라미터명과 사용될 여러 파라미터 값을 지정한다.
- scoring = 예측 성능을 측정할 평가 방법을 지정한다.
- cv = 교차 검증을 위해 분할되는 학습/테스트 세트의 개수를 지정한다.
- refit = 디폴트가 True이며, True로 생성 시 가장 최적의 하이퍼 파라미터를 찾은 뒤 입력된 estimator 객체를 해당 하이퍼 파라미터로 재학습시킨다.
결정 트리 알고리즘을 구현한 DecisionTreeClassifier의 중요 하이퍼 파라미터인 max_depth, min_samples_split의 값을 변화시키면서 최적화를 진행했다. 테스트할 하이퍼 파라미터 세트는 딕셔너리 형태로 하이퍼 파라미터의 명칭은 문자열 Key값으로, 하이퍼 파라미터의 값은 리스트 형으로 설정한다.
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
#데이터를 로딩하고 학습 데이터와 테스트 데이터 분리
iris_data = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris_data.data,iris_data.target, test_size=0.2, random_state=121)
dtree=DecisionTreeClassifier()
### 파라미터를 딕셔너리 형태로 설정
parameters={'max_depth':[1,2,3],'min_samples_split':[2,3]}
학습 데이터 세트를 GridSearchCV 객체의 fit(학습 데이터 세트) 메서드에 인자로 입력한다.
GridSearchCV 객체의 fit(학습데이터 세트) 메서드를 수행하면 학습 데이터를 cv에 기술된 폴딩 세트로 분할해 param_grid에 기술된 하이퍼 파라미터를 순차적으로 변경하면서 학습/평가를 수행하고 그 결과를 cv_results_ 속성에 기록한다. cv_results_는 gridsearchcv의 결과 세트로서 딕셔너리 형태로 key값과 리스트 형태의 value값을 가진다. cv_results_를 Pandas의 DataFrame으로 변환하면 내용을 좀 더 쉽게 볼 수 있음.
# param_grid의 하이퍼 파라미터를 3개의 train, test set fold로 나누어 테스트 수행 설정.
### refit=True가 default임. True이면 가장 좋은 파라미터 설정으로 재학습시킴
grid_dtree=GridSearchCV(dtree, param_grid=parameters,cv=3, refit=True)
# 붓꽃 학습 데이터로 param_grid의 하이퍼 파라미터를 순차적으로 학습/평가
grid_dtree.fit(X_train, y_train)
# GridSearchCV 결과를 추출해 DataFrame으로 변환
scores_df=pd.DataFrame(grid_dtree.cv_results_)
scores_df[['params','mean_test_score','rank_test_score','split0_test_score','split1_test_score','split2_test_score']]

print('GridSearchCV 최적 파라미터:',grid_dtree.best_params_)
print('GridSearchCV 최고 정확도:{0:.4f}'.format(grid_dtree.best_score_))
- params 칼럼에는 수행할 때마다 적용된 개별 하이퍼 파라미터 값을 나타낸다.
- rank_test_score는 하이퍼 파라미터별로 성능이 좋은 score 순위를 나타낸다. 1이 가장 뛰어난 순위이며 이때의 파라미터가 최적의 하이퍼 파라미터이다.
- mean_test_score는 개별 하이퍼 파라미터별로 CV의 폴딩 테스트 세트에 대해 총 수행한 평가 평균값이다.
GridSearchCV 객체의 fit( )을 수행하면 최고 성능을 나타낸 하이퍼 파라미터의 값과 그때의 평가 결과값이 각각 best_params_, best_score_ 속성에 기록된다. (즉, cv_results_의 rank_test_score가 1일 때의 값이다.

refit=True이면 GridSearchCV가 최적 성능을 나타내는 하이퍼 파라미터로 Estimator를 학습해 best_estimator_를 이용해 앞에서 train_test_split( )으로 분리한 테스트 데이터 세트에 대해 예측하고 성능을 평가하면
from sklearn.metrics import accuracy_score
# GridSearchCV의 refit으로 이미 학습된 estimator반환
estimator=grid_dtree.best_estimator_
# GridSearchCV의 best_estimator_는 이미 최적 학습이 됐으므로 별도 학습이 필요없음
pred=estimator.predict(X_test)
print('테스트 데이터 세트 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))

96.67%의 결과가 도출했다.
참고: 파이썬 머신러닝 완벽 가이드, 권철민, 위키북스
'AI > 머신러닝' 카테고리의 다른 글
| [ML 실습] 10일차 복습- 사이킷런으로 타이타닉 생존자 예측모델 만들기(Kaggle) (0) | 2025.03.23 |
|---|---|
| [ML 실습] 9일차 복습- 사이킷런 머신러닝 만들어보기(데이터 전처리) (0) | 2025.03.17 |
| [ML 실습] 7일차 복습- 사이킷런 머신러닝 만들어보기(개요) (0) | 2025.03.12 |
| [ML 실습] 6일차 복습- 판다스 DataFrame(3) (2) | 2025.01.28 |
| [ML 실습] 5일차 복습- 판다스 DataFrame(2) (0) | 2025.01.28 |