『파이썬 머신러닝 완벽 가이드』 도서를 공부하며 정리한 글입니다.
코드 결과는 직접 실행해보면서 결과를 보시면 좋을 것이라 생각하여 생략하였습니다.
데이터 전처리는 ML(머신러닝) 알고리즘만큼 중요하다.
쓰레기를 넣으면 쓰레기가 나온다는 (Garbage in, Garbage out) 말이 있듯이, ML 알고리즘의 성능이 좋더라도, 어떤 데이터를 입력으로 가지느냐에 따라 결과가 매우 크게 달라질 수 있다.
그렇기 때문에 ML알고리즘을 적용하기전에 데이터에 대해 미리 처리해야할 것들이 있다.
1. 결손값(NaN)
Null값이라고 하는 것인데, 이는 ML 알고리즘에 허용되지 않는다. 그렇기 때문에 무조건 결측치를 없애줘야하는데, 크게 결측치를 제거하는 방법과 대체하는 방법이 있다.
(1) Null값이 얼마 되지 않는 경우
- feature의 평균값 등으로 간단히 대체한다.
(2) Null값이 대부분인 경우
- 해당 fature를 drop하는게 좋다.
다만, 가장 결정하기 힘든 부분이
(3) Null값이 일정 수준 이상 되는 경우
- 일정 수준이라고 할 정확한 기준이 일단 없다.
- 그리고 해당 feature가 중요도가 높은 feature이고 null을 제거하거나 단순히 평균값으로 대체했을 때 예측 왜곡이 심할 경우, 다양한 방식으로 검토한 후 정밀한 대체값을 선정해야 한다.
- 내가 해봤던 처리작업을 말해보자면, 결측치가 꽤 많았던 컬럼 a에 대해 다른 컬럼들과의 상관관계를 파악한 후, 가장 높은 상관관계를 가지는 컬럼 b(범주형이었다.)의 범주 별 a의 평균을 매겨서 결측치들을 대체하였다.
2. 숫자형 변환
모든 ML 알고리즘은 문자열 값을 입력값으로 허용하지 않기 때문에, 모든 문자열 값은 인코딩되어 숫자 형으로 변환해야한다.
문자열 feature는 '카테고리형 피처'와 '텍스트형 피처' 가 있는데,
- 카테고리형 피처는 보통 우리가 주요 특징으로 사용하는 범주형 피처라고 생각하면 된다.
- 텍스트형 피처는 단순히 데이터를 식별하는 용도로 사용되어 예측에서 중요한 요소가 될수 없는 경우가 대부분이다.
2-1. 데이터 인코딩
데이터 인코딩은 위에서도 언급되었듯이, 문자형 데이터를 숫자형으로 변환해주는 것이다.
대표적으로 레이블 인코딩(Label encoding)과 원-핫 인코딩(One Hot encoding)이 있다.
a. 레이블 인코딩
카테고리형 피처를 코드형 숫자 값으로 변환하는 것이다. 코드형 숫자 값이라는 것은 별게 아니라,
TV:1, 냉장고:2, 전자레인지:3, 컴퓨터:4, 선풍기:5, 믹서기:6 이와 같은 것이다.
물론 01, 02는 카테고리형이므로, 1,2와 같은 숫자형 값으로 변환되어야한다.
# 사이킷런의 레이블 인코딩은 LabelEncoder 클래스로 구현한다.
from sklearn.preprocessing import LabelEncoder
items = ['TV', '냉장고', '전자레인지', '컴퓨터', '선풍기', '선풍기', '믹서', '믹서']
# LabelEncoder를 객체로 생성
encoder = LabelEncoder()
# fit()과 transform()으로 레이블 인코딩 수행.
encoder.fit(items)
labels = encoder.transform(items)
이렇게 코드를 수행하고 나면, labels는 [0 1 4 5 3 3 2 2] 이다. 문자형이 숫자형으로 변환된 것이다.
만약 해당 숫자들이 어떤 문자열 값인지 알고 싶다면, LabelEncoder 객체의 classes_ 속성값으로 확인하면 된다.
print('인코딩 클래스: ', encoder.classes_)
이렇게 인코딩한 값을 다시 디코딩하여 문자열 값으로 받고 싶다면, inverse_transform() 을 이용하면 된다.
print('디코딩 원본값 : ', encoder.inverse_tansform([4, 5, 2, 0, 1, 1, 3, 3])
하지만 레이블 인코딩의 문제점은 ML 알고리즘에서 이를 적용할 경우 문제가 될 수 있다는 점이다.
숫자 값의 경우 크고 작은 특성이 작용하기 때문에, 1인 TV보다 2인 냉장고가 더 크다고 판단을 하여 중요하게 인식하거나 가중치를 크게 부여할 가능성이 발생한다.
이러한 특성 때문에 레이블 인코딩은 트리 계열의 ML 알고리즘에서 별문제가 없지만
선형회귀와 같은 ML 알고리즘에는 적용하지 않아야 한다.
이 문제를 해결하는 인코딩 방식이 원-핫 인코딩이다.
b. 원-핫 인코딩
피처 값의 유형에 따라 새로운 피처를 추가해 고유 값에 해당하는 칼럼에만 1을 표시하고, 나머지 칼럼에는 0으로 표시하는 방식이다.
그림이 이해하기 더 쉬울 것이다.
각 범주별 칼럼이 새로 추가되고, 해당하는 범주값?에만 1이 표시되고 나머지는 0으로 표시하는 것이다.
위 사진에서 처럼, LabelEncoder와 One-Hot Encoding의 차이점은
- One-Hot Encoding은 0과 1로만 구성되지만 범주형만큼 칼럼이 새로 추가되고, 그 칼럼에는 0과 1로 구성된다는 것이고,
- LabelEncoder는 해당 범주마다 부여되는 숫자값으로 구성된다는 것이다. 범주형 갯수만큼 많아질 것이다.
이제 코드로 확인해보겠다. One-Hot Encoding은 사이킷런에서 OneHotEncoder 클래스로 쉽게 할 수 있다.
단, 주의할 점은 1. 모든 문자열 값을 숫자형 값으로 변환한다. 2. 2차원 데이터로 변환한다.
이 과정을 거치고, 원핫인코더에는 2차원 데이터를 입력 값으로 넣어야한다는 점이다.
그래서 1번째 과정은 LabelEncoder를 사용해서 변환하고, 2번째과정에서는
from sklearn.preprocessing import OneHotEncoder
import numpy as np
from sklearn.preprocessing import LabelEncoder
items = ['TV', '냉장고', '전자레인지', '컴퓨터', '선풍기', '선풍기', '믹서', '믹서']
### 1.LabelEncoder 이용하여 숫자형으로 변환.
# LabelEncoder를 객체로 생성
encoder = LabelEncoder()
# fit()과 transform()으로 레이블 인코딩 수행.
encoder.fit(items)
labels = encoder.transform(items)
### 2. reshape() 이용하여 2차원 데이터로 변환.
labels = labels.reshape(-1, 1)
* 여기서 resahpe(-1,1)의 의미는 뭘까?
행 위치에 '-1'이 있다는 것은 '원래 배열의 길이와 남은 차원으로 부터 추정'한다는 의미이다.
즉, 데이터가 12개인데 열을 1로 뒀을 경우, 행 갯수가 12개가 되는 것이고,
열을 3으로 뒀을 경우, 행 갯수가 4개가 되는 식으로, 가변적인 것을 의미한다고 생각하면 된다.
여기서는 결국, labels.reshape(8,1)과 같은 의미인 것이다.
형태는 다음과 같다.
array([[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 4],
[ 5],
[ 5]]])
이제 해당 숫자형 행들을 이용해서 원-핫 인코딩을 적용해보겠다.
### 원-핫 인코딩 적용.
oh_encoder = OneHotEncoder()
oh_encoder.fit(labels)
oh_labels = oh_encoder.transoform(labels)
# 원-핫인코딩 데이터를 array로 출력해보면
print(oh_labels.toarray())
각 범주별 컬럼이 추가로 생성된 것을 확인할 수 있다. 물론 0과 1로만 구성되어있겠다.
추가로, 웟-핫 인코딩을 더 쉽게 지원하는 API가 판다스에 있다. 바로 get_dummies() 를 이용하면 된다. (꼭 좋은 건 마지막에 알려준다ㅋㅋㅋ)
사이킷런의 OneHotEncoder와 다르게 문자열 카테고리 값을 바로 원핫인코딩할 수 있는 좋은 녀석이다.
import pandas as pd
df = pd.DataFrame({'item': ['TV', '냉장고', '전자레인지', '컴퓨터', '선풍기', '선풍기', '믹서', '믹서']
})
pd.get_dummies(df)
다음 2탄에서는, 입력 데이터들이 서로 다른 범위일 경우, 일정한 수준으로 맞추는 작업인 피처 스케일링(표준화와 정규화)에 대해 적어보겠다.
'지식 > Machine Learning' 카테고리의 다른 글
단순회귀, 다중회귀, 다항회귀 (0) | 2021.05.23 |
---|---|
데이터 전처리 (2. 피처 스케일링) (0) | 2021.04.11 |
교차 검증 (0) | 2021.04.08 |
ndarray, 리스트, 딕셔너리와 DataFrame 상호 변환하기 (0) | 2021.03.28 |
K-NN 알고리즘의 쉬운 예제 (0) | 2021.03.16 |