[Python] Random Forest 최적화 방법

2023. 3. 13. 23:11

앞서 알아봤던 Random Forest 알고리즘의 최적화하는 방법에 대해 알아보자.
모델에 사용되는 하이퍼파라미터 별 성능을 시각화하여 최적화가 기대되는 값을 찾아내야 한다.
 
1. 모델 최적화 함수: 학습할 트리 모델 개수 선정
2. 모델 최적화 함수: 최대 깊이 선정
3. 모델 최적화 함수: 분리 노드의 최소 자료 수 선정
4. 모델 최적화 함수: 잎사귀 노드의 최소 자료 수 선정
 
위와 같이 4가지 하이퍼파라미터에 대해 순차적으로 시행하며 최적화한다.
사용할 데이터셋은 boston 집값예측 예제이며, RandomForestRegressor 로 평가하였다.

# 1. 트리 모델 개수 선정
def optimi_estimator(algorithm, algorithm_name, x_train, y_train, x_test, y_test, n_estimator_min, n_estimator_max):
    train_score = []; test_score =[]
    para_n_tree = [n_tree*5 for n_tree in range(n_estimator_min, n_estimator_max)]

    for v_n_estimators in para_n_tree:
        model = algorithm(n_estimators = v_n_estimators, random_state=1234)
        model.fit(x_train, y_train)
        train_score.append(model.score(x_train, y_train))
        test_score.append(model.score(x_test, y_test))

    # 트리 개수에 따른 모델 성능 저장
    df_score_n = pd.DataFrame({'n_estimators': para_n_tree, 'TrainScore': train_score, 'TestScore': test_score})
    # 트리 개수에 따른 모델 성능 추이 시각화 함수 호출
    optimi_visualization(algorithm_name, para_n_tree, train_score, test_score, "The number of estimator", "n_estimator")
    print(round(df_score_n, 4))
    
n_estimator_min = 1
n_estimator_max = 50
optimi_estimator(algorithm, algorithm_name, 
                 x_train, y_train, x_test, y_test, 
                 n_estimator_min, n_estimator_max)

트리 개수는 많을수록 과적합 방지에 유리하다. 학습 데이터 기반 모델 정확도와 테스트 데이터 기반 모델 정확도의 차이가 적은 값으로 선정하는 것이 좋으므로 트리 개수가 더 많아져도 성능에 차이가 없다는 점을 고려하여 100으로 선정한다.

# 2. 최대 깊이 선정
def optimi_maxdepth (algorithm, algorithm_name, x_train, y_train, x_test, y_test, depth_min, depth_max, n_estimator):
    train_score = []; test_score = []
    para_depth = [depth for depth in range(depth_min, depth_max)]

    for v_max_depth in para_depth:
        model = algorithm(max_depth = v_max_depth,
                          n_estimators = n_estimator,
                          random_state=1234)
        
        model.fit(x_train, y_train)
        train_score.append(model.score(x_train, y_train))
        test_score.append(model.score(x_test, y_test))

    # 최대 깊이에 따른 모델 성능 저장
    df_score_n = pd.DataFrame({'depth': para_depth, 'TrainScore': train_score, 'TestScore': test_score})
    # 최대 깊이에 따른 모델 성능 추이 시각화 함수 호출
    optimi_visualization(algorithm_name, para_depth, train_score, test_score, "The number of depth", "n_depth")
    print(round(df_score_n, 4))
    
depth_min = 1
depth_max = 21
optimi_maxdepth(algorithm, algorithm_name, 
                x_train, y_train, x_test, y_test, 
                depth_min, depth_max, n_estimator)

최대 깊이는 적을수록 과적합 방지에 유리하고, 학습데이터와 test 데이터의 결과가 적은 값으로 선정한다.
나는 3로 선정하였다.

# 3. 분리 노드의 최소 자료 수 선정
def optimi_minsplit (algorithm, algorithm_name, x_train, y_train, x_test, y_test, n_split_min, n_split_max, n_estimator, n_depth):
    train_score = []; test_score = []
    para_split = [n_split*2 for n_split in range(n_split_min, n_split_max)]
    for v_min_samples_split in para_split:
        model = algorithm(min_samples_split = v_min_samples_split,
                          n_estimators = n_estimator,
                          max_depth = n_depth,
                          random_state = 1234)
        model.fit(x_train, y_train)
        train_score.append(model.score(x_train, y_train))
        test_score.append(model.score(x_test, y_test))

    # 분리 노드의 최소 자료 수에 따른 모델 성능 저장
    df_score_n = pd.DataFrame({'min_samples_split': para_split, 'TrainScore': train_score, 'TestScore': test_score})
    # 분리 노드의 최소 자료 수에 따른 모델 성능 추이 시각화 함수 호출
    optimi_visualization(algorithm_name, para_split, train_score, test_score, "The minimum number of samples required to split an internal node", "min_samples_split")
    print(round(df_score_n, 4))
    
n_split_min = 1
n_split_max = 101

optimi_minsplit (algorithm, algorithm_name,
                 x_train, y_train, x_test, y_test,
                 n_split_min, n_split_max, n_estimator, n_depth)

split 노드의 최소 자료 수는 많을수록 과적합 방지에 유리하다. 노드가 많으면서 학습데이터와 test 데이터 간의 결과 차이가 적은 값으로 선정한다.

# 4. 잎사귀 노드의 최소 자료 수 선정
def optimi_minleaf(algorithm, algorithm_name, x_train, y_train, x_test, y_test, n_leaf_min, n_leaf_max, n_estimator, n_depth, n_split):
    train_score = []; test_score = []
    para_leaf = [n_leaf*2 for n_leaf in range(n_leaf_min, n_leaf_max)]

    for v_min_samples_leaf in para_leaf:
        model = algorithm(min_samples_leaf = v_min_samples_leaf,
                            n_estimators = n_estimator,
                            max_depth = n_depth,
                            min_samples_split = n_split,
                            random_state=1234)
        model.fit(x_train, y_train)
        train_score.append(model.score(x_train, y_train))
        test_score.append(model.score(x_test, y_test))
        
n_leaf_min = 1
n_leaf_max = 51
optimi_minleaf(algorithm, algorithm_name, 
               x_train, y_train, x_test, y_test, 
               n_leaf_min, n_leaf_max, n_estimator, n_depth, n_split) 

잎사귀 노드의 최소 자료 수는 많을수록 과적합 방지에 유리하다. 잎사귀 노드가 많으면서 학습데이터와 test 데이터 간의 결과가 적은 값으로 선정한다.
 
 - 결과적으로 regression 의 경우에는min_samples_split 와 min_samples_leaf 는 높은값을 취할수록 Classifier 와 같은 거동을 보이고, 정확도가 떨어지는 것을 알 수 있었다.
따라서 기본 default 값을 쓴 결과보다 부정확한 모델이 형성되었다.
위와 같은 방법이 있는 것만 참고하고 비교하면서 사용토록 하자.
 
 
참고자료 : [Python] Random Forest 알고리즘 정의, 장단점, 최적화 방법 (tistory.com)

BELATED ARTICLES

more