Machine Learning/Basic

Categorical Feature

바나나인간 2020. 7. 25. 20:47

범주형 피쳐라는 것은 성별(남, 여), 혈액형 (A, B, AB, O) 등과 같이 유한한 선택 범위의 값을 취하는 피쳐다.

이러한 범주형 피쳐는 반드시 수치형 피쳐로 전환을 해야 분석 작업이 가능해진다.

 

1. Ordinal encoding

클래스 사이에 대소관계가 존재하는 데이터에서 사용할 수 있다.

예를 들어, 성적 클래스가 [낮음, 중간, 높음]으로 나눠질 때, 이 클래스는 "높음 > 중간 > 낮음"과 같은 순서형 관계를 가진다.

따라서 순서에 따라 수치 ID를 부여하여 다음과 같이 표현할 수 있다.

{"높음":3, "중간":2, "낮음":1}

 

2. One-hot encoding

원-핫 인코딩은 클래스 사이에 대소관계가 존재하지 않을 때 사용한다.

예를 들어, 형액형은 네 가지의 값을 가질 수 있는데, 이를 4차원의 sparse vector로 표현할 수 있다.

{"A":[1, 0, 0, 0], "B":[0, 1, 0, 0], "C":[0, 0, 1, 0], "D":[0, 0, 0, 1]}

 

import numpy as np

sent = "이순신 은 조선 중기 의 무신 이 다 . 이순신 은 조선 과 일본 과 의 전쟁 을 승리 로 이끌 었 다 ."
tokens = sent.strip().split(' ')
vocabs = sorted(set(tokens))

num_tokens = len(tokens)
vocab_size = len(vocabs)
print('num_tokens:', num_tokens)
print('vocab_size:', vocab_size)
onehot_vectors = np.zeros((num_tokens, vocab_size), int)

for i, word in enumerate(tokens):
    onehot_vectors[i, vocabs.index(word)] = 1
    print(word, '\t:\t', onehot_vectors[i])

>>

num_tokens: 24
vocab_size: 17
이순신  :        [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
은      :        [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
조선    :        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]
중기    :        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]
의      :        [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
무신    :        [0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0]
이      :        [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
다      :        [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
.       :        [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
이순신  :        [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
은      :        [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
조선    :        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]
과      :        [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
일본    :        [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]
과      :        [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
의      :        [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
전쟁    :        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
을      :        [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0]
승리    :        [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
로      :        [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0]
이끌    :        [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
었      :        [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]
다      :        [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
.       :        [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

 

원-핫 벡터를 통해 만들 때는 차원의 저주에 빠지는 경우를 조심해야 한다.

고차원의 벡터는 다양한 문제를 야기할 수 있다.

먼저, 고차원 공간하의 두 점 사이의 거리는 측정이 매우 어려워질 수 있다.

또한, 모델의 파라미터의 개수는 차원이 증가함에 따라 함께 증가하게 되며, 과적합 문제를 일으킬 수 있다.

마지막으로 모든 차원이 분류나 예측에 도움이 되는 것은 아니다. 따라서 피쳐의 선택과 함께 차원의 수를 효과적으로 줄일 수 있는 방법이 필요하다.

 

3. Binary encoding

Binary encoding은 각 클래스에 ID를 부여하고, 해당 ID를 이진법으로 표현하는 것이다.

import numpy as np

blood_type = ["A", "B", "AB", "O"]
max_binary_len = len("{0:b}".format(len(blood_type)))

for i, type_ in enumerate(blood_type):
    binary = "{0:b}".format(i)
    filled_binary = binary.zfill(max_binary_len)
    print(type_, "\t:\t", filled_binary)

>>

A       :        000
B       :        001
AB      :        010
O       :        011

 

결과적으로 0/1으로 이루어진 고유 벡터를 얻을 수 있으며, 차원의 수는 원-핫 인코딩보다 작아 저장 공간을 절약할 수 있다.