Post

2.2 데이터 인코딩

2.2 데이터 인코딩


범주형 데이터를 숫자 형태로 바꾸는 작업을 데이터 인코딩 이라고 한다. 대표적인 데이터 인코딩 방식으로는 레이블 인코딩과 원-핫 인코딩이 있다.



1. 레이블 인코딩

label encoding은 범주형 데이터를 숫자로 일대일 맵핑해주는 인코딩 방식이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
from sklearn.preprocessing import LabelEcoder 

fruits = ['사과', '블루베리', '바나나', '', '블루베리', '바나나', '사과']

label_encoder = LabelEncoder()

fruits_label_encoded = label_encoder.fit_transform(fruits)

print('레이블 인코딩 적용 후 데이터: ', fruits_label_encoded)

'''
[3 2 1 0 2 1 1 3]
'''
원본->레이블 인코딩 후
사과 3
블루베리 2
바나나 1
 0
블루베리 2
바나나 1
바나나 1
사과 3

[!]1차원 데이터에 적용하는 LabelEncoder외에 2차원 데이터에 적용하는 OrdinalEncoder도 있다. 여러 feature를 인코딩 하려면 OrdinalEncoder를 사용하는게 좋다.

레이블 인코딩은 간단하지만 명목형 데이터를 레이블 인코딩하면 모델은 서로 가까운 숫자를 비슷한 데이터라고 판단하기 때문에 성능이 떨어질 수 있다.

머신러닝 모델은 1(바나나)과 3(사과) 보다 1(바나나)과 2(블루베리)를 더 비슷한 데이터라고 인식한다. 이 문제는 원-핫 인코딩으로 해결할 수 있다.





2. 원-핫 인코딩

one-hot encoding 은 여러 값 중 하나만 활성화 하는 인코딩이다. 실행 절차는 다음과 같다.

  1. 인코딩하려는 Feature의 고윳값 개수를 구한다.

  2. Feature의 고윳값 개수만큼 열을 추가한다.

  3. 각 고윳값에 해당하는 열에 1을 표시하고 나머지 열에는 0을 표시한다.


과일->과일_귤과일_바나나과일_블루베리과일_사과
사과 0001
블루베리 0010
바나나 0100
 1000
블루베리 0010
바나나 0100
바나나 0100
사과 0001

원-핫 인코딩은 레이블 인코딩의 문제(서로 가까운 숫자를 비슷한 데이터로 판단하는 문제)를 해결한다. 하지만 원-핫 인코딩도 열 개수가 지나치게 많아진다는 단점이 있다.

Feature의 고윳값이 많으면 그만큼 열 개수와 메모리 사용량이 늘어나기 때문에 모델 훈련 속도가 느려질 수 있다.


[!] Tip. 명목형 Feature에 고윳값이 많을 때 해결 방법

  1. 비슷한 고유값 끼리 그룹화: 그룹화하면 해당 명목형 피처의 고윳값 개수가 줄어드는 효과가 있다.

  2. 빈도가 낮은 고윳값을 ‘기타(etc)’로 처리: 비슷한 고윳값끼리 그룹화하는 방법과 비슷하다. 빈도가 낮은 고윳값 들을 묶어 ‘기타 고윳값’ 으로 일괄 처리하는 방법이다.

  3. 다른 인코딩 적용: 타깃 인코딩, 프리퀀시 인코딩 등 그 외 인코딩 기법이 있다. 다른 인코딩 기법도 각자 단점이 있다.


문자열 데이터에 바로 원-핫 인코딩을 적용할 수 없기 때문에 먼저 숫자형 데이터로 변환 후 원-핫 인코딩을 적용해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from sklearn.preprocessing import LabelEncoder, OneHotEncoder

fruits = ['사과', '블루베리', '바나나', '', '블루베리', '바나나', '사과']

label_encoder = LabelEncoder()
onehot_encoder = OneHotEncoder()

fruits_label_encoded = label_encoder.fit_transform(fruits)
fruits_onehot_encoded = onehot_encoder.fit_transform(fruits_label_encoded.reshape(-1, 1))

print("원핫 인코딩 적용 후 데이터: \n", fruits_onehot_encoded.toarray())

'''
[[0. 0. 0. 1.]
 [0. 0. 1. 0.]
 [0. 1. 0. 0.]
 [1. 0. 0. 0.]
 [0. 0. 1. 0.]
 [0. 1. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 0. 1.]]
'''

원-핫 인코딩은 대부분 값이 0인 희소행렬을 만들어낸다. 희소행렬은 메모리 낭비가 심하기 때문에 OneHotEncoder는 변환 결과를 압축 형태인 CSR (Compressed Sparse Row) 행렬로 돌려준다. 마지막에 호출 한 .toarray()는 CSR형태의 행렬을 일반 배열로 바꿔주는 역할을 한다.


판다스의 get_dummies() 함수를 사용하면 문자열 데이터를 숫자형으로 바꾸지 않아도 된다.

1
2
3
4
5
6
7
import pandas as pd

pd.get_dummies(fruits)

'''
OneHotEncoder로 변환한 인코딩 결과와 같음
'''



2.1 reshape() 메서드 용법

reshape() 메서드는 배열 형상을 바꿀 때 사용한다.

fruits_label_encoded

1
array([3, 2, 1, 0, 2, 1, 1, 3])


이를 (4, 2) 형상의 행렬로 바꾸려면 다음과 같이 reshape(4, 2)를 호출하면 된다.

1
2
3
4
5
6
7
fruits_label_encoded.reshape(4, 2)

=> 
array([[3, 2],
	   [1, 0],
	   [2, 1],
	   [1, 3]])


reshape()에 넘기는 값 중 하나를 -1로 지정할 수도 있다. 그럼 원본 데이터와 나머지 형상을 참고해서 최종 형상을 적절히 바꿔준다.

1
2
3
4
5
6
7
8
9
10
11
fruits_label_encoded.reshape(-1, 1)

=>
array([[3],
	   [2],
	   [1],
	   [0],
	   [2],
	   [1],
	   [1],
	   [3]])
This post is licensed under CC BY 4.0 by the author.