인공지능-기계학습/언어인지_NLP

원 핫 인코딩? One-Hot Encoding?

The Yellow Lion King 2022. 4. 24. 23:00
반응형

주요내용

  • One-hot Encoding 이란?
  • 왜? 원핫 인코딩이 필요한가?
  • 어떻게 하나?
  • 장점 및 단점
  • 파이썬에서의 구현 방법

 

One-hot Encoding 이란?

먼저 위키피디아에 따르면 One-hot 을 아래와 같이 정의하고 있습니다.

A one-hot is a group of bits among which the legal combinations of values are only those with a single high (1) bit and all the others low (0).

 

Bit - Wikipedia

Unit of information The bit is the most basic unit of information in computing and digital communications. The name is a portmanteau of binary digit.[1] The bit represents a logical state with one of two possible values. These values are most commonly repr

en.wikipedia.org

즉, 비트 들의 모임 중 하나만 1이고 나머지는 모두 0인 비트 들의 그룹을 원핫(One-hot)이라고 합니다. 

그럼 인코딩(Encoding)이란 무엇일까요? 인코딩은 부호화라는 의미로 위키피디아에서는 아래와 같이 말하고 있습니다.

인코딩(encoding)은 컴퓨터를 이용해 영상 · 이미지 · 소리 데이터를 생성할 때 데이터의 양을 줄이기 위해 데이터를 코드화하고 압축하는 것이다.

 쉽게 말하면 데이터를 압축/변형 하는 것은 인코딩, 이 압축/변형된 데이터를 원형으로 변환하는 것을 디코딩(Decoding)이라고 합니다.  

그래서 원핫과 인코딩을 합친 One-hot Encoding(원핫 인코딩)이란

데이터를 One-hot 데이터 형태로 변형/압축하는 것

을 말합니다. 여기서 데이터는 이미지 데이터가 될 수도 있고 텍스트 데이터나 카테고리(범주형) 데이터가 될 수도 있습니다. 

 

 

왜? 원핫 인코딩이 필요한가?

일반적인 인코딩은(부호화는) 정의에서 나온 것처럼 변형하거나 압축이 필요할 때 사용됩니다. 복잡하고 긴 이름이나 내용을 특정 규칙에 따라 변형 또는 매핑하여 축소할 때 효과적입니다. 파일 압축을 생각해보세요. 메일이나 메신저를 사용해서 용량이 큰 이미지나 동영상 파일을 전송할때 생각해보세요. 그냥 전송하는 것보다는 압축한 파일을 전송하는 것이 훨씬 빠르고 안정적입니다. 이처럼 원핫 인코딩의 경우에도 복잡한 데이터를 그대로 사용하지 않고 컴퓨터가 처리하기 쉽게 숫자로 변형해 주는 것입니다. 이렇게 함으로써 데이터를 처리하기 위해 필요한 메모리 양을 줄일 수 있고 처리를 빠르게 할 수 있습니다. 게다가 대부분의 통계나 머신러닝 모델들은 입력 데이터로 숫자값을 기본으로 합니다. 그래서 특히, 범주형 데이터를 원핫 인코딩해서 사용하는 경우가 많이 있습니다. 예를 들어서 주택 데이터 셋 중에서 주택 유형이라는 피처(데이터 항목)이 있고 이 항목의 실제 값들은 '아파트', ''연립주택', '다세대주택', '단독주택', '다중주택', '다가구주택', '기타' 로 구성되어있다고 하겠습니다. 이러한 값들을 그대로 모델의 입력값으로 사용할 수 없기 때문에 숫자로 바꾸어주는 것이 필요합니다. 그래서 이 법주형 데이터를 원핫 인코딩으로 변환할 경우, '아파트'는 '100000'으로 '연립주택'은 '010000'으로 변환되어 사용될 수 있습니다. 이렇게 원핫 인코딩된 값들은 분석 모델의 인풋 데이터로 사용할 수 있습니다. 

 

 

어떻게 하나?

