2018. 1. 15. 09:03ㆍML(머신러닝)/BASIC
도움이 되셨다면, 광고 한번만 눌러주세요. 블로그 관리에 큰 힘이 됩니다 ^^
지도와 비지도 다양한 머신러닝 알고리즘 살펴봄
-> 모델 평가와 매개변수 선택에 대해 알아보자
비지도 학습은 선택하는 일 정성적인 일 = 정량적이지 않다는 말
지도 학습 위주로 살펴봄
평가를 위해서는 train_test_split = > train / test
모델 생성 => fit
test 모델 평가 => score 메서드
score 메서드 -> 정확히 분류된 샘플의 비율을 계산하는 방법
train / test 나누는 이유 -> 새로운 데이터가 얼마나 일반화되어 있는지 측정하기 위해
안정적인 일반화를 위해 -> 교차 검증(cross validation)
score R^2 이외에 다른 방법
from sklearn.datasets import make_blobs
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
# 인위적인 데이터셋을 만듭니다
X, y = make_blobs(random_state=0)
# 데이터와 타깃 레이블을 훈련 세트와 테스트 세트로 나눕니다
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# 모델 객체를 만들고 훈련 세트로 학습시킵니다
logreg = LogisticRegression().fit(X_train, y_train)
# 모델을 테스트 세트로 평가합니다
print("테스트 세트 점수: {:.2f}".format(logreg.score(X_test, y_test)))
교차 검증(Cross Validation)
일반화 성능 재기 위해 훈련 세트 테스트 세트 한번 나누는 것보다 더 안정적인 방법
데이터를 여러 번 반복해서 나누고 여러 모델을 학습
주로 k-겹 교차 검증 | k는 특정 숫자 보통 5, 10
ex) 5-겹 교차 검증
데이터를 먼저 fold 라고 하는 거의 비슷한 크기의 부분 집합 "다섯" 개로 나눔
-> 그 다음 모델 생성
첫번째 모델은 1번째 fold - Test / 나머지 train
2번째 fold -Test /...
....
이런 식으로 다섯 번의 분할마다 정확도 측정하여 다섯 개의 정확도 얻음
scikit-learn 교차검증 방법
from sklearn.model_selection import cross_val_score from sklearn.datasets import load_iris from sklearn.linear_model import LogisticRegression iris = load_iris() logreg = LogisticRegression() scores = cross_val_score(logreg, iris.data, iris.target) # default = 3 - fold print("교차 검증 점수: {}".format(scores))
scores = cross_val_score(logreg, iris.data, iris.target, cv=5) print("교차 검증 점수: {}". format(scores)
교차 검정의 장점
한번 나누는 것보다 -> 교차검증하면 1. train_test_split 이용하면 데이터 무작위
-> 운 좋게 훈련 세트에는 분류하기 어려운 샘플만 담을 수 있다는 가정 해보자 -> 당연히 정확도는 매우 떨어질 것이다
# 그러나 교차 검증을 사용하면 테스트 세트에 각 샘플이 정확하게 한 번씩 들어간다
-> 각 샘플은 폴드 중 하나에 속하며 각 폴드는 하나의 테스트가 된다. -> 그래서 교차 검증 점수를 높이기 위해서 -> 잘 일반화됨
또 데이터를 여러 개로 나누면 모델이 훈련 데이터에 얼마나 민감한지 알 수 있다.
최악의 경우와 최선의 경우를 각각 확인할 수 있다.
2. 한번 분할했을 때보다 더 데이터를 효과적으로 사용 가능하다.
보통 train_test_split -> 75 % train / 25 % test하고 평가를 학습 -> 5겹을 사용하면 매 반복에서 80 % train 20% test
# 단점
연산 시간이 늘어난다 -> k-fold 면 한번 할 때보다 시간이 k 배가 걸린다.
교차 검증 함수는 -> 모델 반환 x -> cross_val_score 함수 호출 -> 내부적으로 여러 모델 만들지만
교차 검증 목적 -> 단지 주어진 데이터 셋에 학습된 알고리즘이 얼마나 일반화될 수 있는지를 평가
sklearn.model_seletion 모듈의 cross_val_predict 함수 사요하여 교차 검증으로 만든 예측값을 구할 수 있다.
cross_val_predict(logreg.iris.data, iris.target, cv=5) -> 각 폴드가 테스트 세트일 때 예측된 값을 반환해준다.
계층별 K-겹 교차 검증과 그 외 전략들
항상 좋은 것은 아님
만약에 iris 데이터 -> 3겹 교차 검증 사용 -> 첫 번째 반복에서 테스트에는 클래스 0 / 2번째에는 테스트에는 1 / 3번째는 테스트에는 2
-> 정확도 0 -> 단순한 k 겹 교차 검증 문제가 있어서 -> scikit-learn에서는 이 방법 대신 계층별 k 겹 교차검증 (stratified)
cross_val_score 함수에서 기본적으로 분류에는 StratifiedKFold 사용하여 훈련 / 테스트 나누고 | 회귀에서는 단순한 KFold
KFold에서 shuffle 매개변수를 기본 값 FALSE 대신 TRUE 지정하면 폴드 나누기 전 무작위로 섞임
하지만 cross_val_score에서 KFold는 제어 방법 x -> 따로 KFold 만들어 -> cv 매개변수로 전달
교차검증 상세 옵션
cross_val_score 사용할 때 CV 매개변수 이용해 폴드 개수 정함
그러나 SCIKIT-LEARN에서는 CV 매개변수에 교차 검증 분할기(cross_validation spliter) 전달함으로써 더 세밀하게 제어해 분할 가능
회귀 : k-겹 교차 검증 / 분류 : 계층별 k-겹 교차 검증 기본값이 잘 작동한다
-> 하지만 다른 사람의 결괏값을 재현할 때는 분류 데이터 셋에 기본 k-겹 교차 검증 사용할 때
-> 먼저 model_selection 모듈에서 KFold 분할기를 import 하고 원하는 폴드 수를 넣어 객체 성성
from sklearn.model_selection import KFold
kfold = KFold(n_splits=5)
print("교차 검증 점수:\n{}".format(
cross_val_score(logreg, iris.data, iris.target, cv=kfold)))
kfold = KFold(n_splits=3)
print("교차 검증 점수:\n{}".format(
cross_val_score(logreg, iris.data, iris.target, cv=kfold)))
각 폴드는 iris 데이터셋에 클래스중 대응 x -> 학습 x -> 계층별 폴드를 만드는 대신 다른 해결 방법
데이터를 섞어서 (shuffle) -> 샘플의 순서를 뒤죽박죽 만들기
KFold에서 shuffle FALSE -> TRUE 바꿔주기
random_state로 고정해서 똑같은 작업 재현 가능
kfold = KFold(n_splits=3, shuffle=True, random_state=0)
print("교차 검증 점수:\n{}".format(
cross_val_score(logreg, iris.data, iris.target, cv=kfold)))
LOOCV
LOOCV 교차 검증은 폴드 하나에 샘플 하나만 들어있는 K 겹 교차 검증으로 생각할 수 있다.
각 반복에서 하나의 데이터 포인트를 선택해 테스트 세트로 사용한다. 작은 데이터 셋에서는 효과적, 큰 데이터에서는 시간이 걸림
from sklearn.model_selection import LeaveOneOut
loo = LeaveOneOut()
scores = cross_val_score(logreg, iris.data, iris.target, cv=loo)
print("교차 검증 분할 횟수: ", len(scores))
print("평균 정확도: {:.2f}".format(scores.mean()))
임의 분할 교차검증
유연한 또 다른 방법 임의 분할 교차 검증 ( shuffle-split cross-validation)
임의 분할 교차 검증에서 train_size 만큼의 포인트로 훈련 세트를 만들고, test_size 만큼의 (훈련 세트와 중복되지 않는) 포인트로 테스트 세트
이 분할은 n_splits 횟수만큼 반복
다음 코드는 50 % 훈련 50 % test 10번 분할 반복
from sklearn.model_selection import ShuffleSplit
shuffle_split = ShuffleSplit(test_size=.5, train_size=.5, n_splits=10)
scores = cross_val_score(logreg, iris.data, iris.target, cv=shuffle_split)
print("교차 검증 점수:\n{}".format(scores))
그룹별 교차 검증
데이터 안에 매우 연관된 그룹 -> 교차검증 널리 사용
얼굴 사진 인식 100명 모음 -> 한 사람을 찍은 여러 장의 사진 , 여러 표정으로 가지고 있다
-> 이 데이터셋에 없는 사람의 표정을 정확히 구분하는 것이 목표
성능 측정하기 위해 계층별 교차 검증 사용할 수 있지만 -> 같은 사람의 사진이 훈련 세트와 테스트 세트에 모두 나타날 수 있다
완전히 새로운 얼굴보다 훈련 세트에 잇던 얼굴의 표정은 훨씬 쉽게 식별할 수 있을 것이다.
새 얼굴에 대한 일반화 성능 더 정확하게 평가하려면 훈련 세트와 테스트 세트에서 서로 다른 사람의 사진이 들어가야 한다.
이를 위해 사진의 사람이 누구인지 배열을 groups 매개변수로 전달받을 수 있는 GroupKFold를 사용 가능
groups 배열은 훈련 세트와 테스트 세트를 만들 때 분리되지 않아야 할 그룹을 지정하는 것이며 , 클래스 레이블은 아니다.
데이터에 그룹 있는 것들 ex ) 의료 애플리케이션 , 같은 환자로부터 얻은 여러 샘플을 가지고 새로운 환자에게 일반화하는 것이 목적
마찬가지로 음성인식에서도 같은 사람의 목소리가 여러 개 저장 -> 새로운 사람의 대화를 인식하고 싶다
from sklearn.model_selection import GroupKFold
# 인위적 데이터셋 생성
X, y = make_blobs(n_samples=12, random_state=0)
# 처음 세 개의 샘플은 같은 그룹에 속하고
# 다음은 네 개의 샘플이 같습니다.
groups = [0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3]
scores = cross_val_score(logreg, X, y, groups, cv=GroupKFold(n_splits=3))
print("교차 검증 점수:\n{}".format(scores))
12개의 포인트 -> groups는 각 데이터에 대해 각 포인트가 어떤 그룹에 속하는지 (어떤 환자) 4개 그룹
굳이 정렬할 필요가 없다 -> 여기서 예를 들어서 한 것 그룹 레이블 기반으로 계산해줌
다양한 상황에서 적용할 수 있는 다양한 교차 검증 전략 있다 그중 기본으로 KFold / StratifiedKFold / GroupKFold
그리드 서치
앞에서는 일반화 -> 지금부터는 매개변수를 튜닝하여 일반화 성능 높이기
매개변수란 무엇인가
모델에서 중요한 매개변수(일반화 성능 높이는) 값 찾는 것은 어렵지만 모든 모델과 데이터셋에서 해야 할 필수적인 것
GRID_SEARCH 로서 관심 있는 매개변수들을 대상으로 가능한 모든 조합 시도하는 것
EX) RBF 커널 SVM 할 때 커널의 폭 : gamma / 규제 매개변수 C 중요 총 조합수 36개
# 간단한 그리드 서치 구현
from sklearn.svm import SVC
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target,
random_state=0)
print("훈련 세트의 크기: {} 테스트 세트의 크기: {}".format(
X_train.shape[0], X_test.shape[0]))
best_score = 0
for gamma in [0.001, 0.01, 0.1, 1, 10, 100]:
for C in [0.001, 0.01, 0.1, 1, 10, 100]:
# 매개변수의 각 조합에 대해 SVC를 훈련시킵니다
svm = SVC(gamma=gamma, C=C)
svm.fit(X_train, y_train)
# 테스트 세트로 SVC를 평가합니다
score = svm.score(X_test, y_test)
# 점수가 더 높으면 매개변수와 함께 기록합니다
if score > best_score:
best_score = score
best_parameters = {'C': C, 'gamma': gamma}
print("최고 점수: {:.2f}".format(best_score))
print("최적 파라미터: {}".format(best_parameters))
매개변수 과대 적합과 검증 세트
모델 정확도 97 -> 낙관적인 주장이다 -> 이 정확도가 새로운 데이터에는 이어지지 않을 수 있다
매개변수를 조정하기 위해 테스트 세트를 이미 사용했기 때문에 -> 평가를 할 수 없다
-> 그래서 훈련 / 검증 나눈 이유 -> 즉 평가를 위해서 모델을 만들 때 사용하지 않은 독립 데이터셋 필요
이 문제 해결하기 위해 훈련 : 모델 / 검증 : 매개변수 선택 / 테스트 : 매개변수 평가
검증 세트를 사용해 최적의 매개변수 선택 -> 그 매개변수에서 훈련 세트와 검증 세트 데이터를 모두 이용해 모델을 다시 만든다.
이렇게 하는 이유 -> 모델을 만들 때 가능한 많은 데이터를 이용하기 위해서
from sklearn.svm import SVC
# 데이터를 훈련+검증 세트 그리고 테스트 세트로 분할
X_trainval, X_test, y_trainval, y_test = train_test_split(
iris.data, iris.target, random_state=0)
# 훈련+검증 세트를 훈련 세트와 검증 세트로 분할
X_train, X_valid, y_train, y_valid = train_test_split(
X_trainval, y_trainval, random_state=1)
print("훈련 세트의 크기: {} 검증 세트의 크기: {} 테스트 세트의 크기:"
" {}\n".format(X_train.shape[0], X_valid.shape[0], X_test.shape[0]))
best_score = 0
for gamma in [0.001, 0.01, 0.1, 1, 10, 100]:
for C in [0.001, 0.01, 0.1, 1, 10, 100]:
# 매개변수의 각 조합에 대해 SVC를 훈련시킵니다
svm = SVC(gamma=gamma, C=C)
svm.fit(X_train, y_train)
# 검증 세트로 SVC를 평가합니다
score = svm.score(X_valid, y_valid)
# 점수가 더 높으면 매개변수와 함께 기록합니다
if score > best_score:
best_score = score
best_parameters = {'C': C, 'gamma': gamma}
# 훈련 세트와 검증 세트를 합쳐 모델을 다시 만든 후
# 테스트 세트를 사용해 평가합니다
svm = SVC(**best_parameters)
svm.fit(X_trainval, y_trainval)
test_score = svm.score(X_test, y_test)
print("검증 세트에서 최고 점수: {:.2f}".format(best_score))
print("최적 파라미터: ", best_parameters)
print("최적 파라미터에서 테스트 세트 점수: {:.2f}".format(test_score))
더 일반화가 잘되게 한 것을 알 수 있다 새로운 데이터에 대해 92% 정확하게 분류
훈련 세트 / 검증 세트 / 테스트 세트 -> 아주 중요 ###
거의 모든 모델을 짤 때 기본이 되므로 저런 코드를 이용해하는 것이 중요!!
교차 검증을 사용한 그리드 서치
훈련 세트 / 검증 세트 / 테스트 세트 이렇게 데이터를 나눴지만 나누는 방법에 매우 민감!!!
-> 일반화 성능 올리기 위해 교차검증 사용하기
for gamma in [0.001, 0.01, 0.1, 1, 10, 100]:
for C in [0.001, 0.01, 0.1, 1, 10, 100]:
# 매개변수의 각 조합에 대해 SVC를 훈련시킵니다
svm = SVC(gamma=gamma, C=C)
# 교차 검증을 적용합니다
scores = cross_val_score(svm, X_trainval, y_trainval, cv=5)
# 교차 검증 정확도의 평균을 계산합니다
score = np.mean(scores)
# 점수가 더 높으면 매개변수와 함께 기록합니다
if score > best_score:
best_score = score
best_parameters = {'C': C, 'gamma': gamma}
# 훈련 세트와 검증 세트를 합쳐 모델을 다시 만듭니다
svm = SVC(**best_parameters)
svm.fit(X_trainval, y_trainval)
정확도 평가하려면 5 X 6 X 6 = 180... 컴퓨터를 좋은 걸로 바꿔야 하나...
교차 검증은 -> 주어진 데이터 셋에서 알고리즘을 평가하는 방법
하지만 그리드 서치와 같은 탐색방법과 합쳐서 많이 사용 -> 그래서 많은 사람이 교차 검증이란 용어를
교차 검증을 사용한 그리드 서치라고 많이 한다고 한다.
그래서 SCIKIT-LEARN -> GridSearchCV 제공한다
GridSearchCV 먼저 딕셔너리 행태로 검색 대상 매개변수 지정해야 한다
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100],
'gamma': [0.001, 0.01, 0.1, 1, 10, 100]}
print("매개변수 그리드:\n{}".format(param_grid))
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
grid_search = GridSearchCV(SVC(), param_grid, cv=5, return_train_score=True)
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target,
random_state=0)
grid_search.fit(X_train, y_train)
# fit 사용하면 param_grid에 설정된 매개변수 조합에 대한 교차검증 실시
# 매개변수를 사용할 때
print("최적 매개변수: {}".format(grid_search.best_params_))
print("최고 교차 검증 점수: {:.2f}".format(grid_search.best_score_))
print("최고 성능 모델:\n{}".format(grid_search.best_estimator_))
import pandas as pd
pd.set_option('display.max_columns', None)
# DataFrame으로 변환합니다
results = pd.DataFrame(grid_search.cv_results_)
# 처음 다섯 개 행을 출력합니다
display(np.transpose(results.head()))
#C와 gamma 시각화
scores = np.array(results.mean_test_score).reshape(6, 6)
# 교차 검증 평균 점수 히트맵 그래프
mglearn.tools.heatmap(scores, xlabel='gamma', xticklabels=param_grid['gamma'],
ylabel='C', yticklabels=param_grid['C'], cmap="viridis")
정확도가 높으면 -> 밝은 색 / 낮으면 -> 어두운 색
SVC 가 매개변수에 민감
바람직하지 못한 예
fig, axes = plt.subplots(1, 3, figsize=(13, 5))
param_grid_linear = {'C': np.linspace(1, 2, 6),
'gamma': np.linspace(1, 2, 6)}
param_grid_one_log = {'C': np.linspace(1, 2, 6),
'gamma': np.logspace(-3, 2, 6)}
param_grid_range = {'C': np.logspace(-3, 2, 6),
'gamma': np.logspace(-7, -2, 6)}
for param_grid, ax in zip([param_grid_linear, param_grid_one_log,
param_grid_range], axes):
grid_search = GridSearchCV(SVC(), param_grid, cv=5)
grid_search.fit(X_train, y_train)
scores = grid_search.cv_results_['mean_test_score'].reshape(6, 6)
# 교차 검증 평균 점수의 히트맵 그래프
scores_image = mglearn.tools.heatmap(
scores, xlabel='gamma', ylabel='C', xticklabels=param_grid['gamma'],
yticklabels=param_grid['C'], cmap="viridis", ax=ax)
plt.colorbar(scores_image, ax=axes.tolist())
첫 번째 그래프는 점수 변화가 없어서 -> 전체 매개변수 그리드가 같은 색 -> 부적절하게 발생
그러나 매개변수 설정이 바뀌어도 정확에 변화 없다면 -> 매개변수가 전혀 중요하지 않은 것
매우 극단적인 값 적용해보고 -> 매개변수 바꿔가며 정확도 살펴봄
## 두 번째 그래프 세로 띠 -> Gamma 매개 변수만 정확도에 영향을 준다는 뜻
# 교차 검증 점수를 토대로 매개변수 그리드를 튜닝하는 것 -> 아주 안전한 방법
비대칭 매개변수 그리드 탐색
어떤 경우에는 모든 매개변수 조합 GridSearchCV 수행하는 것 좋지 않을 수 있음
SVC는 KERNEL 매개변수를 가지고 있는데 어떤 커널을 사용하는지에 따라 관련 있는 매개변수들이 결정
KERNEL =" linear" 이면 선형 모델 C 매개 변수만 사용
KERNEL = "RBF" C와 GAMMA를 모두 사용 (C, GAMMA , KERNEL 매개변수의 모든 조합을 조사 X)
KERNEL ="linear" 이면 gamma를 사용하지 않으므로 -> 시간 낭비
이런 조건부 매개변수 조합을 적용하려면 gridsearchcv에 전달할 param_grid를 딕셔너리의 리스트로 만들어줌
각 딕셔너리는 독립적인 그리드로 적용됩니다.
param_grid = [
{'kernel': ['rbf'], 'C': [0.001, 0.01, 0.1, 1, 10, 100], 'gamma': [0.001, 0.01, 0.1, 1, 10, 100]},
{'kernel': ['linear'], 'C': [0.001, 0.01, 0.1, 1, 10, 100]}] print("그리드 목록:\n {}". format(param_grid))
grid_search = GridSearchCV(SVC(), param_grid, cv=5, return_train_score=True)
grid_search.fit(X_train, y_train)
print("최적 파라미터: {}".format(grid_search.best_params_))
print("최고 교차 검증 점수: {:.2f}".format(grid_search.best_score_))
results = pd.DataFrame(grid_search.cv_results_)
# 좀 더 나은 출력을 위해 결과를 전치시킵니다
display(results.T)
그리드 서치에 다양한 교차 검증 적용
cross_val_score와 비슷하게 gridsearchcv는 분류에는 기본적으로 계층형 k-겹 교차 검증을 사용하고 회귀에는 k-겹 교차 검증 사용
중첩 교차 검증
훈련 , 검증, 테스트 세트 / 훈련 세트와 테스트 세트로 나눈 다음 훈련 세트로 교차 검증 수행하는 방식으로 바꿈
하지만 GridSearchCV를 사용할 때 데이터를 훈련 세트와 테스트 세트로 한 번만 나누기 때문에 분할에 크게 의존
중합 교차 검증 - 바깥쪽 루프 ( 훈련 / 테스트 ) 그리고 각 훈련 세트에 대해 그리드 서치 실행
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100],
'gamma': [0.001, 0.01, 0.1, 1, 10, 100]}
scores = cross_val_score(GridSearchCV(SVC(), param_grid, cv=5),
iris.data, iris.target, cv=5)
print("교차 검증 점수: ", scores)
print("교차 검증 평균 점수: ", scores.mean())
print(param_grid)
안쪽 루프와 바깥쪽 루프에 각각 계층형 5겹 교차 검증 사용
param_grid 매개변수 조합은 42개 , 42x5x5 = 1050개나 되므로 연산 매우 비싼 방법
def nested_cv(X, y, inner_cv, outer_cv, Classifier, parameter_grid):
outer_scores = []
# outer_cv의 분할을 순회하는 for 루프
# (split 메소드는 훈련과 테스트 세트에 해당하는 인덱스를 리턴합니다)
for training_samples, test_samples in outer_cv.split(X, y):
# 최적의 매개변수를 찾습니다
best_parms = {}
best_score = -np.inf
# 매개변수 그리드를 순회합니다
for parameters in parameter_grid:
# 안쪽 교차 검증의 점수를 기록합니다
cv_scores = []
# inner_cv의 분할을 순회하는 for 루프
for inner_train, inner_test in inner_cv.split(
X[training_samples], y[training_samples]):
# 훈련 데이터와 주어진 매개변수로 분류기를 만듭니다
clf = Classifier(**parameters)
clf.fit(X[inner_train], y[inner_train])
# 검증 세트로 평가합니다
score = clf.score(X[inner_test], y[inner_test])
cv_scores.append(score)
# 안쪽 교차 검증의 평균 점수를 계산합니다
mean_score = np.mean(cv_scores)
if mean_score > best_score:
# 점수가 더 높은면 매개변수와 함께 기록합니다
best_score = mean_score
best_params = parameters
# 바깥쪽 훈련 데이터 전체를 사용해 분류기를 만듭니다
clf = Classifier(**best_params)
clf.fit(X[training_samples], y[training_samples])
# 테스트 세트를 사용해 평가합니다
outer_scores.append(clf.score(X[test_samples], y[test_samples]))
return np.array(outer_scores)
from sklearn.model_selection import ParameterGrid, StratifiedKFold
scores = nested_cv(iris.data, iris.target, StratifiedKFold(5),
StratifiedKFold(5), SVC, ParameterGrid(param_grid))
print("교차 검증 점수: {}".format(scores))
교차 검증과 그리드 서치 병렬화
그리드 서치는 데이터 용량이 크고 매개변수 수도 많을 때는 -> 상당한 연산 부하
=> 병렬화 가능
하나의 교차 검증 분할에서 특정 매개변수를 설정 사용 -> 모델을 만드는 일은 다른 매개변수 설정이나 모델과 전혀 상관 입어 진행할 수 있기 때문이다.
그러므로 그리드 서치와 교차 검증은 여러 cpu 코어 또는 클러스터에 병렬화하기 좋습니다.
GridSearchCV와 cross_val_score에서 n_jobs 사용해 지정
skitlearn - 병렬화를 중첩해서 사용 x -> 그래서 n_jobs 옵션 사용하면 -> 병렬화 옵션 사용 X
평가 지표와 측정
이진 분류의 평가 지표
이진 분류에서 양성 클래스가 - 관심 클래스
에러의 종류
정확도 만으로는 예측 성능 측정하기 부족함
불균형 데이터 셋
한 클래스가 다른 클래스보다 많을 때
from sklearn.datasets import load_digits digits = load_digits() y = digits.target == 9 # 0~8 FALSE 9 TRUE X_train, X_test, y_train, y_test = train_test_split( digits.data, y, random_state=0)
from sklearn.dummy import DummyClassifier
dummy_majority = DummyClassifier(strategy='most_frequent').fit(X_train, y_train)
pred_most_frequent = dummy_majority.predict(X_test)
print("예측된 레이블의 고유값: {}".format(np.unique(pred_most_frequent)))
print("테스트 점수: {:.2f}".format(dummy_majority.score(X_test, y_test)))
DUMMYCLASSIFIER 실제 모델과 비교하기 위해 간단한 규칙 지원 STRATEGY 옵션 - STRATIFIED - 클래스 비율에 맞게 / MOST_FREQUENT - 가장 많은 레이블
# -> 학습하지 않고 90 % 얻음
from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier(max_depth=2).fit(X_train, y_train)
pred_tree = tree.predict(X_test)
print("테스트 점수: {:.2f}".format(tree.score(X_test, y_test)))
from sklearn.linear_model import LogisticRegression
dummy = DummyClassifier().fit(X_train, y_train)
pred_dummy = dummy.predict(X_test)
print("dummy 점수: {:.2f}".format(dummy.score(X_test, y_test)))
logreg = LogisticRegression(C=0.1).fit(X_train, y_train)
pred_logreg = logreg.predict(X_test)
print("logreg 점수: {:.2f}".format(logreg.score(X_test, y_test)))
오차 행렬
- 이진 분류 평가 결과를 나타낼 때 가장 널리 사용하 넌 법
CONFUSION_MATRIX 함수 사용해서 이용함
from sklearn.metrics import confusion_matrix
confusion = confusion_matrix(y_test, pred_logreg)
print("오차 행렬:\n{}".format(confusion))
오차 행렬의 대각형렬 - 정확히 분류된 경우
다른 항목들 한 클래스의 샘플들이 다른 클래스로 잘 본 된 것이 얼마나 많은지
print("빈도 기반 더미 모델:")
print(confusion_matrix(y_test, pred_most_frequent))
print("\n무작위 더미 모델:")
print(confusion_matrix(y_test, pred_dummy))
print("\n결정 트리:")
print(confusion_matrix(y_test, pred_tree))
print("\n로지스틱 회귀")
print(confusion_matrix(y_test, pred_logreg))
재현율= 민감도, 적중률, 진짜 양성 비율
재현율 최적화와 정밀도 최적화는 "상충"
IF FN를 없애서 -> 재현율 완벽 -> 하지만 샘플 양성으로 예측하면 -> FP 증가 -> 정밀도 떨어짐
IF FP를 깡그리 없애면 -> 정밀도 완벽 -> 하지만 재현율 떨어짐
정밀도와 재현율의 조화 평균 인 f - 점수
from sklearn.metrics import f1_score
print("빈도 기반 더미 모델의 f1 score: {:.2f}".format(
f1_score(y_test, pred_most_frequent)))
print("무작위 더미 모델의 f1 score: {:.2f}".format(f1_score(y_test, pred_dummy)))
print("트리 모델의 f1 score: {:.2f}".format(f1_score(y_test, pred_tree)))
print("로지스틱 회귀 모델의 f1 score: {:.2f}".format(
f1_score(y_test, pred_logreg)))
# 2가지 주목 : 하나는 양성 클래스로 예측된 것이 하나도 없어서 빈도 기반 더미 모델 -> 에러 발생
또한 무작위 더미 분류기와 트리 분류기 사이에서도 - 뚜렷한 차이
f-1 점수가 직관적으로 판단할 때 유용하다. 하지만 이해하거나 설명하기 어려움
from sklearn.metrics import classification_report
print(classification_report(y_test, pred_most_frequent,
target_names=["9 아님", "9"]))
print(classification_report(y_test, pred_dummy,
target_names=["9 아님", "9"]))
print(classification_report(y_test, pred_logreg, target_names=["9 아님", "9"]))
불확실성 고려
오차 행렬과 분류 리포트가 - 예측 결과 자세히 분석하게 도와줌
-> 하지만 예측값은 모델에 담긴 많은 정보가 이미 손실된 상태 -> 대부분 분류기 예측의 확신 가늠하기 위한 (decision_function. decision_proba 제공)
예측을 만들어 내는 것은 decision_function이나 predict_proba 출력의 임계값을 검증
decision-function =0 // predict_proba = 0.5
from mglearn.datasets import make_blobs
X, y = make_blobs(n_samples=(400, 50), centers=2, cluster_std=[7.0, 2],
random_state=22)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
svc = SVC(gamma=.05).fit(X_train, y_train)
mglearn.plots.plot_decision_threshold()
print(classification_report(y_test, svc.predict(X_test)))
# -> 클래스 1의 재현율을 높이는 게 중요하다고 가정해보자
-> 클래스 1로 잘못 분류된 FP(거짓 양성)이 늘어나더라도 TP를 늘리자는 뜻
임계값을 바꿔 클래스 1의 재현율을 높이도록 예측 조정
기본적으로 decision_function 값이 0보다 큰 포인트는 클래스 1로 분류되므로 클래스 1로 분류되려면 좀 더 임계값을 낮춰야 한다.
y_pred_lower_threshold = svc.decision_function(X_test) > -.8
print(classification_report(y_test, y_pred_lower_threshold))
'ML(머신러닝) > BASIC' 카테고리의 다른 글
차원 축소에 대한 10가지 팁(Ten quick tips for effective dimensionality reduction) (0) | 2019.08.11 |
---|---|
Binary Classification 중 주의해야 할 것과 팁 (0) | 2019.05.30 |
데이터 표현과 특성 공학 (0) | 2018.01.11 |
지도_비지도 요약 및 정리 (0) | 2018.01.09 |
[ Python ]비지도 군집, 병합군집, 덴드로그램, DBSCAN (2) | 2018.01.09 |