복잡도 파라미터 튜닝
복잡도 파라미터는 복잡도에 영향을 주는 파라미터로, 이 값에 따라 과적합 정도가 결정되므로 매우 신중하게 튜닝을 해야한다. 만약 너무 복잡하게 설정하면 과적합 가능성이 높아질 것이고 너무 단순하게 설정하면 과소적합 가능성이 높아질 것이다.


(Tip)
- 휴리스틱하게 학습되는 모든 모델(학습할때 마다 그 결과가 조금씩 다를 수 있는 모델)
- 정규화 회귀 모델에서 alpha값은 크면 클수록 패널티가 더 부과되기 때문에 모델이 단순해진다.
- 의사결정나무에서 max_depth를 크게 둘수록 나무가 더 깊어질수 있기 때문에 복잡해짐, min_samples_leaf는 잎노드(끝마디)로 판단하기 위한 최소 기준 샘플 수로 그 값이 크면 클수록 나무가 분지가 안되는 효과가 있기 때문에 복잡해지지 않는다.
- SVM에서 C는 오차 패널티 계수(오차를 어느정도 허용 할지, 즉 하드마진/소프트마진 결정),gamma는 시그모이드 커널, rbf 커널에 포함된 하이퍼 파라미터, degree는 polynomial 커널에 포함된 하이퍼 파라미터이다.
- 로지스틱에서 C는 패널티 계수이다.
- 신경망에서 hidden_layer_sizes 은닉층의 수를 조절하는 매개변수로 은닉층이 복잡해지면 노드가 많아진다는 소리이고 노드가 많아지면 연결된 엣지(선)가 많다는 소리이고 엣지가 많다는 것은 거기에 부여된 가중치가 많다는 소리이기 때문에 직접적으로 복잡도에 강한 영향을 준다.
- SVR에서 epsilon은 마진을 설정하기 위한 허용 오차 범위이다.
- Tree Ensemble(XGboost, LightGBM, RandomForest) 트리 계열 모델의 max_depth는 의사결정나무와 동일하고 여러 개의 모델을 쓰다 보니 max_depth를 보통 4정도로 낮게 잡는것이 일반적이다.
- 학습 시 우연성이 개입되는 모델(학습할때 마다 그 결과가 조금씩 다를 수 있는 모델)->회귀모델, 신경망
경사하강법 등의 방법으로 학습되는 모델(예: 회귀모델, 신경망)은 똑같은 데이터로 똑같은 모델을 학습할때 마다 다른 결과를 낼수 있다. 즉, 초기값에 의한 영향이 매우 크다.
따라서 복잡도 파라미터 변화에 따른 성능 변화의 패턴을 제대로 보기 위해서 seed를 고정한 뒤 튜닝을 하는것이 바람직하다. 단, seed는 어떤 seed가 좋은지 정확히 알 수 없기 때문에 seed를 고정하되 하이퍼 파라미터 그리드를 설계할 때 seed도 하나의 축으로 탐색해서 좋은 seed를 찾아내서 고정하는 것이 좋다.
- seed가 고정되어 있거나, 학습 시 우연성이 개입되지 않는 모델
위의 학습 시 우연성이 개입되는 모델보다 복잡도 파라미터에 따른 성능 변화 패턴 확인이 당연히 상대적으로 쉽다.
★★복잡도 파라미터를 튜닝 시 복잡도 파라미터가 둘 이상인 경우에는 서로 영향을 주기 때문에 반드시 두 파라미터를 같이 조정해야 하고 분석가가 처음부터 파라미터를 특정 범위를 설정하여 테스트를 할 경우 파라미터의 어느 범위가 좋은지 알수도 없고 불필요한 많은 범위를 테스트하기 때문에 시간의 문제와 효율적이지 못하다. 따라서 몇 가지 파라미터 값을 테스트한 후 범위를 설정하는 것이 바람직하다.
## 복잡도 파라미터 튜닝 실습 ##
import os
os.chdir(r"C:\Users\82102\Desktop\데이터 전처리\지도학습 주요모델 및 개념\데이터")
import numpy as np
import pandas as pd
df = pd.read_csv("Sonar_Mines_Rocks.csv")
df.info()
X = df.drop('Y', axis=1)
Y = df['Y']
# 학습 데이터와 평가 데이터 분리
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X, Y)
x_train.shape
# 샘플 156개, 특징 60개 -> 샘플에 비해 특징 개수가 많다
y_train.value_counts()
# 라벨 인코딩 진행
y_train.replace({"M":-1, "R":1}, inplace=True)
y_test.replace({"M":-1, "R":1}, inplace=True)
from sklearn.metrics import f1_score
from sklearn.model_selection import ParameterGrid
1. Logistic Regression(복잡도 파라미터 한개, 모델이 단순하고, 우연성이 어느정도 있는 모델)
from sklearn.linear_model import LogisticRegression as LR
# 복잡도 하이퍼 파라미터 튜닝
def LR_model_test(C):
model = LR(C=C, max_iter = 100000, random_state=10).fit(x_train, y_train) # 단순한(가벼운) 모델이므로 max_iter를 크게 잡음
y_pred = model.predict(x_test)
return f1_score(y_test, y_pred)
print("C = 0.1:\t{}".format(LR_model_test(C=0.1)))
print("C = 1:\t{}".format(LR_model_test(C=1)))
print("C = 5:\t{}".format(LR_model_test(C=5)))
# C=1일 때 가장 좋기 때문에 0.1이하, 5이상 일때는 굳이 탐색할 필요가 없다.
# 범위가 여전히 넓기 때문에 몇 가지 더 탐색

