Search

Data Encoding

대분류
인공지능/데이터
소분류
ML/DL 정리 노트
유형
머신 러닝
부유형
데이터 전처리
최종 편집 일시
2024/10/27 15:26
생성 일시
2024/08/23 02:27
14 more properties

Data Encoding

머신러닝 알고리즘은 문자열 데이터 속성을 입력받지 못하며, 모든 데이터는 숫자형으로 입력받아야 한다.
따라서, 문자형 카테고리 속성은 모두 숫자형으로 변환이 되어야 하는데, 이러한 과정을 데이터 인코딩

설치

!pip install category_encoders
Python
복사
import numpy as np import pandas as pd import category_encoders as ce
Python
복사

변수 유형

종류

종류
Norminal Encoding : 순서 정보가 없는 데이터
One hot Encoding
Mean Encoding
Ordinal Encoding : 순서 정보가 있는 데이터
Label Encoding
Target Encoding
Ordinal Encoding
예)
순서정보가 있는 데이터: 과목 성적, 영화 평점...
순서정보가 없는 데이터: 성별, 혈액형....

Norminal Encoding

One hot Encoding

feature 값의 유형에 따라 새로운 feature를 추가해 고유 값에 해당하는 column에만 1을 표시, 나머지 column에만 1을 표시, 나머지 column에는 0을 표시하는 방식
즉, 행 형태로 되어있는 feature의 고유 값을 열 형태로 차원을 변환함
→ 고유값에 해당하는 column에만 1, 나머지 column에는 0을 표시
One-Hot Encoding은 sklearn에서 OneHotEncoder Class로 쉽게 변환 가능
주의
OneHotEncoder로 변환하기 전에 모든 문자열 값이 숫자형 값으로 변환되어야 함 (LabelEncoder가 선행되는 것)
입력 값으로 2차원(매트릭스) 데이터가 필요함
0은 학습에 도움이 안됌
피처의 항목이 많은 경우 차원의 저주에 빠질 수 있다.
category_encoders을 이용한 인코딩
encoder = ce.OneHotEncoder(use_cat_names=True) # 인코딩 객체 만들어짐. df_encoded = encoder.fit_transform(df) # 인코딩 객체가 fit, transform.... df_encoded.head() # transform 결과 보기
Python
복사

get_dummies = 손쉬운 버전의 One-Hot Encoding

pandas의 get_dummies : One-Hot Encoding을 더 쉽게 제공
LabelEncoding 과정을 거칠 필요 없이 (문자열 카테고리 값을 숫자 형으로 변환할 필요 없이) 즉시 사용 가능
df = pd.DataFrame(data) pd.get_dummies(df)
Python
복사

Mean Encoding

각 카테고리의 값을 학습 데이터의 target 값의 평균값으로 설정하는 것
카테고리형 피처가 매우 많은 종류의 카테고리를 가지고 있을 때
One-Hot 인코딩을 할 경우 새로운 컬럼이 너무 많이 생기게 되고 High Cardinality Feature를 모델에 너무 불균형하게 중요하게 만들어 Column Sampling 과정에 안 좋은 영향을 끼치게 된다.
그리고 보통 Feature Engineering 과정에서 Feature들을 서로 결합해 새로운 Feature를 생성하는데 이때, 새로운 High Cardinality Feature가 생성되게 만든다.
그렇기 때문에 High Cardinality 카테고리형 피처를 숫자형으로 인코딩하기 위해 적합한 인코딩 방법이 필요하고 그것이 바로 Mean target 인코딩이다.
주의
구분이 명확하진 않다.
과적합(Overfitting): Mean Target 인코딩은 타겟 값에 대한 정보를 직접적으로 사용하기 때문에, 모델이 훈련 데이터에 과도하게 적응하는 과적합의 위험이 있습니다. 이를 방지하기 위해 교차 검증(Cross-validation)이나 스무딩(Smoothing) 같은 기법을 적용할 수 있다.
해결 방법
교차 검증: Mean Target 인코딩을 적용할 때, 훈련 데이터를 여러 개의 폴드로 나누고 각 폴드의 평균을 사용하여 다른 폴드의 값을 인코딩한다.
스무딩: 작은 샘플 크기에서의 노이즈를 줄이기 위해, 범주형 변수의 평균을 전체 타겟 평균과 결합하여 스무딩된 값을 사용한다.

Mean Encoding vs Label Encoding

