ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [0401 복습] 머신러닝 마무리_로지스틱 회귀분석, K-Fold Cross Validation(k-분할 교차 검증), 성능 예측, 하이퍼파라미터 튜닝, Random Search, Grid Search
    KT 에이블스쿨 복습 2024. 4. 1. 17:58

     

    결정트리 실습 리뷰

    - 모델링에서 학습용, 평가용 데이터 분리 시 검증용 데이터까지 필요하다면 x_val, y_val 로 변수명 설정!

    - max_depth의 기본값 = None

    - 결정트리에서 변수 중요도를 표시: 트리 구조에서 특정 변수가 줄여준 총 불순도의 양이 많은 순서 (전체에서 차지한 비율)

    **max_depth를 주면 변수 중요도가 달라짐! Why? 트리의 깊이(단계)가 줄어들기 때문에 당연히 변수 중요도가 달라짐

     

     

    CH4. Logistic Regression(로지스틱 회귀분석)

    확률문제를 선형회귀로 모델링, 로지스틱 회귀

    • 공부 시간에 따라 합격 (1) 불합격 (0)으로 나눔!
    • 범주값도 숫자이기 때문에 선형 회귀모델을 만들 수는 있음!
    • 그러나 아래의 그래프는 0,1 제외 다른값도 존재! 결과는 0보다 작은값이나 1보다 큰 값은 없기 때문에 문제가 발생함!

    → 이를 개선하기 위해 0.5보다 크면 1, 0.5보다 작으면 0으로 판단하는 식으로 분류 문제에 활용할 수 있다고 판단!

    → 임계값(0.5)을 조절하면서 분류 문제 판단을 적극적 or 소극적으로 구분할 수 있음

          **0.45로 임계값을 설정 시 더 적극적으로 1로 판단!

     

     

    로지스틱 함수

    • 시그모이드(sigmoid) 함수라고도 부름
    • 확률 값 p는 선형 판별식값이 커지면 1, 작아지면 0에 가까워짐!
    • (-∞, ∞) 범위를 갖는 선형 판별식 결과로 (0, 1) 범위의 확률 값을 얻음!
      • (0, 1) : 소괄호로 범위 표현하면 0, 1은 포함되지 않는 범위
      • [0, 1] : 대괄호로 범위 표현하면 0, 1도 포함된 범위
    • 기본적으로 확률 값 0.5를 임계값으로 가지고 있음! (임계값 바꾸려면 수동으로 만들어야 함!)

    모델링

    from sklearn.linear_model import LogisticRegression
    from sklearn.metrics import confusion_matrix, classification_report   # 성능평가 주의
    model = LogisticRegression()
    model.fit(x_train, y_train)
    y_pred = model.predict(x_test)
    print(confusion_matrix(y_test, y_pred))
    print(classification_report(y_test, y_pred))

     

     

    임계값 조정

    # 예측값 확인
    y_pred[10:20]

     

    # 예측 확률: x_test가 0이될 확률, 1이될 확률을 보여줘!
    # 오른쪽이 0.5보다 크면 1로 예측
    p = model.predict_proba(x_test)
    p[10:20]

     

    # 임계값을 0.45로 생각해서 수동 분류
    p1 = p[:, [1]]
    
    # 1로 분류될 확률값 확인 (오른쪽 열만 가져오기)
    p1[10:20]
    
    # 임계값: 0.5, 반복문 확장 # 여기서 나온 결과값은 y_pred 값과 같음
    y_pred2 = [1 if x > 0.5 else 0 for x in p1] # 0.5보다 크면 1, 아니면 0
    y_pred2[10:20]
    
    # 성능 평가
    print(classification_report(y_test, y_pred2))

     

    - 임계값을 0.45로 설정하면서 적극적으로 분류하면 precision을 떨어뜨리더라도 recall을 올릴 수 있음!

    - 변수가 많을 때 복잡해짐 !! multi class 도 분류 가능!

    - 회귀식을 세 개를 만들기! (A, B, C), 각각의 확률 값을 얻어서 가장 큰 확률값을 가진 것으로 설정

     1) A = 1, B/C = 0

     2) B = 1, A/C = 0

     3) C = 1, B/C = 0

     

    - 회귀식을 하나로 만들어서, soft max함수를 사용해 확률값으로 바꿔주는 방법도 있음!

    - # 2단계: 선언하기에서 multi_class = 'ovr'로 설정하면 다중 분류를 이진 분류로 만듦
    model = LogisticRegression(multi_class='ovr')

     

     

    K-Fold Cross Validation

    Random Split의 문제 

    • 새로운 데이터에 대한 모델의 성능을 예측하지 못한 상태에서 최종 평가를 수행
    • 무작위로 분할하면 여러 번 학습시켜도 같은 데이터 셋으로만 성능 평가 하는 것임!

     

    K-분할 교차 검증 개념

    • 모든 데이터가 평가에 한 번, 학습에 k-1번 사용되어 여러 번 검증해 성능을 예측하는 것!
    • k개의 분할 (k>=2)에 대한 성능을 예측해서 일반화 성능을 구하는 것 (디폴트 k=5)
    • 최종 정확도 = Average(Round1, Round2, Round3..., Round10)
    • 튜닝 전 우리 모델의 성능이 어떤 지 예측해보는 것!
      • 장점: 가지고 있는 데이터를 최대한 효율적으로 활용해 과소적합을 방지할 수 있음, 일반화된 모델 만들 수 있음
      • 단점: 반복 횟수가 많아서 학습, 평가에 많은 시간 소요!

     

    성능 예측

    - k 분할 교차 검증 방법으로 모델의 성능을 예측

    - cross_val_score(model, x_train, y_train, cv=n) 형태로 사용! cv는 k값의 개수 지정 (분할 개수, 기본값=5)

    cross_val_score 함수는 넘파이 배열 형태의 값을 반환 / cross_val_score 함수 반환 값의 평균이 예측 성능!

     

    1) Decision Tree(결정트리)

    # 불러오기
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.model_selection import cross_val_score
    
    # 선언하기
    model = DecisionTreeClassifier(random_state=1)
    
    # 검증하기 (학습 데이터 전달, 정확도에 대한 성능, 만약 회귀라면 r2)
    cv_score = cross_val_score(model, x_train, y_train, cv=10)
    
    # 확인
    print(cv_score)
    print('평균:', cv_score.mean())
    print('표준편차:', cv_score.std())
    
    # 예측 결과 저장
    result = {}
    result['Decision Tree'] = cv_score.mean()
    
    # 확인
    result

     

    - 결정트리와 KNN, 로지스틱 회귀분석 각 예측 성능 비교를 위해 딕셔너리에 추가~

     

    2) KNN

    # 불러오기
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.model_selection import cross_val_score
    
    # 선언하기
    model = KNeighborsClassifier()
    
    # 검증하기
    cv_score = cross_val_score(model, x_train, y_train, cv=10)
    
    # 확인
    print(cv_score)
    print(cv_score.mean())
    
    # 예측 결과 저장
    result['KNN'] = cv_score.mean()
    
    # 확인
    result

     

     

    3) Logistic Regression

    # 불러오기
    from sklearn.linear_model import LogisticRegression
    from sklearn.model_selection import cross_val_score
    
    # 선언하기
    model = LogisticRegression()
    
    # 검증하기
    cv_score = cross_val_score(model, x_train, y_train, cv=10)
    
    # 확인
    print(cv_score)
    print(cv_score.mean())
    
    # 예측 결과 저장
    result['Logistic Regression'] = cv_score.mean()
    
    # 확인
    result

     

     

    - 세 가지 중에는 Logistic Regression이 가장 좋은 성능으로 예측됨!

    - 그러나 의사결정트리는 max_depth 설정하고, KNN은 변수 제거를 하면 다른 결과가 나올 수도 있음!

    ** 위의 코딩은 단지 성능을 예측하는 것이므로 정식 학습이 필요함!

    ** k-분할은 성능 예측이라는 점을 꼭 기억!!

     

     

    4) 성능 시각화 비교

    plt.figure(figsize=(3,3))
    #plt.barh(y=list(result.keys()), width=result.values())
    plt.barh(y=list(result), width=result.values())
    plt.show()

     

     

     

     

     

    Hyperparameter 튜닝

    CH1. Hyperparameter

    • 모델의 성능 향상을 위해 최선의 하이퍼파라미터값을 찾는 것! (Grid Search, Random Search 등)

    KNN

    • k 값에 따라 성능이 달라짐 → k 값이 가장 클 때 (=전체 데이터 개수) 가장 단순한 모델인 평균, 최빈값이 됨
    • k 값이 작을수록 복잡한 모델 ! (과적합 가능성 올라감)
    • 거리 계산법에 따라 성능이 달라질 수 있음! (유클리드 거리, 맨하튼 거리)

    Decision Tree

    • max_depth: 트리의 최대 깊이 제한, 기본값(None)으로 데이터 개수가 min_samples_split보다 작아질 때까지 계속 깊이를 증가시킴 → 값이 작을수록 트리 깊이가 제한되어 모델이 단순해짐!
    • min_samples_leaf: leaf가 되기 위한 최소한의 샘플 데이터 수, 기본값은 1→ 값이 클수록 모델이 단순해짐!
    • min_samples_split: 노드를 분할하기 위한 최소한의 샘플 데이터 수, 기본값은 2 → 값이 클수록 모델이 단순해짐!

     

    CH2. Random Search, Grid Search

    • KNN 알고리즘: 이웃 개수인 k값을 어떻게 설정하는가에 따라 모델 성능이 달라짐

    1) 방법1 : Grid Search

    1~n 구간의 정수를 n_neighbors 값으로 해서 모델 성능 정보 수집 (파라미터 값 범위를 모두 사용)

    ② 가장 성능이 좋았던 때의 n_neighbors 값을 찾음

    ③ 이 값을 갖는 KNN 모델 선언 !

    ** n이 크면 상당히 많은 시간이 소요! but 전부 test했기 때문에 아쉬움이 없음

     

    2) 방법2 : Random Search

    1~n 구간의 정수 중 무작위로 m개를 골라 n_neighbors 값을 찾음 (파라미터 값 범위에서 몇 개 선택할지 지정)

    ② 가장 성능이 좋았던 때의 n_neighbors 값을 찾음

    ③ 이 값을 갖는 KNN 모델 선언 !

    ** 임의의 m개를 골랐기 때문에 시간 소모 적음 , but 더 좋은 성능을 보이는 값이 있을 가능성이 있음 ㅠㅠ

     

    - Grid Search, Random Search를 사용할 때 내부적인 K-Fold Cross Validation을 위해 cv 값 지정

    → 실제 수행되는 횟수는 파라미터 조합 수 x cv 값

     

     

    Random Search + Grid Search 적용 고려

    • 하이퍼파라미터 값을 어떻게 정해야 할 지 모르겠을 때
      • Random Search와 Grid Search를 함께 사용할 수 있음
      • Random Search로 먼저 범위 지정 후 무작위 수행 n_iter값 지정해서 최적값 판단
      • 그 후 Grid Search로 근처에 있는 값들 중 더 괜찮은 값이 있을지 확인!

     

    Hyperparameter 튜닝 시 주의사항

    • 파라미터 조정으로 최적화된 성능 얻었다고 해도, 운영환경(평가 데이터)에서의 성능이 보장 되지는 않음!
      • 과적합, 미래 발생할 데이터 과거와 다를 수 있음!

    ** stratify는 주로 분류 문제에서 학습 데이터와 평가 데이터가  같은 수로 나눠지기 위한 것임! (시계열이나 회귀에서는 사용 안 함)

     

     

    모델 튜닝

    1) RandomizedSearchCV 알고리즘 사용하는 모델 선언 

    - 기본 모델 이름, 파라미터 변수, cv(k-fold 분할 개수, default=5), n_iter(시도 횟수, default=10), scoring(평가 방법)

    # 불러오기
    from sklearn.model_selection import RandomizedSearchCV
    # 파라미터 선언
      # max_depth: 1~50
    param = {'max_depth': range(1, 51)}
    
    # Random Search 선언
      # cv=5
      # n_iter=20
      # scoring='r2'
    model = RandomizedSearchCV(model_dt,    # 튜닝할 기본 모델
                              param,        # 테스트 대상 매개변수 범위
                              n_iter=20,    # 임의로 선택할 매개변수 개수
                              cv=5,         # K-Fold cv 개수
                              scoring='r2') # 사용할 평가지표 → 보통 r2
    # 학습하기
    model.fit(x_train, y_train)

     

    2) 결과 확인

    - model.cv_results_['mean_test_score']: 테스트로 얻은 성능

    - model.best_params_: 최적의 파라미터

    - model.best_score_: 최고의 성능

    # 중요 정보 확인
    print('=' * 80)
    print(model.cv_results_['mean_test_score'])
    print('-' * 80)
    print('최적파라미터:', model.best_params_)
    print('-' * 80)
    print('최고성능:', model.best_score_)
    print('=' * 80)

     

    ** 의사결정트리에서는 최적 파라미터값 max_depth가 보통 3~7 사이로 나옴!

     

     

    3) 변수 중요도

    # 변수 중요도, width=model.best_estimator_까지 써야 결정트리가 됨!
    plt.figure(figsize=(5, 5))
    plt.barh(y=list(x), width=model.best_estimator_.feature_importances_)
    plt.show()

     

    - 그리드 서치, 랜덤 서치는 feature_importances_ 속성이 없음!

    →  변수 중요도를 확인하려면 best_estimator_써줘야 함! 

     

Designed by Tistory.