print("C = 0.5:\t{}".format(LR_model_test(C=0.5)))
print("C = 2:\t{}".format(LR_model_test(C=2)))
# C가 1일때 0.766이고 C가 2일때 0.74이니 C가 2보다 큰 것은 바람직하지 않다.
# 튜닝 범위: 0.5 < C < 1

# 파라미터 그리드 설정
LR_parameter_grid = ParameterGrid({"C":np.linspace(0.5, 1, 50),
"max_iter":[100000],
"random_state":[1004, 10, 1000]})
# 파라미터 튜닝 수행(분류문제:f1_score->최대값 찾기->best_score를 작은 값 설정)
best_score = -1
for parameter in LR_parameter_grid:
model = LR(**parameter).fit(x_train, y_train)
y_pred = model.predict(x_test)
score = f1_score(y_test, y_pred)
if score > best_score:
best_score = score
best_parameter = parameter
print(best_parameter, best_score)
# 결론: 로지스틱을 튜닝할때는 random_state, C를 같이 고려하고
# 로지스틱은 단순한 모델이므로 max_iter를 작게 잡을 필요가 없기 때문에 큰 값으로 설정

2. Decision Tree(복잡도 파라미터 두개, 모델이 단순하고, 우연성이 거의 없는 모델)
from sklearn.tree import DecisionTreeClassifier as DTC
# 복잡도 하이퍼 파라미터 튜닝
def DTC_model_test(max_depth, min_samples_leaf):
model = DTC(max_depth=max_depth, min_samples_leaf=min_samples_leaf).fit(x_train, y_train)
y_pred = model.predict(x_test)
return f1_score(y_test, y_pred)
for max_depth in [3,6,9]:
for min_samples_leaf in [1,2,3]:
score = DTC_model_test(max_depth=max_depth, min_samples_leaf=min_samples_leaf)
print("{}-{}:{}".format(max_depth, min_samples_leaf, score))
# "max_depth"가 3일 때 다른 수치에 비해 좋게 안나왔기 때문에 3을 제외하고 6부터 14까지 볼 것이고
# "min_samples_leaf"가 1일 때 다른 수치에 비해 좋게 안나왔기 때문에 2부터 4까지 볼 것이다.

