230630_머신러닝: 데이터셋과 모델 성능 평가- Hold out vs K-Fold Cross Validation

안인균·2023년 7월 1일
0
post-thumbnail

모델 성능 평가를 위한 데이터셋

데이터셋

  • Train data set, 훈련 : 모델 학습할 때 쓰이는 데이터셋

  • Validation data set, 검증 : 학습 중인 모델을 중간 검증

  • Test data set, 평가 : 최종 평가용 데이터셋, 목표 성능치를 가리기 위해서 사용됨. 마지막 한번만 사용.

머신러닝 모델 파라미터

  • 성능에 영향을 주는 값, 최적의 성능을 내는 값을 찾아야 한다.
    • 하이퍼 파라미터 (Hyper parameter)
      : 사람이 직접 설정해야하는 파라미터 값
    • 파라미터 (Parameter)
      : 데이터 학습 을 통해 찾는 파라미터 값

Hold out - Data분리 방식 1

  • 데이터셋을 Train set, Validation set, Test set으로 나눈다.
  • sklearn.model_selection.train_test_split() 함수 사용
    • 하나의 데이터셋을 2분할 하는 함수

Hold out 방식의 단점

  • train/validation/test 셋이 어떻게 나눠 지냐에 따라 결과가 달라진다.
    • 데이터가 충분히 많을때는 변동성이 흡수되 괜찮으나 적을 경우 문제가 발생할 수 있다.
      • 이상치에 대한 영향을 많이 받는다.
      • 다양한 패턴을 찾을 수가 없기 때문에 새로운 데이터에 대한 예측 성능이 떨어지게 된다.
  • Hold out 방식은 (다양한 패턴을 가진) 데이터의 양이 많을 경우에 사용한다.

K-Fold Cross Validation - Data분리 방식 2

  1. 데이터셋을 설정한 K 개로 나눈다.
  2. K개 중 하나를 검증세트로 나머지를 훈련세트로 하여 모델을 학습시키고 평가한다.
  3. K개 모두가 한번씩 검증세트가 되도록 K번 반복하여 모델을 학습시킨 뒤 나온 평가지표들을 평균내서 모델의 성능을 평가한다.
  • 데이터양이 충분치 않을때 사용합니다.
  • 이상치의 영향을 어느정도 줄일 수 있습니다.
  • 보통 Fold를 나눌때 2.5:7.5 또는 2:8 비율이 되게 하기 위해 4개 또는 5개 fold로 나눠 사용합니다.

KFold - 회귀 문제의 데이터셋을 분리할 때 사용.

  • 지정한 개수(K)만큼 분할한다.
  • Raw dataset의 순서를 유지하면서 지정한 개수로 분할한다.
  • 회귀 문제일 때 사용한다.
  • KFold(n_splits=K)
    • 몇개의 Fold로 나눌지 지정
  • KFold객체.split(데이터셋)
    • 데이터셋을 지정한 K개 나눴을때 train/test set에 포함될 데이터의 index들을 반환하는 generator 생성

Generator

  • 연속된 값을 제공(생성)하는 객체. 연속된 값을 한번에 메모리에 저장하지 않고 필요시마다 순서대로 하나씩 제공한다.
  • 함수형식으로 구현하며 return 대신 yield를 사용한다.
def my_gen(i):
    i+=10
    yield i
    
    i+=10
    yield i
    
    
    i+=10
    yield i

### 객체 생성 및 실행 
g = my_gen(10) # generator 객체를 생성
g
# 출력 : <generator object my_gen at 0x00000183BD023220>

# 첫번째 값
# g[0] TypeError: 'generator' object is not subscriptable

next(g) # next() : generator 객체에서 다음 값을 가져오는 함수. 
# 출력 : 20

next(g) # 출력 : 30
next(g) # 출력 : 40

next(g) # StopIteration

# 마지막 next는 함수에서 정의된 모든 yield가 끝나 generator 반복문이 끝나면서
탈출되어 생기는 에러문입니다. 
정의된 yield는 총 3개로 세번의 next(g)가 끝나고 네번째 next(g)에서 발생한 것 입니다.


# 다른 generatore 예시

for i in my_gen(50):
    print(i)
# 출력 : 50 60 70
# yield가 끝나면 자동으로 반복문 탈출

Generator - 코루틴(coroutine) 알아보기

코루틴 (Coroutine) :

