본문으로 바로가기

장, 단점 정리표

TYPE of encoding Advantages Disadvantages
One-hot encoding (get_dummies) - 각 category는 구분되어 있어서 편향이 적음

- 사용하기 매우 쉬움
- 해당 컬럼에 변수가 많을 경우, 많은 컬럼을 재생산하고 모델의 학습 속도를 낮춤

- 0, 1로만 구성되어 Tree의 깊이만 깊어지며 성능을 증가가 어려움

- Random forest를 사용할 경우, 변수의 수가 많을수록 다른 변수보다 많이 계산에 적용되는데 편향이 발생할 수 있음
- Label encoding (replace to numeric)

- Frequency encoding
- One-hot encoding에 비해 빠름 (fewer feat)

- 사용하기 쉬움
- 각 컬럼 내에서 숫자형으로 변환하게 되어 모델은 순서개념을 적용하여 학습

- 선형 회귀 (예측)에 적절하지 않음
Mean encoding - 적은 분할, 빠른 학습 속도

- 적은 양의 많은 category들도 mean target 값을 기반으로 구간 설정이 가능하여  빠름

- 적은 편향
- 구현과 검증이 어려움

- 정규화가 선행되지 않으면 과적합

One-hot encoding

개요

1) 0과 1의 벡터로 해당 column 내의 category 값 (= label)에 대응하여 encoding 시행

 

2) ohe된 데이터셋을 사용할 때, 다중 공선성을 유념해야 한다.

    - feature 간의 상관관계가 높으면 역행렬을 계산하기 어려워 수치적으로 불안정해진다.

    - 따라서 drop_first 매개변수를 사용해 첫 번째 열을 삭제할 수 있다.

 

적용 코드 예시

# titanic dataset

df_train = pd.get_dummies(df_train, columns = ['Initial'], prefix = 'Initial', drop_first=True)


Label encoding

개요

1) 가 라벨을 정수에 대응하여 encoding 시행

 

적용 코드 예시

# titanic dataset

# binary data가 아니기 때문에 비율 확인 (S : 646, C : 168, Q : 77)
df_train['Embarked'].value_counts()

# map 또는 replace
df_train['Embarked'] = df_train['Embarked'].map({'S': 2, 'C': 0, 'Q': 1})

# sklearn module
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df_train['Embarked'] = le.fit_transform(df_train['Embarked'].values)


Mean encoding

개요

1) 많은 distincts 변수들을 다룰 때, 많이 사용되는 기법으로 특히 tree-based 모델에서 유용하다.

2) 예측 : 각 category별로 평균 target 값을 세서 class의 label로 사용

3) 분류 : data point가 class 중 하나에 속할 가능성을 세서 class의 label로 사용

4) label encoding과 매우 유사하지만 target 값과 상관관계가 있어서 학습시키는데 좀 더 효율적이다.

 

$$label_c = p_c$$

- p_c는 category_c의 target value의 평균값을 의미

 

주의점

- 학습데이터에 예측 값이 포함되기 때문에 train data에만 적용

- test data는 절대 사용하면 안된다.

- 예를 들어, train data에는 비율이 9:1 이고 test data의 비율이 5:5 일 경우, data leakaged와 overfitting이 일어난다.

 

적용 코드 예시

# titanic dataset

# target에 대한 mean
embarked_mean = df_train.groupby('Embarked')['Survived'].mean()

# encoded된 값 적용
df_train['Embarked_mean'] = df_train['Embarked'].map(embarked_mean)

Smoothing

1) 위의 극단적인 예시와 같은 상황을 해결하기 위한 방법 (hesitate from overfitting problem)

2) simplist regularisation은 train, test data 모두에 적용 되며, 희귀한 distinct 변수의 encoding을 target mean에 가깝게 하는 것을 의미한다.

$$label_c = \frac{(p_c*n_c + p_{global}*\alpha)}{(n_c+\alpha)}$$

- p_c : target mean for a category

- n_c : number of samples in a category

- P_global : global target mean

- alpha : regularisation parameter (size of a category that we trust)

 

적용 코드 예시

# titanic dataset
df_train['Sex_n_rows'] = df_train['Sex'].map(df_train.groupby('Sex').size())
# df_train['Sex'].value_counts() -> male : 577, female : 314

global_mean = df_train['Survived'].mean()

alpha = 0.7

def smoothing(n_rows, target_mean):
    return (target_mean*n_rows + global_mean*alpha) / (n_rows + alpha)

df_train['Sex_mean_smoothing'] = df_train.apply(lambda x:smoothing(x['Sex_n_rows'], x['Sex_mean']), axis=1)
df_train[['Sex_mean', 'Sex_mean_smoothing']].head()

 

K-fold regularisation

1) k-fold 정규화에서 착안하여 category의 일부분만을 사용

2) 4 ~5 fold면 충분하다.

3) fold만큼 다양한 encoding값이 들어간다.

4) 과정

    - split train data into k-folds --- (1)

For each sample

    - exclude the fold that contains a sample --- (2)

    - estimate encoding for the sample with the data that left using smoothing equation --- (3)

 

적용 코드 예시

from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedKFold

train_2 = train.copy()
train_2[:] = np.nan
train_2['Sex_mean'] = np.nan

X_train = df_train.drop(df_train['Survived'], axis = 1)
y_train = df_train['Survived']

skf = StratifiedKFold(n_splits = 5, shuffle = True, random_state = 42)

for train_id, val_id in skf.split(X_train, y_train):
    X_train, X_val = train.iloc[train_id], train.iloc[val_id]
    
    means = X_val['Sex'].map(X_train.groupby('Sex')['Survived'].mean())
    X_val['Sex_mean'] = means
    train_2.iloc[val_id] = X_val
    
# 폴드에 안들어간 값은 글로벌 평균
global_mean = train['Survived'].mean()
train_2['Sex'] = train_2['Sex'].fillna(global_mean)

 

Expanding mean

1) data leakage가 적고 다채로운 값이 나온다.

2) 많은 대상이 인코딩 될수록 해당 category mean에 가깝다.

3) 작은 카테고리일수록 더욱 randomization이 되므로 overfitting을 피하는데 도움이 된다.

 

적용 코드 예시

cumsum = train.groupby('Sex')['Survived'].cumsum() - train['Survived']
cumcnt = train.groupby('Sex').cumcount() + 1
train_new['Sex_mean'] = cumsum / cumcnt

Conclusion

1) high distincts features column

    - KFold mean encoding 4 or 5 folds and alpha = 5 & frequency encoding --- (1)

    - (dataset > 50,000) and (score is bad) -> expanding mean --- (2)

2) low distincts features column

    - label encoding and frequency encoding --- (1)

    - if unsatisfied with score, KFold mean encoding 4 or 5 folds with alpha = 5 --- (2)

3) datasets < 50,000 rows:

    - label encoding and frequency encoding --- (1)

    - if the dataset is very smalll, just use one-hot encoding

    - do not use too much regularization with mean encoding ( maximum == kfold 4 or 5 with alpha = 5)


참고

www.kaggle.com/vprokopev/mean-likelihood-encodings-a-comprehensive-study

zzsza.github.io/data/2018/09/08/feature-engineering/

'Data > Data preprocessing' 카테고리의 다른 글

Sampling unbalanced data  (1) 2021.02.23
Kernel method  (0) 2021.02.22
Feature Extraction (PCA, LDA)  (0) 2021.02.21
Data Scaling (normalization, standardization)  (0) 2021.02.19
Feature selection (변수 선택)  (0) 2021.01.17