[ML] 라벨 인코딩과 원핫 인코더를 사용한 범주형 인코딩
많은 머신러닝 또는 데이터 과학 활동에서 데이터 세트는 텍스트 또는 범주형 값(기본적으로 숫자가 아닌 값)을 포함할 수 있습니다. 예를 들어 빨강, 주황, 파랑, 흰색 등의 값을 가진 색상 특징이 있습니다. 아침, 점심, 간식, 저녁, 차 등의 값을 포함하는 식사 계획. CATBOAST, 의사 결정 트리와 같은 일부 알고리즘은 범주형 값을 잘 처리할 수 있지만 대부분의 알고리즘은 숫자 값을 사용하여 최첨단 결과를 얻을 것으로 기대합니다.
AI와 머신러닝의 학습 곡선을 살펴보면 대부분의 알고리즘이 숫자 입력에 더 잘 작동한다는 것을 알 수 있습니다. 따라서 분석가가 직면한 주요 과제는 텍스트/카테고리 데이터를 숫자 데이터로 변환하면서도 이를 이해할 수 있는 알고리즘/모델을 만드는 것입니다. 딥러닝의 기반이 되는 신경망은 입력값이 숫자가 될 것으로 예상합니다.
범주형 값을 숫자 값으로 변환하는 방법에는 여러 가지가 있습니다. 각 접근 방식에는 고유한 장단점과 기능 세트에 미치는 영향이 있습니다. 여기서는 두 가지 주요 방법에 초점을 맞추겠습니다: 원핫 인코딩과 레이블 인코더입니다. 이 두 인코더는 모두 가장 널리 사용되는 Python 라이브러리 중 하나인 SciKit-learn 라이브러리의 일부이며 텍스트 또는 범주형 데이터를 모델이 예상하고 더 나은 성능을 발휘할 수 있는 수치 데이터로 변환하는 데 사용됩니다.
라벨 인코딩 (Label Encoding)
이 접근 방식은 매우 간단하며 열의 각 값을 숫자로 변환하는 것입니다. 열 이름이 bridge-types이고 아래 값이 있는 교량 데이터 집합을 예로 들어 보겠습니다. 데이터 세트에는 더 많은 열이 있지만, 레이블 인코딩을 이해하기 위해 하나의 범주형 열에만 초점을 맞추겠습니다.
BRIDGE-TYPE
Arch
Beam
Truss
Cantilever
Tied Arch
Suspension
Cable
아래와 같이 각 텍스트 값에 대해 실행 시퀀스를 넣어 텍스트 값을 인코딩하도록 선택합니다:
이것으로 가변 브리지 타입의 라벨 인코딩을 완료했습니다. 이것이 라벨 인코딩의 전부입니다. 하지만 데이터 값과 데이터의 종류에 따라 라벨 인코딩은 숫자 순서를 사용하기 때문에 새로운 문제가 발생합니다. 숫자를 사용하는 문제는 데이터 간의 관계/비교를 도입한다는 점입니다. 겉으로 보기에는 다양한 교량 유형 사이에 아무런 관계가 없지만, 숫자를 보면 ‘케이블(Cable)’ 교량 유형이 ‘아치(Arch)’ 교량 유형보다 우선순위가 높다고 생각할 수 있습니다. 알고리즘이 데이터에 0 < 1 < 2 … < 6의 계층/순서가 있다고 오해하여 계산 시 ‘Cable’ 교량 유형에 ‘Arch’ 교량 유형보다 6배 더 많은 가중치를 부여할 수 있습니다.
‘안전 수준(Safety Level)’이라는 다른 열을 고려해 보겠습니다. 이 열의 레이블 인코딩을 수행하면 숫자의 순서/우선순위가 유도되지만 올바른 방식으로 유도되지는 않습니다. 여기서는 숫자 순서가 이상하게 보이지 않으며 알고리즘이 안전도 순서를 0 < 1 < 2 < 3 < 4, 즉 없음(None) < 낮음(Low) < 중간(Medium) < 높음(High) < 매우 높음(Very-High)으로 해석하면 의미가 있습니다.
파이썬에서 라벨 인코딩 (Label Encoding in Python)
카테고리 코드 접근 방식 사용(Using category codes approach):
이 접근 방식을 사용하려면 카테고리 열이 ‘카테고리’ 데이터 유형이어야 합니다. 기본적으로 숫자가 아닌 열은 ‘객체’ 유형입니다. 따라서 이 접근 방식을 사용하기 전에 유형을 ‘카테고리’로 변경해야 할 수도 있습니다.
# import required libraries
import pandas as pd
import numpy as np
# creating initial dataframe
bridge_types = ('Arch','Beam','Truss','Cantilever','Tied Arch','Suspension','Cable')
bridge_df = pd.DataFrame(bridge_types, columns=['Bridge_Types'])
# converting type of columns to 'category'
bridge_df['Bridge_Types'] = bridge_df['Bridge_Types'].astype('category')
# Assigning numerical values and storing in another column
bridge_df['Bridge_Types_Cat'] = bridge_df['Bridge_Types'].cat.codes
bridge_df
sci-kit 학습 라이브러리 접근 방식 사용(Using sci-kit learn library approach):
많은 데이터 분석가가 라벨 인코딩을 수행하는 또 다른 일반적인 접근 방식은 SciKit 학습 라이브러리를 사용하는 것입니다.
import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder
# creating initial dataframe
bridge_types = ('Arch','Beam','Truss','Cantilever','Tied Arch','Suspension','Cable')
bridge_df = pd.DataFrame(bridge_types, columns=['Bridge_Types'])
# creating instance of labelencoder
labelencoder = LabelEncoder()
# Assigning numerical values and storing in another column
bridge_df['Bridge_Types_Cat'] = labelencoder.fit_transform(bridge_df['Bridge_Types'])
bridge_df
bridge_df with categorical caolumn and label-encoded column values
원핫 인코더 (One-Hot Encoder)
레이블 인코딩은 직선적이지만 알고리즘이 숫자 값을 일종의 계층/순서가 있는 것으로 잘못 해석할 수 있다는 단점이 있습니다. 이러한 순서 문제는 ‘원핫 인코딩’이라는 또 다른 일반적인 대안적 접근 방식으로 해결됩니다. 이 전략에서는 각 카테고리 값이 새 열로 변환되고 해당 열에 1 또는 0(참(True)/거짓(False)의 표기법)의 값이 할당됩니다. 원핫 인코딩을 사용한 교량 유형 및 안전 수준에 대한 이전 예를 살펴보겠습니다.
위는 범주형 열 ‘Bridge-Type’의 원핫 인코딩된 값입니다. 같은 방법으로 ‘Safety-Level’ 열을 확인해 보겠습니다.
첫 번째 열 값(Arch/None)이 있는 행은 ‘1’(True를 나타냄)이 되고 다른 값의 열은 ‘0’(False를 나타냄)이 됩니다. 마찬가지로 값과 열 값이 일치하는 다른 행의 경우에도 마찬가지입니다.
이 접근 방식은 계층/순서 문제를 해결하지만 데이터 집합에 더 많은 열을 추가해야 하는 단점이 있습니다. 카테고리 열에 고유 값이 많은 경우 열의 수가 크게 늘어날 수 있습니다. 위의 예제에서는 관리가 가능했지만, 인코딩으로 인해 열이 많아지면 관리가 매우 어려워집니다.
Python에서 원핫 인코딩 (One-Hot Encoding in Python)
sci-kit learn 라이브러리 접근 방식 사용:
SciKit 라이브러리의 OneHotEncoder는 숫자 범주형 값만 사용하므로 문자열 유형의 모든 값은 핫 인코딩 전에 레이블 인코딩을 해야 합니다. 따라서 이전 예제에서 데이터 프레임을 가져와서 Bridge_Types_Cat 열에 OneHotEncoder를 적용하겠습니다.
import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder
# creating instance of one-hot-encoder
enc = OneHotEncoder(handle_unknown='ignore')
# passing bridge-types-cat column (label encoded values of bridge_types)
enc_df = pd.DataFrame(enc.fit_transform(bridge_df[['Bridge_Types_Cat']]).toarray())
# merge with main df bridge_df on key values
bridge_df = bridge_df.join(enc_df)
bridge_df
데이터 프레임에서 ‘Bridge_Types_Cat’ 열을 삭제할 수 있습니다.
더미 값 접근 방식 사용:
이 접근 방식은 원하는 만큼 카테고리 열을 인코딩할 수 있고 접두사를 사용하여 열에 레이블을 지정하는 방법을 선택할 수 있으므로 더 유연합니다. 적절한 이름을 지정하면 나머지 분석이 조금 더 쉬워집니다.
import pandas as pd
import numpy as np
# creating initial dataframe
bridge_types = ('Arch','Beam','Truss','Cantilever','Tied Arch','Suspension','Cable')
bridge_df = pd.DataFrame(bridge_types, columns=['Bridge_Types'])
# generate binary values using get_dummies
dum_df = pd.get_dummies(bridge_df, columns=["Bridge_Types"], prefix=["Type_is"] )
# merge with main df bridge_df on key values
bridge_df = bridge_df.join(dum_df)
bridge_df
Bridge_Type values encoded using dummies approach
결론
범주형 변수를 인코딩하는 각 접근 방식에는 고유한 장단점이 있으므로 다양한 옵션을 이해하는 것이 중요합니다. 데이터 과학에서는 중요한 단계이므로 범주형 변수를 다룰 때 이러한 아이디어를 염두에 두는 것이 좋습니다.
댓글남기기