본문 바로가기
네이버클라우드/AI

AI 8일차 (2023-05-17) 인공지능 기초 _머신러닝 - 데이터 전처리_Optuna 과 QuantileTransformer

by prometedor 2023. 5. 18.

Optuna

하이퍼파라미터 최적화를 위한 오픈 소스 파이썬 라이브러리

ㄴ 머신러닝 모델의 성능을 향상시키기 위해 최적의 하이퍼파라미터 조합을 자동으로 탐색할 수 있음

ㄴ Optuna는 범위와 탐색 방법을 지정하여 하이퍼파라미터 공간을 정의함

ㄴ 그런 다음, 목표 함수(최적화하려는 모델의 성능 지표)를 정의하고, Optuna는 목표 함수를 평가하면서 하이퍼파라미터 공간을 탐색함

ㄴ 베이지안 최적화 알고리즘을 기반으로 하여 확률적으로 좋은 하이퍼파라미터 조합을 찾아냄

ㄴ 많은 머신러닝 프레임워크와 통합이 가능하며, 사용자가 원하는 목표 함수를 지정하고, 파라미터 공간을 설정한 뒤, 최적의 하이퍼파라미터 조합을 탐색함

ㄴ 실험 기록을 저장하고 시각화하는 기능도 제공하여 실험 결과를 관리할 수 있음

ㄴ 사용이 간편하고 다양한 최적화 알고리즘을 지원하며, 분산 컴퓨팅과 함께 사용할 수 있는 기능도 제공함

-->  모델의 성능을 향상시키기 위해 하이퍼파라미터 최적화를 자동화하고 싶을 때 Optuna를 사용

 

import optuna
from optuna import Trial, visualization
from optuna.samplers import TPESampler
from sklearn.metrics import mean_absolute_error

'''
optuna.trial.Trial.suggest_categorical() : 리스트 범위 내에서 값을 선택한다.
optuna.trial.Trial.suggest_int() : 범위 내에서 정수형 값을 선택한다.
optuna.trial.Trial.suggest_float() : 범위 내에서 소수형 값을 선택한다.
optuna.trial.Trial.suggest_uniform() : 범위 내에서 균일분포 값을 선택한다.
optuna.trial.Trial.suggest_discrete_uniform() : 범위 내에서 이산 균일분포 값을 선택한다.
optuna.trial.Trial.suggest_loguniform() : 범위 내에서 로그 함수 값을 선택한다.
'''

def objectiveCAT(trial: Trial, x_train, y_train, x_test):
    param = {
        'n_estimators' : trial.suggest_int('n_estimators', 500, 4000),
        'depth' : trial.suggest_int('depth', 8, 16),
        'fold_permutation_block' : trial.suggest_int('fold_permutation_block', 1, 256),
        'learning_rate' : trial.suggest_float('learning_rate', 0, 1),
        'od_pval' : trial.suggest_float('od_pval', 0, 1),
        'l2_leaf_reg' : trial.suggest_float('l2_leaf_reg', 0, 4),
        'random_state' :trial.suggest_int('random_state', 1, 2000)
    }
    
# 학습 모델 생성
model = CatBoostClassifier(**param)
CAT_model = model.fit(x_train, y_train, verbose=True) # 학습 진행

# 모델 성능 확인
score = accuracy_score(CAT_model.predict(x_test), y_test)
return score

# MAE가 최소가 되는 방향으로 학습을 진행
# TPESampler : Sampler using TPE (Tree-structured Parzen Estimator) algorithm.
study = optuna.create_study(direction='maximize', sampler=TPESampler())

# n_trials 지정해주지 않으면, 무한 반복

study.optimize(lambda trial : objectiveCAT(trial, x, y, x_test), n_trials = 5)
print('Best trial : score {}, \nparams {}'.format(study.best_trial.value, study.best_trial.params))

# 하이퍼파라미터별 중요도를 확인할 수 있는 그래프
print(optuna.visualization.plot_param_importances(study))

# 하이퍼파라미터 최적화 과정을 확인
optuna.visualization.plot_optimization_history(study)
plt.show()

 

 

실습


ml23_optuna_california.py

import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split, KFold
from sklearn.model_selection import cross_val_score, cross_val_predict
from sklearn.datasets import fetch_california_housing
from sklearn.preprocessing import MinMaxScaler

import tensorflow as tf
tf.random.set_seed(77) # weight 난수값 조정

#1. 데이터
datasets = fetch_california_housing()
x = datasets['data']
y = datasets.target

x_train, x_test, y_train, y_test = train_test_split(
    x, y, train_size=0.8, shuffle=True, random_state=42
)

# kfold
n_splits = 5
random_state = 42
kfold = KFold(n_splits=n_splits, shuffle=True, 
              random_state=random_state)    # KFold : 회귀모델 / StratifiedKFold : 분류모델

# Scaler 적용
scaler = MinMaxScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

import optuna
from optuna import Trial, visualization
from optuna.samplers import TPESampler
from sklearn.metrics import mean_absolute_error
from catboost import CatBoostRegressor
import matplotlib.pyplot as plt

