오늘은 머신 러닝을 위한 데이터 전처리 과정 중 2가지 인코딩 방식 - 라벨 인코딩(Label Encoding)과 원-핫 인코딩(One-Hot Encoding)에 대해 정리하는 포스트를 작성하도록 하겠습니다.
머신 러닝을 위한 데이터 중 많은 것들은 범주형 데이터로 분류할 수 있습니다. 그리고 이런 범주형 데이터를 처리하는 방법은 모델의 학습 방식과 결과에 직접적인 영향을 줍니다.
라벨 인코딩과 원-핫 인코딩은 범주형 데이터를 머신 러닝을 위해 숫자형 데이터로 변환하는 데 사용되며, 각각의 방법은 특정 상황에서 장점과 단점을 가집니다. 이를 이해하기 위해 seaborn의 타이타닉 데이터셋을 사용할 것입니다. 특히, embark_town
이라는 컬럼에 초점을 맞추어, 이 컬럼이 어떻게 각 인코딩 방식에 의해 변환되는지 살펴볼 것입니다.
embark_town
은 타이타닉호의 승객들이 탑승한 항구를 나타내는 컬럼으로, 범주형 데이터의 전형적인 예시입니다. 이 데이터를 활용하여 라벨 인코딩과 원-핫 인코딩이 각각 어떻게 적용되는지, 그리고 그 결과가 어떻게 다른지를 구체적으로 설명하겠습니다.
먼저, 머신 러닝 모델을 위한 데이터를 준비 하도록 하겠습니다. 이번 포스트에서 사용할 데이터셋은 seaborn 라이브러리의 타이타닉 데이터셋입니다. 타이타닉 데이터셋은 타이타닉호의 승객 정보를 담고 있으며, 여러 범주형 컬럼들을 포함하고 있습니다.
import seaborn as sns
# 타이타닉 데이터셋 로드
titanic = sns.load_dataset('titanic')
survived | pclass | sex | age | sibsp | parch | fare | embarked | class | who | adult_male | deck | embark_town | alive | alone | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 3 | male | 22.0 | 1 | 0 | 7.2500 | S | Third | man | True | NaN | Southampton | no | False |
1 | 1 | 1 | female | 38.0 | 1 | 0 | 71.2833 | C | First | woman | False | C | Cherbourg | yes | False |
2 | 1 | 3 | female | 26.0 | 0 | 0 | 7.9250 | S | Third | woman | False | NaN | Southampton | yes | True |
3 | 1 | 1 | female | 35.0 | 1 | 0 | 53.1000 | S | First | woman | False | C | Southampton | yes | False |
4 | 0 | 3 | male | 35.0 | 0 | 0 | 8.0500 | S | Third | man | True | NaN | Southampton | no | True |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
886 | 0 | 2 | male | 27.0 | 0 | 0 | 13.0000 | S | Second | man | True | NaN | Southampton | no | True |
887 | 1 | 1 | female | 19.0 | 0 | 0 | 30.0000 | S | First | woman | False | B | Southampton | yes | True |
888 | 0 | 3 | female | NaN | 1 | 2 | 23.4500 | S | Third | woman | False | NaN | Southampton | no | False |
889 | 1 | 1 | male | 26.0 | 0 | 0 | 30.0000 | C | First | man | True | C | Cherbourg | yes | True |
890 | 0 | 3 | male | 32.0 | 0 | 0 | 7.7500 | Q | Third | man | True | NaN | Queenstown | no | True |
891 rows × 15 columns
embark_town
컬럼은 타이타닉호 승객들이 탑승한 항구의 이름을 나타냅니다. 데이터셋에는 주로 'Southampton', 'Cherbourg', 'Queenstown'의 세 가지 값이 있으며, 일부는 결측치(NaN)로 표시됩니다.
# 'embark_town' 컬럼의 값 분포 확인
titanic['embark_town'].value_counts(dropna=False)
embark_town
Southampton 644
Cherbourg 168
Queenstown 77
NaN 2
Name: count, dtype: int64
데이터 전처리의 첫 번째 단계로, 결측치 처리를 진행합니다. 이 예제에서는 결측치를 'N'으로 대체하여 표시합니다.
# 결측치를 'N'으로 대체
titanic['embark_town'].fillna('N', inplace=True)
라벨 인코딩은 범주형 데이터를 순서형 숫자로 변환하는 방법입니다. 이 방식은 범주를 0부터 시작하는 숫자로 매핑하는 간단한 방식입니다. 그러나 숫자의 크기가 모델 학습에 영향을 미칠 수 있어, 선형 모델이나 신경망과 같은 모델에서는 주의해서 사용해야 합니다. 반면, 결정 트리와 같은 트리 기반 모델에서는 숫자의 크기에 영향을 덜 받으므로 라벨 인코딩이 효과적일 수 있습니다.
from sklearn.preprocessing import LabelEncoder
# 라벨 인코더 생성
encoder = LabelEncoder()
# 'embark_town' 컬럼에 라벨 인코딩 적용
encoder.fit(titanic['embark_town'])
# 인코딩된 클래스 확인
encoder.classes_
[output]
array(['Cherbourg', 'N', 'Queenstown', 'Southampton'], dtype=object)
이제 embark_town
컬럼의 각 범주가 숫자로 변환되었습니다. 이 숫자들은 모델에 직접 입력될 수 있습니다.
# 인코딩 적용
labels = encoder.transform(titanic['embark_town'])
# 처음 5개의 인코딩된 레이블 확인
labels[:5]
[output]
array([3, 0, 3, 3, 3])
라벨 인코딩의 장점은 단순하고 계산이 쉽습니다. 하지만 이 방식은 범주 간의 관계나 순서가 없는 데이터에 순서를 부여할 수 있기 때문에, 모델이 잘못된 관계를 학습할 위험이 있습니다. 따라서 라벨 인코딩은 범주 간의 관계가 중요하지 않거나 트리 기반 모델을 사용할 때 더 적합합니다.
다음으로, 원-핫 인코딩에 대해 살펴보겠습니다. 이 방법은 라벨 인코딩의 주요 단점을 해결하며, 다른 유형의 모델에 더 적합할 수 있습니다.
원-핫 인코딩(One-Hot Encoding)은 범주형 데이터를 0과 1을 사용해 변환하는 방법입니다. 이 방식은 각 범주를 새로운 열로 표현하고, 해당 범주에 해당하는 경우 1, 그렇지 않은 경우 0으로 표시합니다. 이렇게 하면 모델이 범주 간의 수치적 크기에 영향을 받지 않도록 할 수 있습니다.
하지만 라벨 인코딩과 달리 원-핫 인코딩을 수행할 때는 두 가지 주의점이 있습니다. 첫째, 인코딩되기 전의 데이터는 숫자형이어야 합니다. 문자열 범주형 데이터를 먼저 라벨 인코더를 활용해 숫자형 데이터로 변환할 수 있습니다. 둘째, 원-핫 인코더는 입력 데이터가 2차원 배열 형태로 제공되어야 합니다. 이 경우 ndarray.reshape(-1, 1)을 활용하여 데이터를 적절한 형태로 변환할 수 있습니다.
from sklearn.preprocessing import OneHotEncoder
# 원-핫 인코더 생성
oh_encoder = OneHotEncoder()
# 라벨 인코딩된 데이터를 2차원 배열로 변환
labels = labels.reshape((-1, 1))
# 원-핫 인코딩 적용
oh_encoder.fit(labels)
oh_labels = oh_encoder.transform(labels)
원-핫 인코딩된 결과는 희소 행렬 형태로 저장됩니다. 이는 메모리 효율성을 높이기 위한 방법입니다.
# 원-핫 인코딩된 데이터의 희소 행렬 형태 확인
print(oh_labels)
(0, 3) 1.0
(1, 0) 1.0
(2, 3) 1.0
(3, 3) 1.0
(4, 3) 1.0
(5, 2) 1.0
: :
(885, 2) 1.0
(886, 3) 1.0
(887, 3) 1.0
(888, 3) 1.0
(889, 0) 1.0
(890, 2) 1.0
원-핫 인코딩의 장점은 모델이 범주 간의 순서나 크기를 고려하지 않도록 하는 것입니다. 이는 특히 선형 모델이나 신경망과 같은 모델에서 유용합니다. 하지만, 원-핫 인코딩은 데이터의 차원을 크게 증가시킬 수 있으며, 이는 '차원의 저주'를 야기할 수 있습니다. 또한, 많은 수의 범주를 가진 컬럼에 적용할 경우 메모리 사용량이 크게 증가할 수 있습니다.
따라서 원-핫 인코딩은 범주 간의 관계가 중요하지 않고, 모델이 범주의 크기나 순서를 고려하지 않아야 할 때 적합합니다. 이 방법은 선형 회귀, 로지스틱 회귀, 신경망 등에서 효과적입니다.
라벨 인코딩은 범주형 데이터를 숫자로 변환하는 간단한 방법이지만, 모델이 이 숫자의 크기나 순서에 영향을 받을 수 있다는 단점이 있습니다. 따라서 라벨 인코딩은 트리 기반 모델 같이 숫자의 크기나 순서가 중요하지 않은 모델에서 주로 사용됩니다.
반면, 원-핫 인코딩은 각 범주를 독립적인 특성으로 변환하여 모델이 범주 간의 관계를 고려하지 않도록 합니다. 이 방법은 특히 선형 모델, 로지스틱 회귀, 신경망 등에서 유용하게 사용될 수 있습니다. 하지만 데이터의 차원을 크게 증가시키는 단점이 있으므로, 차원 수와 메모리 사용량을 고려하여 적절히 선택해야 합니다.
인코딩 방식을 선택할 때는 다음과 같은 점을 고려해야 합니다: