ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 머신러닝 Cross Validation 구현하기, 파이썬 코드 예시(K-fold, sklearn.model_selection.RepeatedKFold)
    Data Science/Pandas & Numpy&Scikit-learn 2022. 11. 22. 11:51
    반응형

    1. Cross Validation이란?

     

    2. Reggression 예제에서의 K-fold 파이썬 코드 구현

    2.1 라이브러리 호출

    import seaborn as sns
    
    import numpy as np
    import pandas as pd
    
    from sklearn.preprocessing import MinMaxScaler, OneHotEncoder
    from sklearn.model_selection import train_test_split, RepeatedKFold
    
    from xgboost import XGBRegressor

    2.2 데이터셋 준비

    seaborn 라이브러리를 활용하여 tips 데이터를 불러온다.

    해당 데이터셋은 고객 정보를 활용하여 얼마의 tip을 줄지 판단하는 회귀(Reggressor) 문제이다.

    df = sns.load_dataset('tips')

    예시 데이터인만큼 결측치는 별도로 존재하지 않으며,

    이상치 또한 없다고 가정한다.

    결측치 처리에 대해서는 해당 포스팅의 8번 항목을 참조. ([Pandas] Pandas를 통한 데이터 전처리)

    2.3 Train/Test 분할

    Train/Test 셋으로 분할해준다.

    만약 Train Set과 Test Set이 별도로 제공된다면, 해당 단계를 건너뛰면 된다.

    reset_index를 적용해주는 이유는 train_test_split하게되면 index가 섞이게 된다.

    이후 전처리과정에서 문제를 야기할 수 있으므로 0부터 다시 시작하게 초기화해준다.

    train_df, test_df = train_test_split(df, test_size=0.2, random_state=7)
    
    # 분할하면서 섞인 index를 초기화해준다
    train_df.reset_index(drop=True, inplace=True)
    test_df.reset_index(drop=True, inplace=True)
    
    train_df.head(2)

    2.4 데이터 전처리(Preprocessing)

    2.4.1 사용할 컬럼 설정

    numeric_cols = ['total_bill','size'] # 수치형 데이터
    categoric_cols = ['sex','smoker','day','time'] # 범주형 데이터
    encoded_categoric_cols = [] # 범주형 데이터 인코딩 후 변경된 컬럼 저장용
    target = ['tip'] # 예측하고자 하는 목표(y)

    2.4.2 스케일링(Scaling)

    데이터가 동일한 범위의 값을 가지도록 scaling을 진행해준다.

    (Tree계열의 모델을 사용할 경우 Feature에 대한 scaling은 생략해도 된다.)

    scaling에 대한 자세한 내용은 아래의 글을 참조.

    ([정규화,sklearn] MinMaxScaler, StandardScaler, RobustScaler)

    # Feature(X, 독립변수)를 위한 scaling
    scaler = MinMaxScaler()
    train_df[numeric_cols] = scaler.fit_transform(train_df[numeric_cols])
    
    # target(Y, 종속변수)를 위한 scaling
    scaler_y = MinMaxScaler()
    train_df[target] = scaler_y.fit_transform(train_df[target])
    
    train_df.head(2)

    2.4.3 인코딩(Encoding)

    범주형 데이터를 모델에 넣어주기 위해서는 인코딩을 적용해야한다.

    sklearn 라이브러리를 활용하여 인코딩을 진행한다.

    인코딩의 자세한 내용은 아래의 글을 참조.

    ([인코딩,sklearn] One-Hot Encoding)

     

     

    #from sklearn.preprocessing import OneHotEncoder
    
    enc = OneHotEncoder()
    enc.fit(train_df.loc[:,categoric_cols])
    
    encoded_df = pd.DataFrame(enc.transform(train_df.loc[:,categoric_cols]).toarray(),
                          columns=enc.get_feature_names(categoric_cols))
    
    encoded_categoric_cols = list(encoded_df.columns)
    encoded_df.head(2)

    만들어진 encoded_df를 원본과 합쳐주기 전에,
    인코딩된 원본 컬럼을 삭제하고 합쳐준다.

    train_df = train_df.drop(categoric_cols, axis=1)
    train_df = pd.concat([train_df,encoded_df],axis=1)
    train_df.head(2)

    2.5 k-fold 준비

    RepeatedKFold 라이브러리를 사용하여 K-fold를 구현한다.

    n_splits : 분할할 K 개수

    n_repeats : n_splits * n_repeats 개수 만큼의 k-fold를 만들어낸다.

                       (n_repeats가 2이상일경우 새로운 random 기준으로 k split을 진행한다.)

    #from sklearn.model_selection import RepeatedKFold
    
    rkf = RepeatedKFold(n_splits=5, n_repeats=1, random_state=7)

    아래의 코드는 RepeatedKFold에 대한 간단한 사용 예시이다.

    n_repeats가 1일 경우 아래의 데이터셋을 다음과 같이 5등분하여 (5,8),(0,2),(1,9),(3,7),(4,6) kfold를 진행했다.

    n_repeats가 2일 경우에는 총 두번의 분할 셋을 가지고 각각 kfold를 수행했다.

    ( set1 : (5,8),(0,2),(1,9),(3,7),(4,6)  //  set2 : (1,3),(2,5),(0,9),(4,6),(7,8)

    이때 rkf.split(tmp_df.index)에서는 사용될 데이터가 아닌 데이터의 인덱스를 반환함을 명심해야한다.

    tmp_df = pd.DataFrame({
        'col_a' : [1,2,3,4,5,6,7,8,9,10]
    })
    i=0
    
    for train_index, valid_index in rkf.split(tmp_df.index):
        print(f'------{i}번째 fold------')
        print('train index',train_index)
        print('valid index',valid_index)

    2.6 k-fold를 활용한 모델 학습

    먼저, 학습에 사용할 Feature들을 리스트에 담아둔다.

    # 학습에 사용할 Feature lst
    x_col_lst = numeric_cols+encoded_categoric_cols
    x_col_lst

    다음으로는 분할된 k-fold 개수만큼 모델을 생성하고 학습한다.

    model_lst = []
    
    for train_index, valid_index in rkf.split(train_df.index):
        
        # 주어진 인덱스를 기반으로 해당 회차의 Train/Valid를 생성한다
        X_train = train_df.loc[train_index,x_col_lst]
        X_valid = train_df.loc[valid_index,x_col_lst]
        y_train = train_df.loc[train_index,target]
        y_valid = train_df.loc[valid_index,target] 
        
        # 모델을 선언하고 학습한다.
        xgb = XGBRegressor(n_estimators=100, learning_rate=0.15)
        xgb.fit(X_train, y_train, early_stopping_rounds=5,
                eval_set=[(X_valid, y_valid)], verbose=False)
        
        # 해당 모델에 대한 R2 Score 확인
        print('R2 Score : ',xgb.score(X_valid, y_valid))
        
        # 학습된 모델을 리스트에 저장한다
        model_lst.append(xgb)

    K-fold에서 5개로 분할하였기 때문에 5개의 모델이 생성된다.

    성능이 좋지는 않지만, 해당 포스팅은 사용방법 예시가 목적이기에 넘어간다.

    2.7 테스트 수행

    2.7.1 테스트 데이터셋 전처리

    Test set에도 train set과 동일한 전처리를 수행해주어야한다.

    이때 scaling이나 encoding을 할때 fit_transform이 아닌 transform을 써야한다!

    test_df.loc[:,numeric_cols] = scaler.transform(test_df.loc[:,numeric_cols])
    test_df.loc[:,target] = scaler_y.transform(test_df.loc[:,target])
    
    
    encoded_df = pd.DataFrame(enc.transform(test_df.loc[:,categoric_cols]).toarray(),
                          columns=enc.get_feature_names(categoric_cols))
    
    test_df = test_df.drop(categoric_cols, axis=1)
    test_df = pd.concat([test_df,encoded_df],axis=1)
    
    test_X = test_df.loc[:,x_col_lst]
    
    test_X.head(2)

    2.7.2 예측하기

    총 5개의 모델에 모두 test_X를 넣어 예측을 수행한다.

    각 예측결과는 평균을 구하여 최종 예측 결과를 생성한다.

    total_preds = []
    for m in model_lst:
        total_preds.append(m.predict(test_X))
    final_preds = sum(total_preds)/5.0
    
    print(final_preds)

    여기서 주의할점은 현재 예측결과가 Scaling 되어있다는 점이다.

    따라서 Unscaling을 해주어야 진짜 예측값을 얻을 수 있다.

    final_preds_realScale = scaler_y.inverse_transform([final_preds])[0]
    final_preds_realScale

    3. Classification 예제에서의 K-fold 파이썬 코드 구현

    추후작성예정

    반응형

    댓글

Designed by Tistory.