데이터 전처리(Data Preprocessing)는 머신러닝 알고리즘만큼 중요합니다. 어떻게 전처리해서 어떤 데이터를 입력으로 가지느냐에 따라 결과가 크게 달라지기 때문입니다.
1. 결손값 <NaN, Null 값의 처리>
이 값들은 다른 값으로 변환하던지 없애야합니다. 그럼 어떤 값을 변환해야 하고, 어떤 값을 없애야 할까요?
일반적으로는 아래와 같습니다.
Null 값이 많지 않은 Feature : | 평균값, 최빈값 등으로 대체 |
Null 값이 많은 Feature : | 해당 Feature 삭제 |
하지만, 해당 피처의 중요도가 높을 경우엔 단순히 평균값으로 대체하거나 삭제해버리면 옳바른 예측을 할 수 없을 것 입니다. 이럴 경우에는 업무 로직 등을 상세히 검토해 더 정밀한 대체 값을 선정해야 합니다.
결손값은 경우에 따라 데이터 전처리 과정에서 처리를 해주어도 되고, 사이킷런을 이용할 수도 있습니다.
from sklearn.impute import SimpleImputer (모든 결측치를 평균으로 대체)
Age, Cabin의 결측치를 평균 값으로 채웁니다.
from sklearn.impute import SimpleImputer
## default, imputing 'mean' value
imputer = SimpleImputer()
X_train_imputed = imputer.fit_transform(X_train)
X_val_imputed = imputer.transform(X_val)
# 학습
linear_model.fit(X_train_imputed, y_train)
# 예측
pred = linear_model.predict(X_val_imputed)
<참고>
scikit-learn.org/0.16/modules/generated/sklearn.preprocessing.Imputer.html
scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html
2. 카테고리 값을 가진 피쳐
사이킷런의 머신러닝 알고리즘은 문자열 값을 처리하지 못합니다. 그래서 모든 문자열 값을 숫자 형으로 변환해야 하는데 문자열 중 카테고리 피처는 데이터 인코딩(encoding)을 통해 변환할 수 있습니다.
문자열 | 카테고리형 피처 | 데이터 인코딩(encoding) |
텍스트형 피처 | 피처 벡터화(feature vectorization) |
만약 불필요한 피처일 경우에는 삭제하는 것이 좋습니다. ex) 주민번호, 단순 문자열 아이디
머신러닝의 대표적인 인코딩 방식은 레이블 인코딩(Label encoding)과 원-핫 인코딩(One Hot encoding)이 있습니다.
1. 레이블 인코딩(Label encoding)
from sklearn.preprocessing import LabelEncoder
items=['피자','치킨','짜장면','짜장면','탕수육']
encoder= LabelEncoder()
encoder.fit(items)
labels= encoder.transform(items)
print('인코딩 변환값:', labels)
- 레이블 인코딩 속성 값
print('인코딩 클래스 : ', encoder.classes_)
print('디코딩 원본값 : ', encoder.inverse_transform([1,2,3,0]))
레이블 인코딩은 간단하게 문자열을 숫자형 카테고리 값으로 변환합니다. 하지만 이 숫자들은 크고 작음의 순서가 존재한다는 문제가 있습니다. 머신러닝 알고리즘에서 짜장면<치킨<탕수육<피자 순으로 가중치를 부여하거나 중요하게 인식할 가능성이 발생합니다. 이러한 특성 때문에 Label encoding은 선형회귀같은 머신러닝 알고리즘에는 적용하지 않아야 합니다. 트리 계열의 머신러닝 알고리즘은 숫자의 이러한 특성을 반영하지 않기 때문에 문제없습니다.
2. 원-핫 인코딩(One-Hot Encoding)
원핫인코딩은 행 형태로 되어 있는 데이터 값을 열 형태로 넣어 주고, 고유 값에 해당하는 칼럼에만 1을 표시하고 나머지는 0을 표시합니다.
<방법1>
from sklearn.preprocessing import OneHotEncoder
import numpy as np
items=['피자','치킨','짜장면','짜장면','탕수육']
#먼저 label encoding을 사용해 숫자값으로 변경
encoder= LabelEncoder()
encoder.fit(items)
labels= encoder.transform(items)
labels
#2차원 데이터로 변환
labels = labels.reshape(-1,1)
labels
#원핫인코딩
oh_encoder = OneHotEncoder()
oh_encoder.fit(labels)
oh_labels = oh_encoder.transform(labels)
print('원-핫 인코딩 데이터')
print(oh_labels.toarray())
print('원-핫 인코딩 데이터 차원 : ',oh_labels.shape)
<방법2> pd.get_dummies()
import pandas as pd
df = pd.DataFrame({'item' : ['피자','치킨','짜장면','짜장면','탕수육']})
pd.get_dummies(df)
3. 피처 스케일링(Feature scaling)
Feature scaling 이란 서로 다른 변수의 값 범위를 일정한 수준으로 맞추는 작업을 말합니다.
대표적으로 표준화(Standardization)과 정규화(Normalization)가 있습니다.
1. StandardScaler (표준화 스케일)
일반적으로 표준화(Standardization)란 데이터의 피처 각각이 평균이 0이고 분산이 1인 가우시안 정규 분포를 가진 값으로 변환하는 것 입니다. 표준화 = (오리지널 값-전체값평균)/표준편차
StandardScaler는 표준화를 쉽게 지원하기 위한 class입니다. 즉, 개별 피처를 평균이 0, 분산이 1인 값으로 변환해줍니다.
이렇게 몇몇 알고리즘에서는 가우시안 정규 분포가 필요한데, 특히 사이킷런에서 구현한 RBF 커널을 이용하는 서포트 벡터 머신(Support Vector Machine)이나 선형회귀(Linear Regression), 로지스틱 회귀(Logistic Regression)는 데이터가 가우시안 분포를 가지고 있다고 가정하고 구현되어 있습니다. 그렇기 때문에 사전에 표준화를 적용하는 것은 예측 성능 향상에 중요한 요소가 될 수 있습니다.
< code >
from sklearn.datasets import load_iris
import pandas as pd
iris = load_iris()
iris_data = iris.data
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)
iris_df.head()
from sklearn.preprocessing import StandardScaler
# StandardScaler 객체 생성
scaler = StandardScaler()
# 데이터 세트 변환
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)
# ndarray -> dataframe
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
iris_df_scaled.head()
a=iris_df.mean()
b=iris_df.var()
c=iris_df_scaled.mean()
d=iris_df_scaled.var()
df = pd.DataFrame({'스케일 전 평균값':a,'스케일 후 평균값':c,'스케일 전 분산값':b,'스케일 후 분산값':d})
df
2. MinMaxScaler (정규화 스케일)
정규화(Normalization)란 서로 다른 피처의 크기를 통일하기 위해 크기를 변환해주는 것을 말합니다. 각 피처 별로 단위가 다르기 때문에 단위를 모두 최소 0~ 최대 1로 변환해 비교합니다.
하지만 사이킷런의 전처리 과정의 Nomalizer 모듈과 일반적인 정규화에 약간 차이가 있습니다.
사이킷런의 Nomalizer 모듈은 선형대수에서의 정규화 개념이 적용되었는데, 이것은 개별 벡터의 크기를 맞추기 위해 변환하는 것을 의미합니다. 즉, 개별 벡터를 모든 피처 벡터의 크기로 나눠 주는 것입니다.
일반 정규화 | 정규화=(오리지널값-최솟값)/(최대값-최솟값) |
선형대수의 정규화 | Nomalizer = 오리지널값/피쳐들의 크기 (피쳐a의 제곱+피쳐b의 제곱 +... +피쳐n의제곱 의 루트값) |
MinMaxScaler는 데이터값을 0~1 사이 범위 값으로 변환합니다. (음수 값이 있으면 -1~1값을 변환)
데이터의 분포가 가우시안 분포가 아닐 경우에 Min,Max Scale을 적용해 볼 수 있습니다.
< code >
from sklearn.preprocessing import MinMaxScaler
# 객체생성
scaler = MinMaxScaler()
# 데이터 세트 변환
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)
# ndarray -> dataframe
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
iris_df_scaled.head()
x=iris_df_scaled.min()
y=iris_df_scaled.max()
df1 = pd.DataFrame({'스케일 후 최소값':x,'스케일 후 최대값':y})
df1
3. 학습 데이터와 테스트 데이터의 스케일링 변환 시 유의점
Scaler 객체를 이용해 데이터의 스케일링 변환 시 fit(), transform(), fit_transform() 메소드를 이용합니다.
- fit() : 데이터 변환을 위한 기준 정보 설정을 적용(ex.최소값,최대값 설정 등)
- transform() : 설정된 정보를 이용해 데이터를 변환
- fit_transform() : 두개를 한번에 적용
※주의점
학습 데이터 : fit() 과 transform() 사용
테스트 데이터 : transform() 만 사용
학습 데이터로 fit()된 스케일링 기준 정보를 그대로 테스트에 적용해야하기 때문.
이런 주의사항이 발생하기 때문에 되도록 데이터를 분리하기 전에 스케일링을 적용하는 것이 좋습니다.
이 유의사항은 사이킷런 기반의 PCA와 같은 차원 축소 변환이나 텍스트의 피처 벡터화 변환 작업 시에도 동일하게 적용됩니다.
'머신러닝 (Machine Learning) > python Scikit-learn library' 카테고리의 다른 글
Model Selection 모듈(학습/테스트 분리,교차검증) (0) | 2021.02.10 |
---|---|
사이킷런 기반 프레임워크(3) 사이킷런에 내장된 예제 데이터 세트 (0) | 2021.02.07 |
사이킷런 기반 프레임워크(2) 사이킷런의 주요 모듈 (0) | 2021.02.07 |
사이킷런 기반 프레임워크(1) Estimator, fit(), predict() 메서드 (0) | 2021.02.07 |
사이킷런 특징과 설치법 (0) | 2021.02.07 |