AI·빅데이터 융합 경영학 Study Note

[ML수업] 5주차 실습2: model tuning(hyperparameter optimization), grid search CV, randim search CV, Baysian optimization with optuna 본문

AI·ML

[ML수업] 5주차 실습2: model tuning(hyperparameter optimization), grid search CV, randim search CV, Baysian optimization with optuna

SubjectOwner 2023. 11. 21. 15:50
from sklearn.datasets import load_digits

digits = load_digits()

#import optuna

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(digits.data, digits.target, random_state=0)

from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC

model = KNeighborsClassifier()
#model = DecisionTreeClassifier()
#model = LogisticRegression()
#model = SVC()

 

1. Grid Search CV

# Set the parameters for grid search
# param_grid: dictionary with parameters names as keys and
# lists of parameter settings to try as values

param_grid = {'n_neighbors': range(4,10),
              'weights': ['uniform','distance']}
#param_grid 
# {'n_neighbors': range(4, 10), 'weights': ['uniform', 'distance']}


from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(model, param_grid, scoring='accuracy', cv=5, n_jobs=-1)
grid_search.fit(X_train, y_train)

 

 

1. param_grid = {'n_neighbors': range(4,10),

              'weights': ['uniform','distance']}

 

 'n_neighbors': range(4,10): 이 부분은 K-최근접 이웃(K-Nearest Neighbors) 모델의 n_neighbors 하이퍼파라미터를 조정하기 위한 설정입니다. range(4, 10)은 4부터 9까지의 정수값을 시도하여 최적의 이웃 수를 찾도록 그리드 탐색을 수행합니다.

 

'weights': ['uniform','distance']: 이 부분은 또 다른 하이퍼파라미터인 weights의 후보값을 설정합니다. weights K-최근접 이웃을 할 때 사용되며, 두 가지 옵션인 'uniform' 'distance'를 포함하고 있습니다. 'uniform'는 균일한 가중치를 사용하고, 'distance'는 거리에 역수를 적용한 가중치를 사용하는 것을 의미합니다.

 

2.

grid_search = GridSearchCV(model, param_grid, scoring='accuracy', cv=5, n_jobs=-1)
 

scoring='accuracy': 모델의 성능을 평가하는 데 사용할 평가 지표를 지정합니다. 이 경우, 'accuracy'는 정확도를 의미하며, 모델의 분류 성능을 측정하는 지표로 사용됩니다.

cv=5: 교차 검증(Cross-Validation)을 수행할 때 분할할 폴드(fold)의 수를 지정합니다. 이 경우, 5-겹 교차 검증을 사용하여 모델을 평가합니다.

n_jobs=-1: 그리드 탐색 작업을 병렬로 처리할 때 사용할 CPU 코어의 수를 지정합니다. -1은 가능한 모든 CPU 코어를 사용하도록 설정하는 것을 의미합니다.

 

그러니까 내가 임의로 바꿀 수 있는 변수는 cv 뿐.

 

 

Evaluate the model with best parameters

grid_search.score(X_test, y_test), KNeighborsClassifier().fit(X_train, y_train).score(X_test, y_test)
#(0.9866666666666667, 0.98)

 

grid_search.score(X_test, y_test): 이 부분은 그리드 탐색(GridSearchCV)을 통해 찾은 모델의 성능을 평가합니다. grid_search는 그리드 탐색 객체로, 이미 훈련된 모델의 성능을 평가할 수 있는 상태입니다. X_test는 테스트 데이터의 입력 특성, y_test는 테스트 데이터의 실제 출력(타겟)을 나타냅니다. 따라서 이 부분은 그리드 탐색을 통해 선택된 모델의 테스트 데이터에 대한 성능을 나타냅니다.

KNeighborsClassifier().fit(X_train, y_train).score(X_test, y_test): 이 부분은 K-최근접 이웃(K-Nearest Neighbors) 분류 모델을 훈련하고 해당 모델을 테스트 데이터에 대해 평가합니다. KNeighborsClassifier()는 K-최근접 이웃 모델을 생성하고, fit(X_train, y_train)은 모델을 훈련 데이터에 맞춥니다. 그 다음 .score(X_test, y_test)는 테스트 데이터에 대한 정확도(accuracy)를 계산하여 모델의 성능을 평가합니다.

이 두 가지 방법을 사용하여 모델의 성능을 각각 측정하고 비교할 수 있습니다. 각 방법은 모델을 평가하는 방식이 다르며, 그리드 탐색을 통해 선택된 모델과 K-최근접 이웃 모델을 비교하여 어떤 모델이 더 나은 성능을 보이는지 확인할 수 있습니다. (높을수록 좋은거임.)

 

print("Best parameters: {}".format(grid_search.best_params_))
print("Best CV score: {:.2f}".format(grid_search.best_score_))

