«
in 데이터  / #pandas #python #데이터 정제  

One-hot 인코딩 쉽게 하기

머신러닝을 할 때는 모든 데이터를 숫자로 넣어주어야 합니다. 개인의 출신 지역(서울, 부산, …)이나 전공한 학과(경영학과, 경제학과, …) 같이 글자로 되어있지만 몇 가지로 분류할 수 있는 데이터는 어떻게 숫자로 바꾸어야 할까요?

서울=1, 부산=2, 경기=3, 강원=4 … 이렇게?

각 지역에 코드를 지정해서 숫자로 표시하는 방법이 있겠죠? 데이터베이스에서 자료를 내려받는 경우에 용량을 아끼려고 각 데이터에 숫자로 된 코드를 부여하여 저장하는 경우가 많습니다. 그런데 이 숫자들을 그대로 학습시키면 컴퓨터에게 올바르지 않은 편견을 가지게 할 수 있습니다.

  • 부산(2)은 서울(1)보다 1만큼 크다.
  • 경기도(3)는 서울(1)보다 2만큼 크다.
  • 경기도(3)는 서울(1)보다 부산(2)에 가깝다????

아직까지 머신 러닝에 있어 사람의 역할이 많이 중요하다고 볼 수 있는 부분이죠. 각 변수의 성질을 파악하여 적절하게 숫자로 변환해 주는 과정은 아직은 컴퓨터가 수행하기 어렵다고 생각합니다.

통계학에서는 몇 가지로 분류할 수 있는 데이터를 범주형 변수라고 하는데요. 범주형 변수를 머신 러닝에 활용할 때는 원-핫(One-hot) 인코딩이라고 해서 해당하는 칸의 정보를 1로 표시하고 나머지는 0으로 표시하는 방법을 많이 사용합니다.

One-hot 인코딩 예시
One-hot 인코딩 예시, 출처: stackoverflow

머신 러닝에서는 범주형 변수뿐만 아니라 분류 문제에서 학습에 사용되는 정답 데이터와 컴퓨터가 softmax로 만들어낸 확률값의 크로스 엔트로피를 구하기 위해서도 사용되고, 감성 분석이나 텍스트 생성 모델을 만들 때도 사용하는 보편적인 데이터 변형 방법입니다.

쉽게 생각하면 OMR카드에 답을 쓰는 것처럼 데이터를 만든다고 생각하시면 돼요. 예를 들어 ABDBBBB를 1번부터 OMR 카드에 적는다고 하면, 1번에 A, 2번에 B를 까맣게 칠하고 나머지를 비우는 것처럼요. 이렇게 하면 숫자로 변환할 때 각 분류를 편향되지 않게 컴퓨터에게 학습시킬 수 있습니다.

OMR카드. 이건 뭔가 잘못된거같은데..

Pandas로 One-hot 인코딩 해보기

One-hot 인코딩을 하기 위해 먼저 파이썬으로 100명의 가짜 학생 데이터를 만들어 보겠습니다.

import pandas as pd
from pandas import DataFrame, Series
from itertools import cycle

pd.set_option('display.unicode.east_asian_width', True)

area = '서울 부산 대구 인천 광주 대전 울산 세종 경기 강원 충북 충남 전북 전남 경북 경남 제주'.split()
college = '인문대학 사회과학대학 자연과학대학 간호대학 경영대학 공과대학 미술대학'.split()
gender = '남성 여성'.split()

# 100개의 가짜 데이터 생성, itertools.cycle 함수로 각 요소를 순환시킵니다.
fake_data = zip(range(100), cycle(area), cycle(college), cycle(gender))
hundred_students = DataFrame([data for num, *data in fake_data],
                              columns='지역 단과대 성별'.split())
hundred_students.head(10)
  지역 단과대 성별
0 서울 인문대학 남성
1 부산 사회과학대학 여성
2 대구 자연과학대학 남성
3 인천 간호대학 여성
4 광주 경영대학 남성
5 대전 공과대학 여성
6 울산 미술대학 남성
7 세종 인문대학 여성
8 경기 사회과학대학 남성
9 강원 자연과학대학 여성

먼저 ‘단과대’ 컬럼만 One-hot encoding을 해 보겠습니다. pandas의 get_dummies 함수를 이용하면 한줄로 One-hot 인코딩을 할 수 있습니다.

# pd.get_dummies로 One-hot 인코딩
college_one_hot_encoded = pd.get_dummies(hundred_students.단과대) 

# 원래 데이터와 비교식으로 보여주기용 데이터프레임
college_with_onehot = pd.concat(
	[DataFrame(hundred_students.단과대), college_one_hot_encoded],
	axis=1) 
college_with_onehot.head(10)
  단과대 간호대학 경영대학 공과대학 미술대학 사회과학대학 인문대학 자연과학대학
0 인문대학 0 0 0 0 0 1 0
1 사회과학대학 0 0 0 0 1 0 0
2 자연과학대학 0 0 0 0 0 0 1
3 간호대학 1 0 0 0 0 0 0
4 경영대학 0 1 0 0 0 0 0
5 공과대학 0 0 1 0 0 0 0
6 미술대학 0 0 0 1 0 0 0
7 인문대학 0 0 0 0 0 1 0
8 사회과학대학 0 0 0 0 1 0 0
9 자연과학대학 0 0 0 0 0 0 1

데이터프레임을 첫번째 파라미터로 넣고, prefix에 컬럼들을 지정해 주면 한꺼번에 One-hot 인코딩을 할 수 있습니다.

pd.get_dummies(hundred_students, prefix=['지역', '단과대', '성별']).head(10)
   지역_강원  지역_경기  지역_경남  지역_경북  지역_광주  지역_대구  \
0          0          0          0          0          1          0   
1          0          0          0          0          0          0   
2          0          0          0          0          1          0   
3          0          0          0          0          0          0   
4          0          0          1          0          0          0   
5          0          0          0          0          0          0   
6          1          0          0          0          0          0   
7          0          0          1          0          0          0   
8          0          0          0          0          0          0   
9          0          0          0          0          0          0   

   지역_대전  지역_부산  지역_서울  지역_세종    ...      지역_충북  \
0          0          0          0          0    ...              0   
1          0          0          0          0    ...              0   
2          0          0          0          0    ...              0   
3          0          0          0          0    ...              0   
4          0          0          0          0    ...              0   
5          0          0          0          0    ...              0   
6          0          0          0          0    ...              0   
7          0          0          0          0    ...              0   
8          1          0          0          0    ...              0   
9          0          0          0          0    ...              0   

   단과대_간호대학  단과대_경영대학  단과대_공과대학  단과대_미술대학  \
0                0                0                0                1   
1                0                0                0                0   
2                0                1                0                0   
3                0                0                0                1   
4                0                1                0                0   
5                0                0                0                1   
6                0                0                0                0   
7                0                0                0                0   
8                0                0                0                0   
9                1                0                0                0   

   단과대_사회과학대학  단과대_인문대학  단과대_자연과학대학  성별_남성  \
0                    0                0                    0          0   
1                    0                1                    0          1   
2                    0                0                    0          1   
3                    0                0                    0          0   
4                    0                0                    0          0   
5                    0                0                    0          1   
6                    0                1                    0          0   
7                    0                1                    0          1   
8                    0                0                    1          0   
9                    0                0                    0          1   

   성별_여성  
0          1  
1          0  
2          0  
3          1  
4          1  
5          0  
6          1  
7          0  
8          1  
9          0  

[10 rows x 26 columns]