AI·빅데이터 융합 경영학 Study Note
[ML수업] 8주차 실습2: feature engineering- Categorical Feature Transformation (범주형) 본문
[ML수업] 8주차 실습2: feature engineering- Categorical Feature Transformation (범주형)
SubjectOwner 2023. 11. 21. 15:52X_train_imp[cat].head()
###

### One-Hot Encoding- ##### pd.get_dummies()를 사용하는 방법
# 학습 데이터와 평가 데이터를 결합한 후, get_dummies를 통한 OHE 수행
X_all_imp = pd.concat([X_train_imp, X_test_imp])
X_all_imp_ohe = pd.get_dummies(X_all_imp, columns=cat)
#X_all_imp_ohe.info()
#X_all_imp_ohe.filter(like='car').head()
# 'car'라는 문자열을 포함한 열들을 필터링하여 선택하고, 선택된 열들과 해당하는 처음 5개의 행을 출력
# 학습 데이터와 평가 데이터로 재분할
#이렇게 하면 원핫인코딩된 새로운 데이터셋이 생기는거임.
X_train_imp_ohe = X_all_imp_ohe.iloc[:X_train_imp.shape[0],:].reset_index(drop=True)
X_test_imp_ohe = X_all_imp_ohe.iloc[X_train_imp.shape[0]:,:].reset_index(drop=True)
### One-Hot Encoding- ##### OneHotEncoder를 사용하는 방법
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(handle_unknown='ignore', sparse=False)
ohe.fit(X_train_imp[cat]) #[]를 더 감싼 이유는 인자로 2차원 배열을 받기 때문.
print(ohe.categories_) # # OneHotEncoder의 범주형 변수의 카테고리 정보를 확인합니다
'''
[array([0, 1, 2, 3, 4, 5, 6], dtype=object), array([0, 1], dtype=object), array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], dtype=object), array([1.0, 2.0, 3.0, 4.0], dtype=object), array([0, 1], dtype=object), array([1.0, 2.0, 3.0, 4.0], dtype=object), array(['AL', 'AR', 'CO', 'CT', 'DC', 'DE', 'FL', 'GA', 'IA', 'ID', 'IN', 'KS', 'KY', 'MD', 'ME', 'MO', 'MS', 'MT', 'ND', 'NE', 'NH', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'RI', 'SD', 'TN', 'UT', 'WA', 'WI', 'WV', 'WY'], dtype=object), array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], dtype=object)]
'''
각 카테고리 목록은 해당 범주형 변수에 포함된 고유한 카테고리의 값들을 나타내며, 각 값은 해당 변수의 원-핫 인코딩된 특성에 대한 인덱스로 사용됩니다. 이 정보를 통해 각 범주형 변수의 원-핫 인코딩 결과를 해석할 수 있습니다.
아래 두 코드는 같은 기능을 하는데 첫 번째 코드는 배열로 작업하고 두 번째 코드는 DataFrame으로 작업합니다.
결과물은 동일함.
1. 이 코드는 먼저 더미 특성의 칼럼 이름을 생성하고, 이를 원-핫 인코딩된 결과를 DataFrame으로 변환하는 데 사용합니다. 그런 다음, 인코딩된 특성을 원본 데이터에서 제거하고 나머지 특성과 결합하여 X_test_imp_ohe라는 새로운 데이터프레임을 생성합니다. 이렇게 하면 인코딩된 특성이 포함된 완전한 데이터가 준비됩니다.
# OHE 결과를 DataFrame 형식으로 만들어 사용할 경우:
# dummy에 대한 컬럼명 생성
columns = []
for i, c in enumerate(cat):
columns += [f'{c}_{v}' for v in ohe.categories_[i]]
# 생성된 dummy를 DataFrame으로 변환
ohe_train = pd.DataFrame(ohe.transform(X_train_imp[cat]), columns=columns)
ohe_test = pd.DataFrame(ohe.transform(X_test_imp[cat]), columns=columns)
# 인코딩한 feature는 제거하고 나머지 feature와 결합
X_train_imp_ohe = pd.concat([X_train_imp.drop(columns=cat).reset_index(drop=True), ohe_train], axis=1) # 원래 피처 삭제 후 OHE된 feature 병합
X_test_imp_ohe = pd.concat([X_test_imp.drop(columns=cat).reset_index(drop=True), ohe_test], axis=1) # 원래 피처 삭제 후 OHE된 feature 병합
X_train_imp_ohe
2. 이 코드는 먼저 X_train_imp와 X_test_imp에서 범주형 변수(cat)를 제거한 후, 해당 범주형 변수를 원-핫 인코딩하여 얻은 결과를 기존의 수치형 변수와 결합합니다. 이렇게 하면 인코딩된 특성이 포함된 새로운 데이터프레임 X_train_imp_ohe와 X_test_imp_ohe가 생성됩니다.
# OHE 결과를 Array 형식으로 만들어 사용할 경우:
X_train_imp_ohe = X_train_imp.drop(cat, axis=1)
X_test_imp_ohe = X_test_imp.drop(cat, axis=1)
X_train_imp_ohe = np.c_[X_train_imp.drop(cat, axis=1),
ohe.transform(X_train_imp[cat])]
X_test_imp_ohe = np.c_[X_test_imp.drop(cat, axis=1),
ohe.transform(X_test_imp[cat])]
X_train_imp_ohe
두가지 방법이 있다.
주요 차이점:
LabelEncoder는 각 범주에 고유한 정수를 할당하며 범주 간 순서를 고려하지 않습니다.
OrdinalEncoder는 범주 간의 상대적인 순서를 고려하여 인코딩합니다. 또한 알 수 없는 범주를 처리하는 방법을 설정할 수 있습니다.
# LabelEncoder: 하나의 범주형 피처만 인코딩
from sklearn.preprocessing import LabelEncoder
# 레이블 인코딩 결과를 저장할 변수를 생성합니다.
X_train_imp_le, X_test_imp_le, = X_train_imp.copy(), X_test_imp.copy()
le = LabelEncoder()
# 각 범주형 변수에 대해 레이블 인코딩을 수행합니다.
for c in cat:
# 학습 데이터(X_train_imp)를 이용하여 레이블 인코딩을 수행하고, 결과를 학습 데이터 및 테스트 데이터에 적용합니다.
X_train_imp_le[c] = le.fit_transform(X_train_imp[c])
X_test_imp_le[c] = le.transform(X_test_imp[c])
handle_unknown 매개변수를 사용하여 알 수 없는 범주를 처리할 수 있으며, unknown_value를 설정하여 알 수 없는 범주를 대체할 값을 지정할 수 있습니다.
'error' (기본값): 알 수 없는 범주가 발견되면 오류를 발생시킵니다. 이 옵션을 선택하면 새로운 데이터에 등장하는 알 수 없는 범주가 처리되지 않고, 오류 메시지가 출력됩니다.
'use_encoded_value': 알 수 없는 범주를 사용자가 지정한 unknown_value 매개변수로 인코딩합니다. 따라서 새로운 범주는 사용자가 지정한 값으로 대체됩니다.
# OrdinalEncoder: 전체 범주형 피처를 인코딩
from sklearn.preprocessing import OrdinalEncoder
X_train_imp_le, X_test_imp_le, = X_train_imp.copy(), X_test_imp.copy()
le = OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1, dtype=int)
X_train_imp_le[cat] = le.fit_transform(X_train_imp[cat])
X_test_imp_le[cat] = le.transform(X_test_imp[cat])
X_train_imp_le[cat]
<타겟 인코딩> <<< 이게 제일 좋은 듯 .
타겟 인코딩(Target Encoding)은 범주형 변수를 다루는 데이터 전처리 기술 중 하나로, 주로 분류(classification) 문제에서 사용됩니다. 이 기술은 각 범주형 변수의 범주(category)를 해당 범주에 대한 타겟 변수(종속 변수)의 평균값 또는 확률값으로 대체하는 방법입니다.
타겟 인코딩은 일반적으로 범주형 변수가 많은 경우나 범주 간의 관계가 중요한 경우에 유용하게 사용됩니다.
최종적으로 X_train_imp_te 데이터프레임의 범주형 변수 열은 TargetEncoder를 적용한 결과로 업데이트되었습니다.
# Target Encoding
from category_encoders import TargetEncoder
X_train_imp_te, X_test_imp_te, = X_train_imp.copy(), X_test_imp.copy()
te = TargetEncoder(cols=cat, min_samples_leaf=5, smoothing=100)
X_train_imp_te[cat] = te.fit_transform(X_train_imp[cat], y_train)
X_test_imp_te[cat] = te.transform(X_test_imp[cat])
X_train_imp_te[cat]
# day 별 target 평균값
pd.concat([X_train_imp[cat], y_train], axis=1).groupby('day')['record_type'].mean()
<타겟 인코딩 using K-fold> <<<< 이게 그냥 타겟인코딩을 하는것보다 성능이 좋음.
# Target encoding using k-fold
from sklearn.model_selection import KFold
X_train_imp_te, X_test_imp_te, = X_train_imp.copy(), X_test_imp.copy()
# for문을 이용한 변수를 반복하여 타깃 인코딩 수행
for c in cat:
# 학습 데이터 전체에서 각 범주별 타깃 평균을 계산
data_tmp = pd.DataFrame({c: X_train_imp[c], 'target': y_train})
target_mean = data_tmp.groupby(c)['target'].mean()
# 테스트 데이터의 카테고리 변경
X_test_imp_te[c] = X_test_imp[c].map(target_mean)
# 학습 데이터 변환 후 값을 저장하는 배열을 준비
tmp = np.repeat(np.nan, X_train_imp.shape[0])
# 학습 데이터 분할
kf = KFold(n_splits=4, shuffle=True, random_state=72) # n_splits은 4~10 정도가 적당
for idx_1, idx_2 in kf.split(X_train_imp):
# 아웃 오브 폴드로 각 범주형 목적변수 평균 계산
target_mean = data_tmp.iloc[idx_1].groupby(c)['target'].mean()
# 변환 후의 값을 날짜 배열에 저장
tmp[idx_2] = X_train_imp[c].iloc[idx_2].map(target_mean)
# 변환 후의 데이터로 원래의 변수를 변경
X_train_imp_te[c] = tmp
X_train_imp_te[cat]