본문 바로가기
데이터 분석/데이터 전처리

[Numpy] 원-핫 인코딩(One-Hot Encoding) 간단하게 해보기 (feat. eye)

by 부자 꽁냥이 2023. 4. 16.

안녕하세요~ 꽁냥이에요. 데이터 전처리시 범주형 변수가 있는 경우 이를 One-Hot Encoding으로 변환하는 경우가 많은데요. Numpy에서 제공하는 eye 함수를 이용하면 One-Hot Encoding을 쉽게 할 수 있는데요. 이번 포스팅에서는 Numpy를 이용한 One-Hot Encoding 방법을 알아보고 나만의 One-Hot Encoder를 만들어보는 방법에 대해서 알아보겠습니다.


   원-핫 인코딩(One-Hot Encoding) 구현

1) numpy를 이용한 One-Hot Encoding : eye

만약 범주가 0부터 시작하는 숫자로 되어 있는 경우 Numpy의 eye 함수를 이용하여 One-Hot Encoding을 할 수 있습니다.

 

eye 함수는 숫자를 인자로 받고 해당 숫자만큼의 행을 갖는 단위행렬을 생성합니다. 예를 들어 아래 코드는 3X3 단위행렬을 생성합니다.

 

import numpy as np

np.eye(3)

 

array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

 

그렇다면 eye 함수를 이용하여 어떻게 원-핫 인코딩을 할 수 있을까요? 원-핫 인코딩은 유니크한 범주의 개수를 모두 0으로 세팅한 뒤 해당 범주에 해당하는 원소만 1로 인코딩합니다. 앞에서 우리는 범주가 0부터 시작하는 숫자로 표현되어 있다고 가정했습니다. 그러면 범주를 원소가 1인 위치로 생각해볼 수 있습니다.

 

이러한 원리를 이해했다면 eye 함수를 이용한 원-핫 인코딩 변환 과정을 두 단계로 나누어 생각해 볼 수 있을 것입니다. (1) 유니크한 범주 개수에 대응하는 단위행렬을 만들고 (2) 범주에 대응하는 행을 추출하면 되는 것입니다. 아래 그림은 이러한 과정을 나타낸 것입니다.

이제 코딩을 통하여 알아보겠습니다. 아래 코드는 0부터 시작하는 숫자로 이루어진 범주에 대한 원-핫 인코딩을 위와 같은 과정에 따라 구현한 것입니다.

 

category_var = [0, 1, 0, 2, 2, 1, 1]

num_category = len(np.unique(category_var)) ## 유니크 범주 개수
identity_mat = np.eye(num_category) ## 단위 행렬
one_hot_encoding_mat = identity_mat[category_var] ## 범주에 대응하는 행 추출
one_hot_encoding_mat

 

array([[1., 0., 0.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 1., 0.]])

 


2) 나만의 One-Hot Encoder 만들어보기

앞에서 설명한 eye를 이용하는 방법은 0부터 시작하는 숫자로 이루어진 범주이어야 하며 또한 중간에 점프가 있으면 안됩니다. 예를 들어 0, 1, 3, 4와 같이 1과 3 사이에 2가 없다면 eye 함수를 이용하여 원-핫 인코딩을 할 수 없습니다.

 

또한 원-핫 인코딩을 이용한 행렬을 다시 원 범주로 바꿀 필요가 있을 것입니다. 따라서 좀더 일반적인 원-핫 인코딩을 수행하고 원 범주로 되돌려주는 기능을 포함하는 나만의 원-핫 인코더를 만들어보겠습니다. 

 

아래 코드에서 myOneHotEncoder는 fit 메서드를 통해 범주와 원-핫 인코딩을 서로 변환할 수 있도록 매핑 딕셔너리를 만들어줍니다. 그리고 transform을 통해서는 범주를 원-핫 인코딩으로 변환하고 inverse_transform은 원-핫 인코딩을 원래의 범주로 되돌려 줍니다. 이때 transform에서는 drop인자를 통하여 특정 범주에 대응하는 칼럼을 제외할 수 있도록 했습니다.

 

class myOneHotEncoder:
    def __init__(self):
        self.categories = None
        self.mapping = None
        self.inverse_mapping = None
        
    def fit(self, dummy_col): ## 매핑 생성
        categories = np.unique(dummy_col)
        self.categories = categories
        self.mapping = dict(zip(categories, range(len(categories))))
        self.inverse_mapping = dict(zip(range(len(categories)), categories))
        return self
    
    def transform(self, dummy_col, drop=None): ## 범주 -> 원-핫 인코딩
        dummy_col = dummy_col.tolist()
        dummy_col_idx = [self.mapping[x] for x in dummy_col]
        num_category = len(np.unique(self.categories))
        dummy_mat = np.eye(num_category)[dummy_col_idx]
        
        if drop is not None:
            drop_idx = self.mapping[drop]
            dummy_mat = np.delete(dummy_mat, drop_idx, axis=1)
        return dummy_mat
    
    def inverse_transform(self, dummy_mat): ## 원-핫 인코딩 -> 범주
        dummy_to_idx = np.argmax(dummy_mat, axis=1)
        dummy_col = [self.inverse_mapping[x] for x in dummy_to_idx]
        return dummy_col

 

이제 꽁냥이가 만든 원-핫 인코더를 통해 실제 원-핫 인코딩을 해보겠습니다. 여기서는 붓꽃 데이터의 붓꽃 타입을 범주형 변수로 사용하겠습니다.

 

import numpy as np
from sklearn.datasets import load_iris

iris = load_iris()
category = np.array([iris.target_names[x] for x in iris.target])

np.unique(category)

 

category에는 다음과 같이 setosa, versicolor, virginica라는 3개의 범주가 있습니다.

 

 

이제 myOneHotEncoder로 원-핫 인코딩을 수행해 보겠습니다.

 

encoder = myOneHotEncoder().fit(category) ## 매핑 생성
encoder.transform(category) ## 원-핫 인코딩 변환

 

코드를 실행하면 다음과 같이 원-핫 인코딩이 잘된 것을 알 수 있습니다.

array([[1., 0., 0.],
       [1., 0., 0.],
       [1., 0., 0.],
       [1., 0., 0.],
       '''중략'''       
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 0., 1.]])

 

이번엔 원-핫 인코딩으로 변환된 것을 원래의 범주로 변환해 보겠습니다.

 

dummy_mat = np.array([[1., 0., 0.],
                       [1., 0., 0.],
                       [1., 0., 0.],
                       [0., 1., 0.],
                       [1., 0., 0.],
                       [1., 0., 0.],
                       [0., 1., 0.],
                       [0., 0., 1.],
                       [0., 0., 1.],
                       [0., 0., 1.]])
encoder.inverse_transform(dummy_mat)

 

['setosa',
 'setosa',
 'setosa',
 'versicolor',
 'setosa',
 'setosa',
 'versicolor',
 'virginica',
 'virginica',
 'virginica']

 

보시는 바와 같이 원래의 범주로 변환이 잘된 것을 알 수 있습니다.


이번 포스팅에서는 Numpy eye 함수를 이용한 원-핫 인코딩(One-Hot Encoding) 변환 방법과 나만의 인코더를 만드는 방법을 알아보았습니다. 원-핫 인코딩은 예측 모델에서 학습 데이터를 만들 때 많이 사용되므로 알아두시면 좋습니다. 부디 이번 포스팅이 많은 분들께 도움이 되시길 바라며 이상 포스팅 마치겠습니다. 안녕히 계세요~


댓글


맨 위로