데이터 전처리: 범주형 데이터 다루기(순서 매핑, one-hot 인코딩)
March 17, 2022, 10:41 p.m.
훈련 데이터의 모든 값들이 수치로 나타나 있다면 훈련을 진행하기에 정말 편할것입니다. 그렇지만 모든 데이터가 그렇지는 않습니다. 이럴때는 데이터를 수치화 해야 합니다.
이번 포스트에서는 그 중에서도 범주형 데이터를 수치화 하는 법에 대해서 알아보겠습니다.
1. 범주형 데이터란?
범주형 데이터란 무엇일까요?
어떤 특성에 대해서 그 특성을 연속적인 수치 값이 아니라 특정 이름으로 구분지어 놓은 것을 말합니다.
이런 범주형 데이터는 순서가 있는 범주형 데이터와 순서가 없는 범주형 데이터, 두가지로 분류됩니다.
옷 사이즈 같은 것이 순서가 있는 범주형 데이터네요. 'S', 'M', 'L', 'XL' 처럼 구분된 사이즈 데이터는 순서가 있습니다. 아래와 같은 관계를 만들 수 있습니다.
순서가 있는 데이터들은 이런 관계를 살려서 수치화해주어야 학습시에도 도움이 되겠죠?
그럼 순서가 없는 데이터들에는 무엇이 있을까요?
영화의 장르와 같은 데이터들이 있겠네요. 영화의 장르는 순서관계가 없습니다. 서로 다른 범주일 뿐이죠. 이런 데이터들은 one-hot 인코딩 같은 방법을 사용하여 수치화 합니다.
1. 순서가 있는 범주형 데이터
아래와 같이 옷에 관한 데이터가 있다고 해봅시다.
import pandas as pd
df = pd.DataFrame([
['shirt','M','10000'],
['hat','S','6000'],
['shirt','L','12000'],
['hat','M','8000'],
['hoodie','XL','18000'],
['hat','M','8500'],
['shirt','S','8000'],
['hoodie','L','12000']
])
df.columns = ['type', 'size','price']
type size price
0 shirt M 10000
1 hat S 6000
2 shirt L 12000
3 hat M 8000
4 hoodie XL 18000
5 hat M 8500
6 shirt S 8000
7 hoodie L 12000
여기서 순서가 있는 범주형 데이터는 size입니다. 위에서 언급했던 관계를 생각해서 아래와 같이 매핑을 해보겠습니다.
위의 관계를 정의하는 딕셔너리를 만듭니다.
map = {'S':1,'M':2, 'L':3, 'XL':4}
그다음 데이터프레임의 map()을 이용해서 매핑을 진행합니다.
df['size'] = df['size'].map(map)
type size price
0 shirt 2 10000
1 hat 1 6000
2 shirt 3 12000
3 hat 2 8000
4 hoodie 4 18000
5 hat 2 8500
6 shirt 1 8000
7 hoodie 3 12000
위와 같이 size 데이터들이 수치로 변환된 모습을 볼 수 있네요.
3. 순서가 없는 범주형 데이터
위의 데이터에서 type은 순서가 없는 범주형 데이터입니다. 이런 데이터를 임의로 숫자로 바꾼다면 무슨 문제가 생길까요?
옷의 종류를 의미하는 type 간의 순서 관계가 만들어지고 존재하지 않는 의미가 부여되어 학습시에 좋지 않은 결과를 만들어내게 됩니다.
이럴때는 one-hot 인코딩을 사용합니다. 각각의 type을 하나의 벡터로 만드는 것입니다. 아래와 같이요.
type의 종류가 총 3가지이므로 길이가 3인 벡터를 만들어 각각 하나만 1로 하고 나머지를 0으로 합니다. 그렇기 때문에 one-hot 인코딩이라는 말이 붙었습니다.
데이터프레임을 직접 조작하여 이 과정을 진행할 수도 있지만 데이터프레임 자체에 이 기능을 구현하는
one_hot = pd.get_dummies(df[['type']])
type_hat type_hoodie type_shirt
0 0 0 1
1 1 0 0
2 0 0 1
3 1 0 0
4 0 1 0
5 1 0 0
6 0 0 1
7 0 1 0
인코딩이 잘 되었네요. 원래 데이터프레임에 합쳐보겠습니다.
df = pd.concat([df,one_hot], axis=1)
type size price type_hat type_hoodie type_shirt
0 shirt 2 10000 0 0 1
1 hat 1 6000 1 0 0
2 shirt 3 12000 0 0 1
3 hat 2 8000 1 0 0
4 hoodie 4 18000 0 1 0
5 hat 2 8500 1 0 0
6 shirt 1 8000 0 0 1
7 hoodie 3 12000 0 1 0
이제 원래 type열은 필요가 없으니 지워주겠습니다.
df = df.drop(['type'],axis=1)
size price type_hat type_hoodie type_shirt
0 2 10000 0 0 1
1 1 6000 1 0 0
2 3 12000 0 0 1
3 2 8000 1 0 0
4 4 18000 0 1 0
5 2 8500 1 0 0
6 1 8000 0 0 1
7 3 12000 0 1 0
모든 데이터가 수치화 되었습니다. 이제 모델을 훈련시킬 수 있겠네요.
여기서 더 한가지 짚고 넘어갈 점이 있습니다. one-hot 인코딩이 범주형 데이터를 벡터화 하는 것은 좋지만 특성의 수(데이터프레임 열의 수)가 늘어나는 단점이 있습니다. 차원이 늘어날 수록 모델을 훈련하기는 어려워지죠.
여기서 type의 종류는 총 3가지 였습니다. 즉 2비트만 있어도 3가지를 표현할 수 있다는 뜻이죠. 만약 여기서 type_shirt 열을 없앤다면 어떻게 될까요?
여전히 type_hat, type_hoodie 열의 데이터만으로도 3가지의 타입을 구분할 수 있습니다. 그러므로 type_shirt 열도 지워주겠습니다.
df = df.drop(['type_shirt'],axis=1)
size price type_hat type_hoodie
0 2 10000 0 0
1 1 6000 1 0
2 3 12000 0 0
3 2 8000 1 0
4 4 18000 0 1
5 2 8500 1 0
6 1 8000 0 0
7 3 12000 0 1
범주형 데이터를 완전히 수치화 했습니다.
위의 방법론들은 범주형 데이터를 모델 훈련에 적합하도록 변환하는 가장 쉬운 방법들입니다. 범주형 데이터의 의미를 살리면서 수치화 하는 훨씬 다양한 방법과 창의적인 방법들이 존재합니다.
의미있는 데이터 전처리를 통해 모델의 성능을 더욱 높일 수 있길 바랍니당
one-hot