방법은 간단합니다. 범주형의 종류 개수(n) 크기의 벡터를 0으로 초기화하고, 특정 범주를 나타내기 위해 특정 위치의 값을 1로 설정하는 것 입니다. 위의 예에서도 잠깐 살펴본 주택 데이터 셋 예를 더 자세히 알아보겠습니다.  주택 유형이라는 범주형 데이터의 전체 범주 개수가 6개인 경우 벡터의 크기는 6이 됩니다. 이 벡터를 리스트로 표현하면 [0,0,0,0,0,0]이 됩니다. 크기가 6인 0벡터 이지요. 첫번째 범주인 '아파트'를 원핫 인코딩해보면 [1,0,0,0,0,0]로 나타 낼 수 있습니다. 첫번째 위치 값을 1로 설정하고 나머지는 모두 0인 원핫 벡터가 되었습니다. 다른 범주값까지 모두 원핫 인코딩 한 결과는 아래와 같습니다.

 

장점 및 단점

장점은 어떻게 인코딩/디코딩 되는지 쉽게 이해할 수 있다는 것 입니다. 구현도 쉽고 작은 데이터 셋에서 빠르게 동작한다는 장점이 있습니다.

단점은 범주가 추가되면 데이터의 크기가 바뀐다는 것입니다. 위에서 주택유형을 입력으로 쓰기 위해 6자리의 원핫 벡터로 인코딩해서 사용중이었는데 예를들어 전원주택 같은 새로운 주택유형이 하나 추가되면 7자리의 벡터로 바꾸어서 사용해야한 다는 것입니다. 이 말은 기존에 만들었던 모델이나 알고리즘에 변형이 필요하다는 의미 입니다. 매우 큰 변화이지요. 이처럼 향후의 확장성을 고려하여 더미 범주를 추가해서 인코딩하거나 해싱을 이용해서 인코딩 하기도 합니다. 이러한 문제를 OOD(Out Of Dictionary) 라고도 합니다. 예측이나 추론을 위해 원핫 인코딩을 실행했는데 모델이나 알고리즘을 개발할때에는 없던 새로운 범주가 입력되는 경우 인코딩 할 수 없어서 발생하는 에러를 말합니다.

정보저장을 위해 희소 벡터(Sparse Vector)를 사용하기 때문에 정보가 없는 공간에 대해서도 관리가 필요하게 되어서 메모리의 낭비가 발생한다는 것입니다.  위의 주택 유형 예에서 '아파트'를 '100000'으로 인코딩하면 첫번째 1만 값이 있고 나머지는 위치는 모두 정보가 없는 0이 차지하기 때문에 메모리 낭비가 발생하는 것입니다.

또 다른 단점은 범주형 데이터가 순서나 크기의 의미를 포함하고 있을 때 원핫 인코딩을 하게되면 이러한 정보들은 사용할 수 없게된다는 것입니다. 예를 들면 월요일, 화요일, 수요일, 목요일, 금요일, 토요일, 일요일을 원핫 인코딩하면 그저 0과 1일 집합으로 표현됩니다. 월요일은 [1,0,0,0,0,0,0], 토요일은 [0,0,0,0,0,1,0], 일요일은 [0,0,0,0,0,0,1] 이렇게 되겠지요. 이렇게 인코딩된 값들은 요일간에 순서나 크기를 표현하지 못합니다. 반면에 레이블 인코딩의 경우 일요일은 0, 월요일은 1, 화요일은 2, 수요일은 3, 목요일은 4, 금요일은 5, 토요일은 6으로 인코딩하면 요일간의 연계성 정보를 인코딩한 숫자에서도 찾을 수 있습니다. 즉, 수요일 3 다음에는 목요일 4라는 것을 알수 있지요. 이렇게 되면 5보다 큰 수가 의미를 갖을 수도 있습니다. 

 

 

파이썬에서의 구현 방법

