본문 바로가기
Machine Learning

사이킷런으로 시작하는 머신러닝 - 데이터 전처리(피처 스케일링)-

by rubyda 2020. 4. 10.
728x90

피처 스케일링


피처 스케일링(feature scaling)은 서로 다른 변수의 값에 대한 범위를 일정한 수준으로 맞추는 작업입니다.

대표적으로는 표준화(Standardization)와 정규화(Normalization)가 있습니다.

 

표준화: 데이터의 피처들 각가의 평균이 0이고 분산이 1인 가우시안 정규 분포를 가진 값으로 변환해주는 것입니다.

표준화 식

 

 

정규화: 서로 다른 피처들의 크기를 통일하기 위해 크기를 변화해주는 것입니다. 예를들어 A피처는 값이 0~100KM 거리를 나타내고 B피처는 0~100,000,000,00으로 금액을 나타낸다고 했을때 이 변수들을 동일한 크기의 단위로 값을 최소 0~ 최대 1의 값으로 변환한다고 생각하면 됩니다.

정규화 식

 

  • 사이킷런에서 제공해 주는 대표적인 피처 스케일링 클래스인 StandardScalerMinMaxScaler에 대해 알아보겠습니다.

 

StandardScaler


- StandardScaler은 표준화를 쉽게 지원해 주는 함수입니다. 다시 설명하자면 피처들을 평균이 0이고 분산이 1인 값으로 변환을 시켜줍니다. 서포트 벡터 머신(Support Vector Machine), 선형 회귀(Linear Regression), 로지스틱 회귀(Logistic Regression)과 같은 가우시안 분포를 가지고 있다고 가정을 하고 구현된 ML 알고리즘들은 표준화를 적용하는 것이 예측 성능 향상에 중요한 요소로 작용될 수 있습니다.

 

In

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)

print('feature 평균')
print(iris_df.mean())
print('\nfeature 분산')
print(iris_df.var())

예제 데이터로 iris 데이터를 사용하겠습니다.

 

out

feature 평균
sepal length (cm)    5.843333
sepal width (cm)     3.057333
petal length (cm)    3.758000
petal width (cm)     1.199333
dtype: float64

feature 분산
sepal length (cm)    0.685694
sepal width (cm)     0.189979
petal length (cm)    3.116278
petal width (cm)     0.581006
dtype: float64

다음으로 StandardScaler을 사용해서 표준화를 진행해보겠습니다.

 

In

from sklearn.preprocessing import StandardScaler

scaler=StandardScaler()
scaler.fit(iris_df)
iris_scaled=scaler.transform(iris_df)

StandardScaler() 객체를 생선한 후 fit(), transform()을 호출하여 줍니다.

iris_df_scaled=pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature 평균')
print(iris_df_scaled.mean())
print('\nfeature 분산')
print(iris_df_scaled.var())

Out

feature 평균
sepal length (cm)   -1.690315e-15
sepal width (cm)    -1.842970e-15
petal length (cm)   -1.698641e-15
petal width (cm)    -1.409243e-15
dtype: float64

feature 분산
sepal length (cm)    1.006711
sepal width (cm)     1.006711
petal length (cm)    1.006711
petal width (cm)     1.006711
dtype: float64

피처 값들이 평균은 0에 가까운, 분산은 1에 가까운 값으로 변환된 것으로 보아 표준화가 적용이 잘 된 것을 알 수 있습니다.

 

MinMaxScaler


- MinMaxScaler은 데이터의 값들을 0과 1사이의 범위 값으로 변환하여 줍니다. 데이터들의 분포가 가우시안 분포가 아닐 경우에 적용을 해 볼 수 있습니다.

 

In

from sklearn.preprocessing import MinMaxScaler

scaler=MinMaxScaler()
scaler.fit(iris_df)
iris_scaled=scaler.transform(iris_df)

iris_df_scaled=pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature 최솟값')
print(iris_df_scaled.min())
print('/\fearure 최댓값')
print(iris_df_scaled.max())

Out