Mean Target 인코딩:
원리: 범주형 변수의 각 카테고리 값에 대해 해당 카테고리에 속하는 데이터의 타겟 값(예측하려는 목표 변수)의 평균을 계산하여, 그 평균 값으로 해당 카테고리를 수치화하는 기법
예시:
product_type이라는 범주형 변수가 있고, 이 변수의 값으로 "A", "B", "C"가 있다고 가정할 때, 각 제품 유형에 대해 판매 여부(0 또는 1)를 예측하려고 한다면, 각 제품 유형에 해당하는 판매 여부의 평균값을 계산하여 그 값으로 product_type 변수를 인코딩한다.
"A" 유형의 10개의 제품 중 7개가 판매되었다면, "A"는 0.7로 인코딩된다.
장점
이 기법은 타겟 값과 직접적으로 연관된 정보를 반영하기 때문에, 모델이 카테고리와 타겟 사이의 관계를 더 잘 학습할 수 있다.
이로 인해 인코딩된 값들이 less bias(적은 편향성)를 가지게 된다.
Label 인코딩:
원리: 범주형 변수의 각 카테고리 값을 고유한 정수로 변환하는 기법입니다.
예시:
product_type 변수가 "A", "B", "C"라는 값을 가진다면, "A"는 0, "B"는 1, "C"는 2로 인코딩됩니다.
단점
Label 인코딩의 경우, 변환된 정수 값이 순서를 가지게 되어, 모델이 이 순서를 실제 의미가 있는 것으로 해석할 수 있다.
이로 인해 선형 회귀와 같은 모델에서 문제를 일으킬 수 있다.
예를 들어, 모델은 "A" (0)가 "B" (1)보다 작고, "B"는 "C" (2)보다 작다는 잘못된 가정을 하게 됩니다.

Ordinal Encoding

훈련 데이터에 나타나는 범주값들을 (사전순으로 정렬한 뒤) 서수로 변환 (0, 1, 2, …)

Label Encoding

n개의 범주형 데이터를 0부터 n-1까지의 연속적 수치 데이터로 표현하는 것
인코딩 결과가 수치적인 차이를 의미하진 않음.
레이블 인코딩은 문자열 값을 숫자형 카테고리 값으로 변환해주는 것
이를 ML알고리즘에 적용할 경우 예측 성능이 떨어지는 경우가 있어 선형 회귀 등의 알고리즘에는 적용하지 않음
주로 트리 계열의 알고리즘에서 사용
data = {'column': ['Btech', 'Masters', 'High School', 'PHD']} df = pd.DataFrame(data) df.head()
Python
복사

sklearn을 이용한 인코딩

from sklearn.preprocessing import LabelEncoder
Python
복사
encoder = LabelEncoder() df['column_encoded'] = encoder.fit_transform(df['column']) df.head()
Python
복사
df['column'].unique() # array(['Btech', 'Masters', 'High School', 'PHD'], dtype=object) encoder.classes_ # array(['Btech', 'High School', 'Masters', 'PHD'], dtype=object) encoder.inverse_transform([0,1]) # array(['Btech', 'High School'], dtype=object)
Python
복사

Target Encoding

해당 Category에 나타난 Target Variable의 평균을 이용해서 Categorical Values를 대체하는 방식
범주형 변수의 각각의 범주를 타겟 변수의 특정 통계치, 예를 들어 타겟값 평균으로 변환하는 방식
다음과 같은 genre 카테고리 별 이진 target 값을 갖는 데이터 셋이 있을때
"Sci Fi" genre에 대한 인코딩 값은 ("Sci Fi" genre 중 target이 1인 수) / ("Sci Fi" genre 수), 즉, 1/5이 된다.
import pandas as pd import numpy as np np.random.seed(123) target = list(np.random.randint(0, 2, 20)) genres = ["Sci Fi", "Drama", "Romance", "Fantasy", "Nonfiction"] genre = [genres[i] for i in np.random.randint(0, len(genres), 20)] df = pd.DataFrame({"genre": genre, "target": target}) df
Python
복사
기존 데이터셋과 합친 모습
categories = df['genre'].unique() targets = df['target'].unique() cat_list = [] for cat in categories: aux_dict = {} aux_dict['category'] = cat aux_df = df[df['genre'] == cat] counts = aux_df['target'].value_counts() aux_dict['count'] = sum(counts) for t in targets: aux_dict['target_' + str(t)] = counts[t] if t in counts else 0 cat_list.append(aux_dict) cat_df = pd.DataFrame(cat_list) cat_df['genre_encoded_prob'] = cat_df['target_1'] / cat_df['count'] cat_df
Python
복사

Smoothing 처리

평균값은 각각의 범주 단위로 계산되는데, 해당 범주 개수가 적을 경우 극단적으로 0 또는 1에 가깝게 나올 수 있다.
이를 완화하기 위해 전체 평균값을 일정 비율 섞을 수 있는데, 이를 smoothing이라고 한다.
smoothing 정도를 결정하는 αα 파라미터를 사용하여 다음과 같이 계산이 가능하다.
encoding=αp(t=1x=ci)+(1α)p(t=1)encoding = \alpha \cdot p(t=1|x=c_i) + (1-\alpha)\cdot p(t=1)
α\alpha값은 보통 다음 값을 사용
α=11+enkf\alpha = \cfrac{1}{1 + e^{-\frac{n-k}{f}}}
f: smoothing_factor
k: min_samples_leaf
smoothing_factor = 1.0 # The f of the smoothing factor equation min_samples_leaf = 1 # The k of the smoothing factor equation prior = df['target'].mean() smoove = 1 / (1 + np.exp(-(stats['count'] - min_samples_leaf) / smoothing_factor)) smoothing = prior * (1 - smoove) + stats['mean'] * smoove encoded = pd.Series(smoothing, name = 'genre_encoded_smoothing') df4 = df3.join(encoded, on='genre') df4
Python
복사