AI 머신러닝 딥러닝/파이썬 머신러닝 입문 공부일지

파이썬 머신러닝 입문 공부일지 16. 데이터 전처리 (2) 피처 스케일링 (StandardScaler, MinMaxScaler)

Tomitom 2023. 1. 6. 14:29
반응형

 

피처 스케일링 

 

데이터 전처리 과정 중 서로 다른 변수의 값 범위를 일정한 수준으로 맞추는 작업을 피처 스케일링 이라고 합니다. 

대표적으로는 두 가지가 있습니다. 

 

  • 표준화 Standardization  : 데이터 피처의 평균이 0 이고 분산이 1인 가우시안 정규 분포를 가진 값으로 변환하는 것입니다. 가우시안 분포란 자연 현상에서 나타나는 숫자를 확률 모형으로 나타낼 때 사용하는 분포 입니다. 수집된 자료의 분포를 근사하는데 자주 사용되며, 엎어진 종 모양을 가져요. 

 

 

https://recipesds.tistory.com/entry/%EA%B0%80%EC%9A%B0%EC%8B%9C%EC%95%88Gaussian-%EC%A0%95%EA%B7%9C%EB%B6%84%ED%8F%ACNormal-Distribution-%EB%84%88%EB%9E%80-%EB%B6%84%ED%8F%AC-%EC%A0%95%EB%A7%90

 

 

  • 정규화 Normalization : 일반적인 정규화는 서로 다른 피처의 크기를 통일하기 위해 크기를 변환해주는 개념입니다. 예를 들어 거리를 나타내는 변수의 값이 0~100km 로 주어지고, 금액을 나타내는 값이 0~100,000,000원으로 주어질 때 이 변수를 동일한 크기 단위로 비교하기 위해 값을 최소 0 ~ 최대 1으로 변환하는 것입니다. (즉 개별 데이터 크기를 비교하기 쉽도록 모두 똑같은 단위로 변환!)

 

일반적인 정규화

 

그런데 사이킷런에서 제공하는 Normaliztion 모듈은 일반적인 정규화와는 달리 선형대수의 정규화 개념이 사용됩니다. 즉, 개별 벡터의 크기를 맞추기 위해 변환하는 것으로 개별 벡터를 모든 피처 벡터의 크기로 나눠줍니다. 

 

벡터 정규화

 

본 공부에서는 일반적인 의미의 표준화와 정균화를 피처 스케일링 으로 통칭하고 

선형대수 개념의 정규화를 벡터 정규화로 지칭합니다. 

 

이제 대표적인 피처 스케일링 클래스인 StandardScaler 와 MinMaxScaler를 알아보겠습니다. 

 

StandardScaler

 

표준화를 위한 클래스 입니다. 

개별 피처를 평균이 0이고 분산이 1인 값으로 변환하여 가우시안 정규 분포를 가지게끔 합니다. 

사이킷런에서는 서포터즈 벡터 머신, 선형 회귀, 로지스틱 회귀에서 데이터가 가우시안 분포를 가지고 있는 것을 가정하고 있기 때문에 사전에 표준화를 적용하는 것은 예측 성능 향상에 중요한 요소가 됩니다. 

 

지금까지 계속 써온 붓꽃 데이터로 데이터 값을 변환하는지 확인해볼게요. 

우선 붓꽃 데이터를 불러와서 데이터 프레임으로 변환한 뒤 

각 피처의 평균 값과 분산 값을 구합니다. 

 

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('붓꽃 피처의 평균 값')
print(iris_df.mean())
print('\n붓꽃 피처의 분산 값')
print(iris_df.var())

 

산발적으로 흩어져있는 값들을 확인할 수 있습니다. 

이제 StandardScaler 를 이용해서 각 피처를 한꺼번에 표준화하고 변환하겠습니다. 

 

fit()과 transform() 메서드에 변환 대상 피처 데이터 프레임 세트를 입력하고 호출합니다. 

transform() 을 호출할 때 스케일 변환된 데이터 세트는 넘파이의 ndarray 이므로

데이터 프레임으로 변환해 평균값과 분산값을 다시금 확인해봅니다. 

 

from sklearn.preprocessing import StandardScaler

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

# 넘파이의 ndarray이므로 데이터 프레임으로 다시 변환하여 평균값과 분산값을 구한다. 

iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)

print('붓꽃 피처의 평균 값')
print(iris_df_scaled.mean())
print('\n붓꽃 피처의 분산 값')
print(iris_df_scaled.var())

 

 

 

모든 칼럼의 값 평균이 0 에 아주 가까운 값으로 변환되고, 분산은 1에 아주 가까운 값으로 변환되었음을 알 수 있습니다. 

 

MinMaxScaler

이 다음에는 MinMaxScaler (최소, 최대화 스케일링) 에 대해서 알아봅니다.

MinMaxScaler 는 데이터의 값을 0과 1 사이의 범위 값으로 변환합니다. 

(음수 값은 -1 에서 1로 변환해요.) 

 

데이터의 분포가 가우시안 분포가 아닐 경우에 Min, Max, Scale을 적용해볼 수 있습니다. 