# 파라미터 그리드 설정
DTC_parameter_grid = ParameterGrid({"max_depth":np.arange(6,15),
"min_samples_leaf":np.arange(2,5)})
# 파라미터 튜닝 수행(분류문제:f1_score->최대값 찾기->best_score를 작은 값 설정)
best_score = -1
for parameter in DTC_parameter_grid:
model = DTC(**parameter).fit(x_train, y_train)
y_pred = model.predict(x_test)
score = f1_score(y_test, y_pred)
if score > best_score:
best_score = score
best_parameter = parameter
print(best_parameter, best_score)

3. 신경망(복잡도 파라미터가 하나이면서, 모델이 복잡하고, 우연성이 있는 모델)
from sklearn.neural_network import MLPClassifier as MLP
# 복잡도 하이퍼 파라미터 튜닝
def MLP_model_test(hidden_layer_sizes):
model = MLP(hidden_layer_sizes=hidden_layer_sizes, random_state=12).fit(x_train, y_train) # max_iter는 default값으로 일부로 작게 잡음
y_pred = model.predict(x_test)
return f1_score(y_test, y_pred)
for hidden_layer_sizes in [(5, ), (10, ), (3, 3), (5, 5), (10, 10)]:
score = MLP_model_test(hidden_layer_sizes=hidden_layer_sizes)
print(hidden_layer_sizes, score)
# (5,): 첫 번째 은닉층이 5개 노드로 구성된 층의 구조
# (3,3): 첫 번째 은닉층이 3개 노드, 2번째 은닉층이 3개 노드로 구성된 층의 구조
# max_iter warning 발생
# (5, 5)에서는 f1-score가 0이 나옴 => 초기값 영향으로 보여짐 (근거: 더 단순한 모델과 복잡한 모델에서는 성능이 나왔으므로)
# (10, )와 (10, 10)에서 best_score가 나옴 => 더 복잡한 모델이 필요할지 판단이 필요

# 파라미터 그리드 설정
MLP_parameter_grid = ParameterGrid({"random_state":[41,102,15],
"hidden_layer_sizes":[(5, 5), (10, 10), (5, 5, 5), (10, 10, 10)],
"max_iter":[200, 2000, 20000]})
# 파라미터 튜닝 수행(분류문제:f1_score->최대값 찾기->best_score를 작은 값 설정)
best_score = -1
for parameter in MLP_parameter_grid:
model = MLP(**parameter).fit(x_train, y_train)
y_pred = model.predict(x_test)
score = f1_score(y_test, y_pred)
if score > best_score:
best_score = score
best_parameter = parameter
print(best_parameter, best_score)
# 결론: 신경망을 튜닝할때는 random_state, hidden_layer_sizes, max_iter를 같이 고려
# 결론: 신경망, SVR은 하이퍼파라미터를 튜닝했을 때 정말 좋은 성능을 보여주는 모델이다.

오늘은 복잡도에 영향을 주는 하이퍼 파라미터 튜닝하는 방법을 알아보았다.
복잡도 하이퍼 파라미터 튜닝 후에 복잡도와 관련된 최적의 하이퍼 파라미터를 대략적으로 구한 뒤 그 값으로 하이퍼 파라미터 그리드를 설정 한 후 최종적인 하이퍼 파라미터 튜닝을 수행해서 가장 좋은 score 값과 하이퍼 파라미터를 찾는다.
'데이터 전처리 > 지도학습 주요 모델 및 개념' 카테고리의 다른 글
지도학습 모델 및 파라미터 선택(데이터 크기)(맹신하면 안되고 참고만 하기) (0) | 2022.12.09 |
---|---|
지도학습 모델 및 파라미터 선택(그리드 서치) (0) | 2022.12.08 |
주요 모델의 구조 및 특성(2) (0) | 2022.12.08 |
주요 모델의 구조 및 특성(1) (0) | 2022.12.06 |
모델 개발 프로세스 (0) | 2022.12.05 |