본문 바로가기
AI SCHOOL/TIL

[DAY 54] ExtraTreesClassifier, scikit-learn의 OneHotEncoder, cross validation

2023. 3. 14.

극도로 무작위화(Extremely Randomized) 된 앙상블 러닝 모델을 사용하여 분류 결과를 얻어냈다.

그 과정에서 sklearn의 OneHotEncoder를 통해 원핫인코딩을 해보고 pandas의 get_dummies 함수와의 차이점을 익혔으며 교차검증(cross validation)으로 모델을 평가했다.

ExtraTreesClassifier

분류를 위한 앙상블 학습 알고리즘 중 하나로, 무작위 디시전트리를 사용하는 방법
랜덤포레스트와 유사하지만 극도로 무작위화된 특징을 가진다. random threshold를 사용하여 더욱 랜덤한 트리를 생성하기 때문에 모델의 분산을 줄이고 오버피팅을 방지할 수 있다.

데이터 준비

Kaggle에 있는 Telco Customer Churn 데이터를 활용했다.
인구통계와 구독에 관련된 정보로 이루어져 있으며 이를 활용해 Churn(이탈 여부)를 예측했다.
3일간 같은 데이터를 통해 머신러닝을 반복 학습 했으며, 데이터 전처리와 모델 선택의 차이를 두고 결과가 어떻게 달라지는지 확인하였다.

index 지정, 결측치 제거, 숫자 형태의 문자열을 숫자형으로 변환 등 과정을 거친 데이터프레임을 변수 df에 저장하였다.

formation
df.info() 결과

 

nuni
df.nunique() 결과

nunique가 2인 컬럼들이 보인다. binary encoding 대상이 된다.

nuni = df.drop(columns=label_name).nunique()
bicols = nuni[nuni==2].index

df[bicols].head(3)

해당 컬럼들만 모아 보면

bicols

SeniorCitizen은 이미 binary encoding이 되어 있으며 나머지 5개 컬럼은 아래 코드를 통해 수행한다.

df['gender_binary'] = df['gender']=='Male'
for col in bicols[2:]:
    df[f'{col}_binary'] = df[col] == 'Yes'

해당 코드의 실행 결과로 binary encoding된 5개 컬럼이 생긴다.

binaryed

True/False 형태가 되었다.
이후 원래의 컬럼은 drop을 시켰다.

binary encoding 완료

bool 타입의 컬럼 5개가 생긴 것을 확인할 수 있다.

X_train, X_test, y_train, y_test 만들기

X_raw = df.drop(columns='Churn')
y = df['Churn']
X_raw.shape, y.shape

# 실행 결과
((7032, 19), (7032,))

먼저 target인 'Churn' 컬럼을 제외한 X_raw와 'Churn' 컬럼 데이터인 y로 구분했다.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X_raw, y,
                                                    test_size=0.2,
                                                    stratify=y, random_state=42)
                                                    
X_train.shape, X_test.shape, y_train.shape, y_test.shape

# 실행 결과
((5625, 19), (1407, 19), (5625,), (1407,))

그 후 train_test_split을 이용하여 학습, 예측용 데이터 8:2로 나누었다.

One Hot Encoding

pandas의 get_dummies를 사용하지 않고 sklearn의 OneHotEncoder를 사용했다.

# 원핫인코딩할 컬럼명
col_ohe = X_train.select_dtypes(include='object').columns
col_ohe

# 실행 결과
Index(['MultipleLines', 'InternetService', 'OnlineSecurity', 'OnlineBackup',
       'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies',
       'Contract', 'PaymentMethod'],
      dtype='object')

이 컬럼을 대상으로 원핫인코딩을 했다.

X_train_ohe = ohe.fit_transform(X_train[col_ohe])
X_test_ohe = ohe.transform(X_test[col_ohe])
X_train_ohe.shape, X_test_ohe.shape

# 실행 결과
((5625, 31), (1407, 31))

pandas의 get_dummies와 다르게, scikit-learn의 OneHotEncoder를 사용하여 원핫인코딩을 하면 데이터프레임이 반환되지 않는다. 따라서 데이터프레임으로 바꾼 후, 기존의 변환해 줄 필요가 없던 숫자형태의 나머지 데이터와 병합한다.

# 원핫인코딩한 데이터를 데이터프레임으로 만듦
df_train_ohe = pd.DataFrame(X_train_ohe.toarray(), columns=ohe.get_feature_names_out())
df_test_ohe = pd.DataFrame(X_test_ohe.toarray(), columns=ohe.get_feature_names_out())

# 수치 데이터 : 기존 train 데이터에서 object 타입의 데이터는 제외하고 가져오기
X_train_num = X_train.select_dtypes(exclude='object')
X_test_num = X_test.select_dtypes(exclude='object')

# train, test 데이터를 학습 가능한 형태로 만들기
# => 수치데이터와 원핫인코딩된 데이터를 병합
X_train_enc = pd.concat([X_train_num, df_train_ohe], axis=1)
X_test_enc = pd.concat([X_test_num, df_test_ohe], axis=1)

인코딩 완료된 데이터 X_train_enc, X_test_enc는 각각 5625행 40열, 1407행 40열이 되었다.

ExtraTreesClassifier, Cross Validation

# ExtraTreesClassifier 모델 생성
model = ExtraTreesClassifier(random_state=42)

극도로 랜덤화된 앙상블 모델 ExtraTreesClassifier를 생성했다.

from sklearn.model_selection import cross_val_predict

y_valid_pred = cross_val_predict(model, X_train_enc, y_train, cv=5, n_jobs=-1)
(y_train==y_valid_pred).mean()

# 실행 결과
0.7710222222222223

cross_val_predict를 통해 교차 검증된 추정치를 생성하고, 정확도를 확인했다. 약 0.77이 나왔다.

cv
교차 검증

model.fit(X_train_enc, y_train)
y_pred = model.predict(X_test_enc)
y_pred

# 실행 결과
array(['No', 'Yes', 'No', ..., 'No', 'No', 'No'], dtype=object)

분류 모델을 학습시키고, 예측값(Yes, No로 이루어진 배열)을 얻었다.

모델 평가

(y_pred==y_test).mean()

# 실행 결과
0.7711442786069652

boolean 배열의 mean()을 구하는 방법과

model.score(X_test_enc, y_test)

# 실행 결과
0.7711442786069652

모델의 score 메소드를 이용한 방법 모두 같은 결과를 낸다.

# feature_importances_ : 모델의 피처 중요도
fi = pd.Series(model.feature_importances_)
fi.index = model.feature_names_in_
fi.sort_values(ascending=False).head(10)

feature_importances_를 사용하여 모델의 피처 중요도를 알 수 있다.

feature
feature importances

중요도 상위 10개 feature를 시각화하면 아래와 같다.

feature2


sklearn 라이브러리를 활용한 One Hot Encoding을 통해 pandas의 get_dummies와의 차이를 알았고, Extremely randomized ensemble model ExtraTreesClassifier, 교차 검증의 개념과 활용 방법을 익혔다.

반응형

댓글