협작(coroutine)을 위한 함수입니다.
코루틴은 다른 함수나 루틴과 협력하여 작업을 수행하고 결과를 주고받을 수 있습니다.
Generator와 비슷한데, yield 키워드 대신 yield from이나 await 키워드를 사용하여 다른 코루틴으로 제어를 양보하고, 결과를 반환받을 수 있습니다.
실행 흐름을 제어하기 위해 호출자(caller)와 협력하여 비동기적인 작업을 처리하는데 사용될 수 있습니다.

  • 🚩 Generator는 반복문을 생성하는 함수로서 값을 한 번에 하나씩 반환하고 메모리를 효율적으로 관리하는 데 사용됩니다. 반면에, Coroutine은 협작을 위한 함수로서 호출자와 협력하여 비동기 작업을 처리하고 결과를 주고받을 수 있습니다.

mean_squared_error

🚩 회귀 문제는 무한대의 값들을 추정하는 과정이기 때문에 완전히 그 값을 맞춘다는 것은 불가능하다.
따라서 이러한 회귀 문제의 모델 성능 평가는 '얼마나 많이 맞추는가' 가 아니라 '얼마나 적게 틀렸는가' 를 중점적으로 봐야한다.
따라서 사용되는 메서드도 분류문제의 accuracy_score가 아닌 mean_squared_error 를 사용해서 모델 성능 평가를 한다.


StratifiedKFold - 분류 문제의 데이터셋을 분리할 때 사용.

🚩 StratifiedKFoldKFold 나 모델 학습, 추론, 평가 하는 코드는 그렇게 큰 차이는 없습니다. 사용되는 객체와 그에 따른 메서드의 차이만 있을 뿐, 전체적인 코드의 흐름은 동일합니다.
=> 따라서 이를 통해 Cross Validation"함수화" 가 가능합니다.

# cv - Cross Validation
def cv(model, X, y, k, metrics):
    
    s_kfold = StratifiedKFold(n_splits=k)
    index_gen = s_kfold.split(X, y)

    result_list = []

    for train_idx, val_idx in index_gen:
        X_train, y_train = X[train_idx], y[train_idx]
        X_val, y_val = X[val_idx], y[val_idx]
    
        model.fit(X_train, y_train)

        pred = model.predict(X_val)
        score = metrics(y_val, pred)
        result_list.append(score)
    return result_list

Cross Validation Utility 함수

cross_val_score()

: 한개의 평가지표만 가지고 평가할 수 있는 함수.

cross_validate()

: 여러개의 평가지표를 설정하여 평가할 수 있는 함수.

🚩 Cross Validation Utility 함수는 KFold, StratifiedKFold에서 사용된
코드들의 유사성을 통해 함수화가 가능한 점을 토대로
from sklearn.model_selection import cross_val_score, cross_validate 을 통해
import가 가능하고 위의 함수를 호출 하여 사용할 수 있습니다.
데이터셋의 타입에 맞춰 각각의 Parameter에 값을 대입하여 간단하게 사용할 수 있습니다.


데이터 전처리

결측치 처리

결측치란? : Not Available-NA, NaN, None, Null

  • 수집하지 못한 값, 모르는 값.
    머신러닝 알고리즘은 데이터셋에 결측치가 있으면
    학습이나 추론을 하지 못하기 때문에 적절한 처리가 필요합니다.
    결측치 처리는 데이터 전처리 단계에서 진행한다.

결측치 제거

  • Pandas
    • dataframe.isnull(), dataframe.isna()
      • 원소별 결측치 인지 여부 확인

    • dataFrame.dropna(axis=0, subset=None, inplace=False)
      • 결측치 제거
      • axis=0(default) : 결측치가 있는 행을 삭제 / axis=1: 결측치가 있는 열을 삭제
      • subset : 결측치가 있으면 제거할 열이나 행을 지정한다.
      • inplace=False(default) : 결측치를 제거한 결과 DataFrame을 생성해서 반환. inplace=True : 원본 Dataframe에 적용한다.

결측치 다른 값으로 대체

  • pd.DataFrame 에서의 대체 방법
    • dataframe.fillna(value)
      • value : 결측치를 채울 값을 지정한다.
        • scalar : 지정한 값으로 모두 채운다.
        • dictionary : key-컬럼명, value-채울값
          • 컬럼별로 다른 값으로 채운다.


  • scikit-learn 에서의 대체 방법
    • sklearn.impute.SimpleImputer transformer 클래스 사용
      • 주요 매개변수
        • strategy="mean"
          • 결측치를 어떤 값으로 변경할지를 설정.
          • "mean" : default로 평균값으로 변경한다.
          • "median" : 중앙값으로 변경한다.
            • "mean", "median"은 연속형 feature에 적용한다.

          • "most_frequent" : 최빈값으로 변경한다. 범주형 feature에 적용한다.
          • "constant" : 매개변수 fill_value에 설정한 값으로 변경한다.

0개의 댓글