pandas.get_dummies 대신 sklearn.preprocessing.OneHotEncoder를 쓰자¶
1. pandas.get_dummies의 문제점¶
- pandas.get_dummies는 train 데이터의 특성을 학습하지 않기 때문에 train 데이터에만 있고 test 데이터에는 없는 카테고리를 test 데이터에서 원핫인코딩 된 칼럼으로 바꿔주지 않는다.
In [4]:
import pandas as pd
train = pd.DataFrame({'num1':[1,2,3,4,5], 'num2':[10,20,30,40,50], 'cat1':['a', 'a', 'b', 'c', 'c']})
train
Out[4]:
num1 | num2 | cat1 | |
---|---|---|---|
0 | 1 | 10 | a |
1 | 2 | 20 | a |
2 | 3 | 30 | b |
3 | 4 | 40 | c |
4 | 5 | 50 | c |
- train의 cat1 칼럼에는 'a', 'b', 'c' 카테고리가 존재하고, pandas.get_dummies를 사용하면 세 개의 카테고리를 칼럼으로 바꿔준다.
In [5]:
pd.get_dummies(train)
Out[5]:
num1 | num2 | cat1_a | cat1_b | cat1_c | |
---|---|---|---|---|---|
0 | 1 | 10 | 1 | 0 | 0 |
1 | 2 | 20 | 1 | 0 | 0 |
2 | 3 | 30 | 0 | 1 | 0 |
3 | 4 | 40 | 0 | 0 | 1 |
4 | 5 | 50 | 0 | 0 | 1 |
In [6]:
test = pd.DataFrame({'num1':[1,2,3,4,5], 'num2':[10,20,30,40,50], 'cat1':['a', 'a', 'b', 'b', 'a']})
test
Out[6]:
num1 | num2 | cat1 | |
---|---|---|---|
0 | 1 | 10 | a |
1 | 2 | 20 | a |
2 | 3 | 30 | b |
3 | 4 | 40 | b |
4 | 5 | 50 | a |
- 하지만 test 데이터에 있는 cat1 칼럼에는 'c' 카테고리가 존재하지 않는다.
In [7]:
pd.get_dummies(test)
Out[7]:
num1 | num2 | cat1_a | cat1_b | |
---|---|---|---|---|
0 | 1 | 10 | 1 | 0 |
1 | 2 | 20 | 1 | 0 |
2 | 3 | 30 | 0 | 1 |
3 | 4 | 40 | 0 | 1 |
4 | 5 | 50 | 1 | 0 |
- 이 경우 pandas.get_dummies는 'c' 카테고리에 대한 정보가 test 데이터에 없기 때문에 'cat1_c' 칼럼은 생성하지 않는다.
2. sklearn.preprocessing.OneHotEncoder는 train 데이터의 특성을 학습할 수 있다¶
In [18]:
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(sparse=False)
# fit_transform은 train에만 사용하고 test에는 학습된 인코더에 fit만 해야한다
train_cat = ohe.fit_transform(train[['cat1']])
train_cat
Out[18]:
array([[1., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.], [0., 0., 1.]])
In [13]:
ohe.categories_
Out[13]:
[array(['a', 'b', 'c'], dtype=object)]
- sklearn.preprocessing.OneHotEncoder를 사용하여 변환된 결과는 numpy.array이기 때문에 이를 데이터프레임으로 변환하는 과정이 필요하다.
In [27]:
pd.DataFrame(train_cat, columns=['cat1_' + col for col in ohe.categories_[0]])
Out[27]:
cat1_a | cat1_b | cat1_c | |
---|---|---|---|
0 | 1.0 | 0.0 | 0.0 |
1 | 1.0 | 0.0 | 0.0 |
2 | 0.0 | 1.0 | 0.0 |
3 | 0.0 | 0.0 | 1.0 |
4 | 0.0 | 0.0 | 1.0 |
In [28]:
pd.concat([train.drop(columns=['cat1']),
pd.DataFrame(train_cat, columns=['cat1_' + col for col in ohe.categories_[0]])], axis=1)
Out[28]:
num1 | num2 | cat1_a | cat1_b | cat1_c | |
---|---|---|---|---|---|
0 | 1 | 10 | 1.0 | 0.0 | 0.0 |
1 | 2 | 20 | 1.0 | 0.0 | 0.0 |
2 | 3 | 30 | 0.0 | 1.0 | 0.0 |
3 | 4 | 40 | 0.0 | 0.0 | 1.0 |
4 | 5 | 50 | 0.0 | 0.0 | 1.0 |
In [29]:
test_cat = ohe.transform(test[['cat1']])
test_cat
Out[29]:
array([[1., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 1., 0.], [1., 0., 0.]])
In [30]:
pd.DataFrame(test_cat, columns=['cat1_' + col for col in ohe.categories_[0]])
Out[30]:
cat1_a | cat1_b | cat1_c | |
---|---|---|---|
0 | 1.0 | 0.0 | 0.0 |
1 | 1.0 | 0.0 | 0.0 |
2 | 0.0 | 1.0 | 0.0 |
3 | 0.0 | 1.0 | 0.0 |
4 | 1.0 | 0.0 | 0.0 |
In [31]:
pd.concat([test.drop(columns=['cat1']),
pd.DataFrame(test_cat, columns=['cat1_' + col for col in ohe.categories_[0]])], axis=1)
Out[31]:
num1 | num2 | cat1_a | cat1_b | cat1_c | |
---|---|---|---|---|---|
0 | 1 | 10 | 1.0 | 0.0 | 0.0 |
1 | 2 | 20 | 1.0 | 0.0 | 0.0 |
2 | 3 | 30 | 0.0 | 1.0 | 0.0 |
3 | 4 | 40 | 0.0 | 1.0 | 0.0 |
4 | 5 | 50 | 1.0 | 0.0 | 0.0 |
- pandas.get_dummies를 사용할때보다는 훨씬 귀찮은 작업이 되었지만 train 데이터에 있던 'c' 카테고리의 정보가 test 데이터에도 반영된 것을 볼 수 있다.