def objectiveCAT(trial: Trial, x_train, y_train, x_test):
    param = {
        'n_estimators' : trial.suggest_int('n_estimators', 500, 4000),
        'depth' : trial.suggest_int('depth', 8, 16),
        'fold_permutation_block' : trial.suggest_int('fold_permutation_block', 1, 256),
        'learning_rate' : trial.suggest_float('learning_rate', 0, 1),
        'od_pval' : trial.suggest_float('od_pval', 0, 1),
        'l2_leaf_reg' : trial.suggest_float('l2_leaf_reg', 0, 4),
        'random_state' :trial.suggest_int('random_state', 1, 2000)
    }
    # 학습 모델 생성
    model = CatBoostRegressor(**param)
    CAT_model = model.fit(x_train, y_train, verbose=True) # 학습 진행
    # 모델 성능 확인
    score = r2_score(CAT_model.predict(x_test), y_test)
    return score

# MAE가 최소가 되는 방향으로 학습을 진행
# TPESampler : Sampler using TPE (Tree-structured Parzen Estimator) algorithm.
study = optuna.create_study(direction='maximize', sampler=TPESampler())

# n_trials 지정해주지 않으면, 무한 반복
study.optimize(lambda trial : objectiveCAT(trial, x, y, x_test), n_trials = 5)
print('Best trial : score {}, /nparams {}'.format(study.best_trial.value, 
                                                  study.best_trial.params))

# 하이퍼파라미터별 중요도를 확인할 수 있는 그래프
print(optuna.visualization.plot_param_importances(study))

# 하이퍼파라미터 최적화 과정을 확인
optuna.visualization.plot_optimization_history(study)
plt.show()

 

 

 

 

QuantileTransformer

데이터의 분포를 변환하여 정규분포에 가깝게 만드는 전처리 방법

ㄴ 데이터의 특성을 변형하지만, 이상치에 민감하지 않고 로버스트한 성능을 보장할 수 있음

ㄴ 기본적으로 각 특성의 분포를 균등하게 만듦

ㄴ 이를 위해 입력 데이터의 특성값을 정렬한 후, 각 값의 누적 분포 함수의 값을 사용하여 원래 값을 변환

ㄴ 이러한 변환을 통해 데이터의 분포가 주어진 분위수에 해당하는 값으로 매핑됨

ㄴ 데이터를 변환하는 데 사용되는 두 가지 방법을 제공
     ㄴ Uniform 변환

          ㄴ 입력 데이터의 분포를 균등하게 만듦

          ㄴ 이상치에 대해 민감하지 않지만, 데이터의 분포가 부분적으로 변환될 수 있음
     ㄴ Normal 변환

          ㄴ 입력 데이터의 분포를 정규분포에 가깝게 만듦

          ㄴ 데이터의 분포를 보다 정확하게 보존하며, 이상치에 대해서도 로버스트한 성능을 보여줌

 

실습

 

ml24_QuantileTransformer_iris.py

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler, MaxAbsScaler, RobustScaler
from sklearn.preprocessing import QuantileTransformer, PowerTransformer
from sklearn.metrics import accuracy_score
from sklearn.ensemble import RandomForestClassifier

import warnings
warnings.filterwarnings('ignore')
import time


#1. 데이터
datasets = load_iris()
x, y = datasets.data, datasets.target
print(x.shape, y.shape)     # (150, 4) (150,)


x_train, x_test, y_train, y_test = train_test_split(
    x, y, shuffle=True, random_state=72, train_size=0.8
)

# 스케일링
sts = StandardScaler() 
mms = MinMaxScaler()
mas = MaxAbsScaler()
rbs = RobustScaler()
qtf = QuantileTransformer()                     # QuantileTransformer 는 지정된 분위수에 맞게 데이터를 변환함. 
                                                # 기본 분위수는 1,000개이며, n_quantiles 매개변수에서 변경할 수 있음
ptf1 = PowerTransformer(method='yeo-johnson')   # 'yeo-johnson', 양수 및 음수 값으로 작동
ptf2 = PowerTransformer(method='box-cox')       # 'box-cox', 양수 값에서만 작동

scalers = [sts, mms, mas, rbs, qtf, ptf1, ptf2]
for scaler in scalers:	# 각 스케일러를 순환하면서 데이터를 변환하고, 랜덤 포레스트 분류기를 훈련
    x_train = scaler.fit_transform(x_train)
    x_test = scaler.transform(x_test)
    model = RandomForestClassifier()
    model.fit(x_train, y_train)
    y_predict = model.predict(x_test)
    result = accuracy_score(y_test, y_predict)
    scale_name = scaler.__class__.__name__
    print('{0} 결과 : {1:.4f}'.format(scale_name, result), )
    # 여러 스케일링 방법 (StandardScaler, MinMaxScaler, MaxAbsScaler, RobustScaler, 
    # QuantileTransformer, PowerTransformer)을 훈련 및 테스트 데이터에 적용
    # RandomForestClassifier 모델을 스케일된 훈련 데이터로 훈련하고, 
    # 스케일된 테스트 데이터에 대한 예측을 수행
    

#=================================== 결과 =====================================#
# StandardScaler 결과 : 1.0000
# MinMaxScaler 결과 : 1.0000
# MaxAbsScaler 결과 : 1.0000
# RobustScaler 결과 : 1.0000
# QuantileTransformer 결과 : 1.0000
# PowerTransformer 결과 : 1.0000
# ValueError: The Box-Cox transformation can only be applied to strictly positive data
#==============================================================================#

ㄴ 모든 스케일러에 대해 정확도가 1.0000 (또는 100%)로 나타나는 것을 볼 수 있음

--> 모든 스케일링 방법이 Iris 데이터셋에 대해 높은 성능을 제공하는 것을 의미