#Best parameters: {'n_neighbors': 4, 'weights': 'distance'}
#Best CV score: 0.99

 

이 코드는 그리드 탐색(Grid Search)을 통해 찾은 최적 하이퍼파라미터와 그에 대한 교차 검증(Cross-Validation) 점수를 출력하는 부분입니다.
"Best parameters: {}".format(grid_search.best_params_): 이 부분은 최적의 하이퍼파라미터 조합을 출력합니다. grid_search.best_params_는 그리드 탐색을 통해 찾은 최적의 하이퍼파라미터 조합이 들어 있는 딕셔너리를 나타냅니다. 이 부분은 최적의 하이퍼파라미터 조합을 출력합니다.

"Best CV score: {:.2f}".format(grid_search.best_score_): 이 부분은 교차 검증(Cross-Validation)을 통해 얻은 최적 모델의 평균 성능 점수를 출력합니다. grid_search.best_score_는 최적 모델의 교차 검증 점수를 나타냅니다. :.2f는 소수점 두 자리까지 출력하도록 지정한 것으로, 모델의 성능을 소수점 두 자리까지 표시합니다

print("Best estimator:\n{}".format(grid_search.best_estimator_))
#Best estimator: KNeighborsClassifier(n_neighbors=4, weights='distance')

 

그리드 탐색을 통해 선택된 최적의 모델 객체를 나타냅니다. 이 부분은 최적 모델의 세부 정보와 설정을 출력합니다..

 

 

2. Random Search CV

 

#Set the parameters for random search
param_grid = {'n_neighbors': range(1, 10),
              'weights': ['uniform','distance']}
#param_grid
# {'n_neighbors': range(1, 10), 'weights': ['uniform', 'distance']}

from sklearn.model_selection import RandomizedSearchCV

rand_search = RandomizedSearchCV(model, param_distributions=param_grid, 
                                 scoring='accuracy', n_iter=12, random_state=100)
                                 
rand_search.fit(X_train, y_train)

 

Evaluate the model with best parameters
 
Evaluate the model with best parameters
#0.9888888888888889

 

print("Best estimator:\n{}".format(rand_search.best_estimator_))
# Best estimator: KNeighborsClassifier(n_neighbors=3, weights='distance')

 

print("Best parameters: {}".format(rand_search.best_params_))
# Best parameters: {'weights': 'distance', 'n_neighbors': 3}

 

 

3. Bayesian Optimization with Optuna (이해 못함) (어쨌든 가장 성능이 좋은 거임)
- Grid Search와 Random Search는 이전까지의 조사 과정에서 얻어진 hyperparameter 값들의 성능 결과에 대한 '사전 지식'이 전혀 반영되어 있지 않기 때문에 비효율적인 요소가 있음.
- 매 회 새로운 hyperparameter 값에 대한 조사를 수행할 시 '사전 지식'을 충분히 반영하면서, 동시에 전체적인 탐색 과정을 체계적으로 수행할 수 있는 방법이 Bayesian Optimization임.

 

 

import optuna

def objective(trial):
    x = trial.suggest_uniform('x', -10, 10)
    return (x - 2) ** 2

study = optuna.create_study()
study.optimize(objective, n_trials=20)

study.best_params
# {'x': 2.129183214440917}

 

##### Procedure for optimizing sklearn parameters #####
1. Wrap model training with an objective function and return accuracy
2. Suggest hyperparameters using a trial object
3. Create a study object and execute the optimization
 
from sklearn.model_selection import cross_val_score

# 조절할 하이퍼 파라미터와 그 범위를 지정하는 함수 정의
def objective(trial): 
    # optuna.trial.Trial.suggest_categorical() for categorical parameters
    # optuna.trial.Trial.suggest_int() for integer parameters
    # optuna.trial.Trial.suggest_float() for floating point parameters    
    knn_n_neighbors = trial.suggest_int('n_neighbors', 1, 10, step=1)
    knn_weights = trial.suggest_categorical('weights', ['uniform','distance'])

    classifier_obj = KNeighborsClassifier(
        n_neighbors = knn_n_neighbors, 
        weights = knn_weights,    
    )

    score = cross_val_score(classifier_obj, X_train, y_train, cv=5, n_jobs=-1)
    accuracy = score.mean()
    return accuracy

# 최적화 실행
study = optuna.create_study(sampler=optuna.samplers.TPESampler(seed=100), direction="maximize")
study.optimize(objective, n_trials=12) 

#최적화 결과 보기
print("Best score:", study.best_value)
print("Best parameters:", study.best_params)

#Best score: 0.985892881729313
#Best parameters: {'n_neighbors': 3, 'weights': 'uniform'}
model = KNeighborsClassifier(**study.best_params)
model.fit(X_train, y_train)
model.score(X_test, y_test)
#0.9866666666666667

 

# 최적화 과정 시각화
optuna.visualization.plot_optimization_history(study)