데이터 인코딩 (Data encoding)
머신러닝 알고리즘에서는 문자열 데이터를 사용할 수 없으므로 모든 데이터를 숫자로 표현해야 한다. 범주형 데이터를 다루기 위해서는 모두 숫자값으로 변환해야 한다. 대부분의 머신러닝 라이브러리 또한 범주형 자료형이 정수로 인코딩 되어 있을 것으로 기대한다. 따라서 범주형 자료의 인코딩 방법을 정리해본다.
1. map을 이용한 인코딩
인코딩 값을 부여하는 순서가 중요한 경우에 사용한다. 이밖에 인코딩 방법들은 우열을 표현하지 못하거나 숫자, 알파벳, 한글 순으로 순서가 정해져 있으므로 직접 번호를 부여하는 map 방식도 자주 사용된다. dacon 집값 예측 데이터 셋 중에 Kitchen Qual 피처를 통해 실습한다.
import pandas as pd
df = pd.read_csv('C:/Users/Jay/Desktop/dacon/housing/train.csv')
df.head(10)
df['Kitchen Qual'].value_counts()
kitchen_qual_map = {
'Fa': 0,
'TA': 1,
'Gd': 2,
'Ex': 3
}
df['Kitchen Qual'] = df['Kitchen Qual'].map(kitchen_qual_map)
df['Kitchen Qual'].head(10)
df.head(10)
2. 사이킷런 LableEncoder 클래스
- fit_transform : fit과 transform 메서드의 결합으로 인코딩 명령어 / 1차원 array 형식만 넣을 수 있음
- classes_ : 인코딩 클래스
- inverse_transform : 디코딩 원본값으로 반환
- 인코딩 순서는 숫자, 알파벳, 한글 순이다.
from sklearn.preprocessing import LabelEncoder
colors = ['152','Red','주황','Yellow','초록','Gray','검정',]
encoder = LabelEncoder() # 객체 생성
labels = encoder.fit_transform(colors)
print('인코딩 변환값 :', labels)
print('인코딩 클래스:', encoder.classes_)
print('디코딩 원본 값:', encoder.inverse_transform([0,2,5,3,6,1,4]))
데이터 프레임에 적용
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder() # 객체 생성
df_wine['type'] = encoder.fit_transform(df_wine['type'])
df_wine.head()
3. pandas pd.factorize()
- 열거된 유형 또는 범주형 변수로 개체를 인코딩
- pd.factorize()[0] : 0부터 인코딩
df['Drug'] = pd.factorize(df['Drug'])[0]
df
원-핫 인코딩 (One-Hot Encoding)
범주형 변수가 여러 개인 경우 인코딩 시에 0,1,2,3... 등으로 인코딩된다. 그런데 이 때, 인코딩한 정수들은 ML 알고리즘이나 라이브러리에서 순서를 가지는 변수로 취급될 수 있다. 서로 순서나 우열이 있는 데이터로 취급될 경우 잘못된 학습을 하거나 예측성능이 저하되는 문제가 발생할 수 있다. 따라서 0과 1만 가지고 피처 값의 유형에 따라 새로운 피처를 추가해 인코딩하는 방식이다.
원핫 인코딩시 범주의 분류 갯수 만큼 새로운 컬럼이 생기는데 이 때 피처 수가 증가하므로 다중 공선성 문제가 발생할 수 있다. 따라서 피처의 갯수를 적절히 조절할 수 있도록 하나의 컬럼을 삭제하는 등의 조치가 필요하다.
4. pandas pd.get_dummies()
- pandas에서의 원핫 인코딩 함수
colors = ['152','Red','주황','Yellow','초록','Gray','검정',]
pd.get_dummies(colors)
pd.get_dummies(df, drop_first='True')
위와 같이 원핫 인코딩으로 피처 수가 증가하는 경우 다중 공선성 문제가 발생할 수 있다. 따라서 drop_first로 각 범주형 항목의 첫번째 컬럼을 삭제하였다. (Sex_F, BP_HIGH, Cholesterol_HIGH, Drug_A 컬럼 삭제)
5. 사이킷런에서의 원핫 인코딩
- sklearn.preprocessing OneHotEncoder, numpy 이용
sklearn의 원핫 인코딩은 상대적으로 복잡하다. 먼저 숫자값으로 변환하기 위해 LabelEncoder로 변환하고 reshape 함수를 적용하여 2차원 데이터로 변환한다. 이후 원핫 인코딩을 진행한다.
from sklearn.preprocessing import OneHotEncoder
import numpy as np
colors = ['152','Red','주황','Yellow','초록','Gray','검정',]
# 첫번째, 먼저 숫자값으로 변환을 위해 LabelEncoder로 변환
encoder = LabelEncoder()
encoder.fit(colors)
labels = encoder.transform(colors)
labels
# 두번째, 2차원 데이터로 변환
labels = labels.reshape(-1, 1)
labels
# 마지막으로 원-핫 인코딩을 적용
oh_encoder = OneHotEncoder()
oh_encoder.fit(labels)
oh_labels = oh_encoder.transform(labels)
print('원-핫 인코딩 데이터')
print(oh_labels.shape)
oh_labels.toarray()
6. keras에서의 원핫 인코딩
- tf.keras.utils.to_categorical(Y)
# 데이터 입력
df = pd.read_csv('./dataset/iris.csv', names = ["sepal_length", "sepal_width", "petal_length", "petal_width", "species"])
# 데이터 분류
dataset = df.values
X = dataset[:,0:4].astype(float)
Y_obj = dataset[:,4]
Y_obj
# 문자열을 숫자로 변환
e = LabelEncoder()
e.fit(Y_obj) # Y = e.fit_transform(Y_obj) 와 동일
Y = e.transform(Y_obj)
Y
Y_encoded = tf.keras.utils.to_categorical(Y) # 원핫 인코딩
Y_encoded