원핫 인코딩은 통계, 기계학습, 머신러닝, 딥러닝 등 쓰이는 범위가 넓습니다. 그래서 원핫 인코딩 기능은 여러 프레임웍과 페키지에서 제공하고 있습니다.  아래는 scikit-learn 패키지에서 구현한 예시 내용입니다. 

# scikit-learn에서 필요한 모듈을 가져옵니다.
from sklearn.preprocessing import OneHotEncoder

# 프로그램에서 사용할 인스턴스를 하나 만듭니다.
one_hot_encoder = OneHotEncoder()

# 데이터 셋에서 범주형 데이터 항목의 값들을 인코더의 입력값 X로 설정 합니다.
X = [['Apple'], ['Banana'], ['Cherry'], ['Date'], ['Egg'], ['Apple'], ['Cherry'], ['Cherry']]
print('데이터 항목 X: ', X)

# 데이터 X를 이용해서 one hot encoding을 적용 실행
one_hot_encoder.fit(X)

# 인코딩된 카테고리들의 내용을 확인해 보는 명령어
categories = one_hot_encoder.categories_
print('범주 categories: ', categories)

# 특정 범주(여기서는 'Apple', X[0])에 해당하는 원핫 벡터를 찾아보는 명령어
one_hot_vector_for_alpha = one_hot_encoder.transform([X[0]]).toarray()
print('Apple를 인코딩한 값(벡터): ', one_hot_vector_for_alpha)

# 특정 원핫 벡터(여기서는 'Apple'의 원핫 벡터 [[1. 0. 0. 0. 0.]])에 해당하는 범주 Category를 찾는 명령어
category_for_one_hot_vector = one_hot_encoder.inverse_transform(one_hot_vector_for_alpha)
print('Apple 인코딩 벡터를 이용해서 찾은 범주 이름: ', category_for_one_hot_vector)

print('\n모든 범주와 원핫 인코딩을 출력 합니다.')
for category in one_hot_encoder.categories_[0]:
    print(category,': \t', one_hot_encoder.transform([[category]]).toarray())

위의 내용을 실행하기 전에 pip install sklearn 명령을 통해 scikit-learn 패키지를 설치해 주어야 합니다. 아래는 패키지를 설치하고 위의 내용을 파일로 저장후 실행한 결과 입니다.

데이터 항목 X: [['Apple'], ['Banana'], ['Cherry'], ['Date'], ['Egg'], ['Apple'], ['Cherry'], ['Cherry']]
범주 categories: [array(['Apple', 'Banana', 'Cherry', 'Date', 'Egg'], dtype=object)]
Apple를 인코딩한 값(벡터): [[1. 0. 0. 0. 0.]]
Apple 인코딩 벡터를 이용해서 찾은 범주 이름: [['Apple']]

모든 범주와 원핫 인코딩을 출력 합니다.
Apple :    [[1. 0. 0. 0. 0.]]
Banana : [[0. 1. 0. 0. 0.]]
Cherry :  [[0. 0. 1. 0. 0.]]
Date :      [[0. 0. 0. 1. 0.]]
Egg :       [[0. 0. 0. 0. 1.]]

 

 

요약

원핫 인코딩이 무엇인지에 대해서 알아보았고, 왜필요한지, 그리고 어떻게 구현할 수 있는지에 대해서 알아보았습니다. 이렇게 인코딩된 데이터를 이용하여 분석하거나 머신러닝 모델에서 입력 값으로 사용할 수 있습니다. 위에서 보신 것 처럼 Apple을 모델에서는  [[1. 0. 0. 0. 0.]]로 입력 받아 처리합니다. 결과 값을 분류하는 경우, 즉 과일 이름 중에 하나가 결과로 나와야하는 경우에는 역으로  [[1. 0. 0. 0. 0.]]로 나온 모델의 결과 값을 다시 'Apple' 로 바꾸어주는 것이 필요합니다. 이처럼 원핫 인코딩/디코딩은 범주형 데이터의 변환에 많이 쓰입니다. 

 

반응형