feature 최솟값
sepal length (cm)    0.0
sepal width (cm)     0.0
petal length (cm)    0.0
petal width (cm)     0.0
dtype: float64
/earure 최댓값
sepal length (cm)    1.0
sepal width (cm)     1.0
petal length (cm)    1.0
petal width (cm)     1.0
dtype: float64

피처들이 0~1사이의 값으로 변환이 잘 된 것을 알수 있습니다.

 

스케일링 변환 시 주의사항


데이터의 스케일링을 적용할때 fit(), transform(), fir_trnsform() 함수를 사용합니다. 하지만 이 함수들을 적용할 때 주의!!할 부분이 있습니다.

 

바로!! 학습 데이터로 fit(), transform()을 적용하고 테스트 데이터에서 다시 fit()을 수행하지 않고 학습데이터로 fit() 적용한 결과를 이용해서 transform()을 적용해야 한다는 것입니다.

→ 그 이유는 테스트 데이터로 다시 새로운 스케일링 기준을 만들어 버리면 학습 데이터와 테스트 데이터의 스케일링 기준 정보가 달라지기 때문입니다.

 

  • 예제를 통해서 문제가 발생하는 부분을 파악해봅시다.

In

from sklearn.preprocessing import MinMaxScaler
import numpy as np

train_array=np.arange(0,11).reshape(-1,1)
test_array=np.arange(0,6).reshape(-1,1)

학습 데이터를 0~11, 테스트 데이터를 0~5까지의 값을 가지게 ndarray를 만들어 줍니다.

sclaer=MinMaxScaler()
scaler.fit(train_array)
train_scaled=scaler.transform(train_array)

print('원본 train_array:', np.round(train_array.reshape(-1),2))
print('scale이 적용된 train_array:', np.round(train_scaled.reshape(-1),2))

Out

원본 train_array: [ 0  1  2  3  4  5  6  7  8  9 10]
scale이 적용된 train_array: [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]

MinMaxScaler 객체의 fit()과 transform()적용하여 1->0.1, 2->0.2로 변환게 된 것을 확인하였습니다.

 

테스트 데이터의 fit()을 다시 적용해 문제점을 보겠습니다.

 

In

scaler.fit(test_array)
test_scaled=scaler.transform(test_array)

print('원본 test_array:', np.round(test_array.reshape(-1),2))
print('scale이 적용된 test_array:', np.round(test_scaled.reshape(-1),2))

Out

원본 test_array: [0 1 2 3 4 5]
scale이 적용된 test_array: [0.  0.2 0.4 0.6 0.8 1. ]

- 결과를 보면 학습 데이터와 테스트의 스케일링이 맞지 않은것을 알 수 있습니다. 테스트의 경우 최솟값 0, 최댓값 5가 되어 1->0.2, 2->0.4로 변환이 되었습니다. ML 모델은 학습 데이터를 기반으로 학습이 되기 때문에 반드시 ㅔ스트 데이터는 학습 데이터의 스케일링 기준을 따라야 합니다. 따라서 테스트 데이터에는 다시 fit()을 적용해서는 안됩니다.

 

  • 다음은 테스트 데이터에 fit()을 적용하지 않고 학습 데이터의 fit()을 적용한 것을 활용해 보겠습니다.

In

scaler=MinMaxScaler()
scaler.fit(train_array)
train_scaled=scaler.transform(train_array)
print('원본 train_array:', np.round(train_array.reshape(-1),2))
print('scale이 적용된 train_array:', np.round(train_scaled.reshape(-1),2))

test_scaled=scaler.transform(test_array)
print('원본 test_array:', np.round(test_array.reshape(-1),2))
print('scale이 적용된 test_array:', np.round(test_scaled.reshape(-1),2))

 Out

원본 train_array: [ 0  1  2  3  4  5  6  7  8  9 10]
scale이 적용된 train_array: [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]
원본 test_array: [0 1 2 3 4 5]
scale이 적용된 test_array: [0.  0.1 0.2 0.3 0.4 0.5]

출력 결과를 보면 학습 데이터, 데스트 데이터 모두 동일하게 변환된 것을 알 수 있습니다.

 

 

 

 

Reference


파이썬 머신러닝 완벽가이드