코드를 통해 확인해볼게요. 

 

from sklearn.preprocessing import MinMaxScaler

mm = MinMaxScaler()
mm.fit(iris_df)
iris_mm = mm.transform(iris_df)

iris_df_mm = pd.DataFrame(data=iris_mm, columns=iris.feature_names)

print("붓꽃 피처의 최솟값")
print(iris_df_mm.min())
print("\n붓꽃 피처의 최댓값")
print(iris_df_mm.max())

 

모든 피처의 값이 0과 1 사이의 값으로 변환되었음을 알 수 있습니다. 

 

 

 

반응형

 

 

학습 데이터와 테스트 데이터의 스케일링 변환시 유의할 점

 

스케일러 객체를 이용해 데이터 스케일링 변환 시에 우리가 사용하는 메소드들이 있습니다. 

  • fit() : 데이터 변환을 위한 기준 정보 설정 (데이터 세트의 최댓값/최솟값 설정 등) 
  • transform() : 설정된 정보를 바탕으로 데이터를 변환
  • fit_transform() : fit()과 transform()을 한꺼번에 적용

여기에서 우리가 스케일링을 하기 위해 학습 데이터에 fit() 과 transform()을 진행했다면 

테스트 데이터에서는 fit() 을 다시 수행해서는 안 되며, 

학습 데이터 세트에서 진행한 fit() 결과를 이용해 transform() 변환을 적용해야 합니다. 

만약 테스트 데이터에서도 다시 fit() 을 해서 새로운 기준 정보를 설정하게 된다면 학습 데이터와 테스트 데이터의 기준 정보 설정이 달라지기 때문에 올바른 예측 결과가 나오지 않을 수 있습니다. 

 

어떤 문제가 발생하는지 예를 들어서 확인해볼게요. 

 

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~10 까지의 배열과

테스트 데이터 0~5 까지의 배열을 생성했습니다. 

 

우선 학습 데이터에 대해서 fit() 과 transform()을 진행합니다.

0 부터 10까지의 값을 0부터 1까지의 값으로 스케일링하게 된다면

학습 데이터는 10분의 1의 값으로 Scale이 적용되게 됩니다.

1은 0.1로, 2는 0.2로 바뀌겠죠.

 

scaler = MinMaxScaler()

scaler.fit(train_array)
train_sacler = scaler.transform(train_array)

print('원본 학습 데이터 : ', np.round(train_array.reshape(-1),2))
print('스케일링 된 학습 데이터 : ', np.round(train_sacler.reshape(-1),2))

 

중간에 reshape()에 -1이 있는 것은 다음과 같은 의미를 가집니다. 

  • reshape(-1, 정수) 일 때, 정수에 따라서 10개의 원소가 해당 열의 개수만큼 자동으로 구조화 됩니다. 
  • reshape(정수, -1) 일 때, 정수에 따라서 10개의 원소가 해당 행의 개수만큼 자동으로 구조화 됩니다. 
  • reshape(-1) 일 때, -1만 단독으로 있을 경우 원래 배열의 길이와 남는 차원으로부터 추정되어 알아서 배열하라는 뜻입니다. 

이번엔 테스트 데이터 세트를 변환하는데, fit() 을 다시 호출해서 사용해보겠습니다.

테스트 데이터는 1~5까지가 있으므로 데이터는 5분의 1값으로 Scale이 적용됩니다. 

 

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

print('원본 학습 데이터 : ', np.round(test_array.reshape(-1),2))
print('스케일링 된 학습 데이터 : ', np.round(test_sacled.reshape(-1),2))

 

이렇게 출력 결과를 확인하면 학습 데이터와 테스트 데이터의 스케일링이 맞지 않습니다. 

 

머신러닝 모델은 학습 데이터를 기반으로 학습되기 때문에,

반드시 테스트 데이터는 학습 데이터의 스케일링 기준에 따라야 하며

테스트 데이터의 1값은 학습데이터와 동일하게 0.1 값으로 변환이 되어야 합니다. 

 

이번엔 테스트 데이터에 fit()을 호출하지 않고 학습데이터로 fit()을 수행한뒤 fransform()으로 변환해보겠습니다. 

위 코드 두 개를 복사 붙여넣기하고 테스트 데이터의 fit() 코드 줄만 삭제할게요. 

 

scaler = MinMaxScaler()
scaler.fit(train_array)
train_sacler = scaler.transform(train_array)

print('원본 학습 데이터 : ', np.round(train_array.reshape(-1),2))
print('스케일링 된 학습 데이터 : ', np.round(train_sacler.reshape(-1),2))

test_sacled = scaler.transform(test_array)

print('\n원본 학습 데이터 : ', np.round(test_array.reshape(-1),2))
print('스케일링 된 학습 데이터 : ', np.round(test_sacled.reshape(-1),2))

 

 

학습 데이터와 테스트 데이터 모두 10분의 1로 Scale이 조정된 것을 확인할 수 있습니다. 

여기까지 피처 스케일링에 대해서 알아보았습니다. 

 

 

 

 

반응형