포스트의 모든 내용은 XGBoost와 사이킷런으로 배우는 그레이디언트 부스팅를 참고하였습니다.
Decision Tree에서 최적의 hypyer parameter를 찾는데 GridSearchCV를 사용해보았다.
코드를 보면서 이해해보자.
model이 Decision Tree라고 가정해보자.
from sklearn.model_selection improt GridSearchCV # import from sklearn.tree import DecisionTreeRegressor reg = DecisionTreeRegressor(random_state =2) params= {'max_depth',:[None,2,3,4,6,8,10,20]} grid_reg = GridSearchCV(reg,params, scoring ='neg_mean_squared_error', cv=5, return_train_score =True,n_jobs=-1) grid_reg.fit(X_train,y_train)
- grid_search로 찾은 모델이 grid_reg에 저장되었고, 그것으로 train을 한 모습이다.
(test할 때는 grid_reg.predict(X_test)를 하면 된다.)
prams: max_depth는 tree의 최고 깊이를 설정해준다. None는 한계가 없는것
GridSearchCV는 분석이 조금 필요하다. 자주 쓰는 매개변수만 정리를 해보자.GridSearchCV
GridSearchCV(estimator, param_grid, *, scoring=None, n_jobs=None, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score=nan, return_train_score=False)
- estimator : GridSearch를 할 model 여기선 DecisionTree를 사용
- param_grid : parameter를 정해준다.
- scoring : 어떤 방식으로 점수를 낼 것인가? 보통 neg_root_mean_squared_error혹은 neg_mean_squared_error를 사용
- n_jobs : 작업에 할당할 cpu의 갯수를 정한다. -1은 자동으로 모든 cpu를 잡아줌
- refit : 기본 값은 True로 crossvalidation을 한 다음 모든 train_set을 사용하여 재 학습 시킨것, 최적의 모델이 best_estimator에 저장이 되어있다.
- cv : train_set을 얼마나 분할할 것인가를 결정 (k-fold cross_validation에서의 k) >>
# grid_search 함수를 만듭니다. def grid_search(params, reg=DecisionTreeRegressor(random_state=2)): # GridSearchCV 객체를 만듭니다. grid_reg = GridSearchCV(reg, params, scoring='neg_mean_squared_error', cv=5, n_jobs=-1) #n_jobs: cpu를 몇개를 할당할 것인가를 결정, -1은 자동으로 해줌 #GridSearchCv는 cross validation을 실행해서 best_estimator에 저장합니다. 이는 grid_reg에도 저장됨 따라서 grid_reg.predict(X_test)를 하면 자동으로 제일 좋은 predict를 뱉어준다. # X_train와 y_train에서 그리드 서치를 수행합니다. grid_reg.fit(X_train, y_train) best_params = grid_reg.best_params_ # 최상의 매개변수를 추출 print("최상의 매개변수:", best_params) # 최상의 매개변수를 출력 best_score = np.sqrt(-grid_reg.best_score_) # 최상의 점수를 계산 print("훈련 점수: {:.3f}".format(best_score)) # 최상의 점수를 출력 y_pred = grid_reg.predict(X_test) # 테스트 세트에 대한 예측 rmse_test = mean_squared_error(y_test, y_pred)**0.5 # 평균 제곱근 오차를 계산 print('테스트 점수: {:.3f}'.format(rmse_test)) # 테스트 세트 점수를 출력
DecisionTreeRegressor에서 자주 사용하는 매개변수는 다음과 같다.
max_depth: 트리의 깊이를 정의 기본 값은 None, 값이 작을 수록 capacity가 낮아짐min_samples_leaf: 리프 노드가 가질 수 있는 최소 샘플의 개수를 제한 기본 값은 1, ex) min_samples_leaf = 8이면 한 leaf_node가 최소 8개의 samples을 가지고 있어야함. 즉, min_samples_leaf가 높을수록 regularazation이 일어남.max_leaf_nodes: min_samples_leaf와 비슷 , leaf_node의 최대 갯수를 지정 기본값은 Nonemax_feature: 분산을 줄이는데 효율적(overfitting) 모든 특성을 고려하지 않고 지정된 개수의 특성중 선택- min_samples_split: 분할하기 위해 필요한 최소 샘플 개수 제한 기본값은 2 ex) 5이면 5개보다 작은 노드는 분할되지 않음
- splitter: 나누는 기준/ random, best를 선택 , 보통 random추천
- min_weight_fraction_leaf: 리프 노드가 되기 위한 전체 가중치의 최소 비율 기본값은 0.0으로 가중치를 0.02 이런식으로 조절하면 전체 샘플중의 가중치만큼 ex) 1000샘플일때, 가중치가 0.02라고 함은 leaf_node가 20개의 샘플을 가져야함 (overfitting에 효과적)
- criterion: 두가지로 나뉜다.
+ regressor: 'squared_error','friedman_mse'(프리드만),'absoulte_error '(절대값),'poisson'(포아송)
+ classification: 'gini' , 'entropy'
GridsearchCV는 모든 parameter중에서 (params로 제한을 걸기도 하지만) 최적의 값을 찾는 함수이다. 이는 오랜 시간을 요구하기 때문에 실제 task에서는 적절한 작업이 아니다. 책에서는 RandomizedSearchCv를 소개한다.
GridSearchCV와 동일하게 동작하지만, 모든 파라메터를 검사하는 것이 아니라 랜덤한 조합으로 search를 진행한다. 밑의 예제를 보면서 분석해보자.
from sklearn.model_selection import RandomizedSearchCV def randomized_search_clf(params, epoch=20, clf=DecisionTreeClassifier(random_state=2)): # RandomizedSearchCV 객체를 만듭니다. rand_clf = RandomizedSearchCV(clf, params, n_iter=epoch, cv=5, n_jobs=-1, random_state=2) rand_clf.fit(X_train, y_train) #생성된 객체로 randomsearch를 수행 best_model = rand_clf.best_estimator_ # 최상의 모델을 추출 best_score = rand_clf.best_score_ # 최상의 점수를 추출 print("훈련 점수: {:.3f}".format(best_score)) # 최상의 점수를 출력 y_pred = best_model.predict(X_test) # 테스트 세트에 대한 예측 accuracy = accuracy_score(y_test, y_pred)# 정확도를 계산합니다. print('테스트 점수: {:.3f}'.format(accuracy)) # 정확도를 출력합니다. return best_model함수를 보면 prams가 있는데 params는 다음과 같이 작성하면 된다. (범위를 지정해줌으로서, tuning이 가능한 randomsearch가 된다.)
params={ 'criterion':['entropy', 'gini'], 'splitter':['random', 'best'], 'min_samples_split':[2, 3, 4, 5, 6, 8, 10], 'min_samples_leaf':[1, 0.01, 0.02, 0.03, 0.04], 'min_impurity_decrease':[0.0, 0.0005, 0.005, 0.05, 0.10, 0.15, 0.2], 'max_leaf_nodes':[10, 15, 20, 25, 30, 35, 40, 45, 50, None], 'max_features':['sqrt', 0.95, 0.90, 0.85, 0.80, 0.75, 0.70], 'max_depth':[None, 2,4,6,8], 'min_weight_fraction_leaf':[0.0, 0.0025, 0.005, 0.0075, 0.01, 0.05] } randomized_search_clf(params,20,clf= DecisionTreeClassifier(random_state=2)
prams는 위의 처럼 정의할 수도 있지만, 분포를 사용하여 정의하면 훨씬 효율적임을 직감할 수 있다. 책에서는 다음과 같은 함수를 소개하며 DecisionTree를 마친다.
from sklearn.utils.fixes import loguniform from scipy.stats import randint #잘 보면 정수가 필요한 매개 변수에는 randint를 사용하는 것을 볼 수 있다. params = {'max_depth': randint(1,100), 'max_leaf_nodes': randint(1,100), 'max_features': loguniform(1e-5,1), # 로그 uniform distribution 'min_samples_split': loguniform(1e-5,1), 'min_samples_leaf': loguniform(1e-5,1), 'min_impurity_decrease': loguniform(1e-5,1), 'min_weight_fraction_leaf': loguniform(1e-5,1)} # dtc = DecisionTreeClassifier(random_state=0) rs = RandomizedSearchCV(dtc, params, n_iter=100, n_jobs=-1, random_state=0) rs.fit(X_train, y_train) print('최상의 교차 검증 점수:', rs.best_score_) print('최상의 매개변수:', rs.best_params_)