본문 바로가기

AI Study/Machine Learning

데이터 전처리 기본 (2) - feature scailing

피처 스케일링과 정규화

 

  • feature scaling : 서로 다른 변수의 값 범위를 일정한 수준으로 맞추는 작업
    • 대표적인 방법 : 표준화(Standardization) / 정규화(Normalization)

  • 표준화(Standardization) : data의 feature 각각을 평균 = 0, 분산 = 1인 가우시간 정규 분포를 가진 값으로 변환하는 것
    • $$ Xi(new) = \frac {Xi-mean(X)} {stdev(x)} $$
    • X : 표준화를 통해 변환될 feature
    • Xi : feature X의 i번째 데이터
    • Xi(new) : feature X의 i번째 데이터를 표준화한 것
    • mean(X) : feature X의 평균
    • stdev(X) : feature X의 표준편차

  • 정규화(Normalization) : 서로 다른 feature의 크기를 통일하기 위해 크기를 변환함. 변수를 모두 동일한 크기 단위로 비교하기 위해 값을 모두 최소 0 ~ 최대 1의 값으로 변환함. 즉, 개별 데이터의 크기를 모두 똑같은 단위로 변경함.
    • $$ Xi(new) = \frac {Xi-min(X)} {max(X)-min(X)} $$

  • sklearnNormalizer module의 정규화 : 벡터 정규화임. 위의 정규화와 약간 다름.
    • 선형대수에서의 정규화 개념을 따름.
    • 개별 벡터의 크기를 맞추기 위해 변환하는 것을 의미함. 즉, 개별 벡터를 모든 feature vector의 크기로 나눠줌
    • $$ Xi(new) = \frac {Xi} {\sqrt (Xi^2 + Yi^2 + Zi^2)} $$

  • 혼용을 방지하기 위해 일반적 의미의 표준화&정규화 = feature scailing으로 통칭

  • 선형대수 개념의 정규화는 벡터 정규화로 지칭할 것
 

StandardScaler

  • 표준화를 쉽게 지원하기 위한 Class
  • 개별 feature의 평균이 0, 분산이 1인 값으로 변환해줌.
  • data가 가우시간 정규 분포를 가지도록 변환하는 것의 중요성
    • 서포트 벡터 머신(Support Vector Machine)
    • 선형 회귀(Linear Regression)
    • 로지스틱 회귀(Logistic Regression)
    • 위의 3개 모델의 경우 데이터가 가우시간 분포를 가진다고 가정하고 구현됐기 때문에 사전에 데이터 변환 작업이 예측 성능 향상에 중요한 요소가 될 수 있음.
In [31]:
from sklearn.datasets import load_iris
import pandas as pd
# 붓꽃 데이터 셋을 로딩하고 DataFrame으로 변환합니다. 
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())
 
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
 
In [32]:
from sklearn.preprocessing import StandardScaler

# StandardScaler객체 생성
scaler = StandardScaler()
# StandardScaler 로 데이터 셋 변환. fit( ) 과 transform( ) 호출.  
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)

#transform( )시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature 들의 평균 값') # 0에 거의 근사한 값으로 변환됨
print(iris_df_scaled.mean())
print('\nfeature 들의 분산 값') # 1에 근사한 값으로 변환됨
print(iris_df_scaled.var())
 
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
 

MinMaxScaler

  • 정규화를 지원하기 위한 Class
  • 데이터 값을 0과 1 사이의 범위 값으로 변환
    • 음수가 있다면 -1에서 1 사이로 변환함
  • 데이터의 분포가 가우시간 분포가 아닐 경우에 Min, Max Scale을 적용할 수 있음
In [33]:
from sklearn.preprocessing import MinMaxScaler

# MinMaxScaler객체 생성
scaler = MinMaxScaler()
# MinMaxScaler 로 데이터 셋 변환. fit() 과 transform() 호출.  
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)

# transform()시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature들의 최소 값')
print(iris_df_scaled.min())
print('\nfeature들의 최대 값')
print(iris_df_scaled.max())
 
feature들의 최소 값
sepal length (cm)    0.0
sepal width (cm)     0.0
petal length (cm)    0.0
petal width (cm)     0.0
dtype: float64

feature들의 최대 값
sepal length (cm)    1.0
sepal width (cm)     1.0
petal length (cm)    1.0
petal width (cm)     1.0
dtype: float64
 
  • Scaler를 이용하여 학습 데이터와 테스트 데이터에 fit(), transform(), fit_transform() 적용 시 유의사항.
  • 여기서 fit / transform을 사용하는데 목적은?
    • fit()은 데이터 변환을 위한 기준 정보 설정(예를 들면 data set의 max/mix 값 설정 등)을 적용해줌.
    • transform()은 설정된 정보를 이용해 데이터를 변환함.
    • fit_transform()은 fit() + transform()을 한번에 적용하는 기능을 수행함
  • ※training data set, test data set에 fit / transform 적용 : 주의 필요※
    • Scaler 객체를 이용해 training data set로 fit, transform을 적용하면
    • test data set로는 다시 fit을 수행하지 않고, 그냥 앞서 training data set로 fit()을 수행한 결과를 이용해 transform() 변환을 적용해야 한다는 것
    • 즉, train data로 fit()이 적용된 스케일링 정보를 test data에 그대로 적용해야 함!
    • #### 정리 : train에 대해 fit + transform -> test에는 transform
 

↓ train data의 fit()을 그대로 안쓰고 test data에도 fit()을 쓸 때의 문제점 예시

 
In [34]:
from sklearn.preprocessing import MinMaxScaler
import numpy as np

# 학습 데이터는 0 부터 10까지, 테스트 데이터는 0 부터 5까지 값을 가지는 데이터 세트로 생성
# Scaler클래스의 fit(), transform()은 2차원 이상 데이터만 가능하므로 reshape(-1, 1)로 차원 변경
train_array = np.arange(0, 11).reshape(-1, 1)
test_array =  np.arange(0, 6).reshape(-1, 1)
 
In [35]:
# 최소값 0, 최대값 1로 변환하는 MinMaxScaler객체 생성
scaler = MinMaxScaler()
# fit()하게 되면 train_array 데이터의 최소값이 0, 최대값이 10으로 설정.  
scaler.fit(train_array)
# 1/10 scale로 train_array 데이터 변환함. 원본 10-> 1로 변환됨.
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))
 
원본 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. ]
 
In [36]:
# 앞에서 생성한 MinMaxScaler에 test_array를 fit()하게 되면 원본 데이터의 최소값이 0, 최대값이 5으로 설정됨 
scaler.fit(test_array)
# 1/5 scale로 test_array 데이터 변환함. 원본 5->1로 변환.  
test_scaled = scaler.transform(test_array)
# train_array 변환 출력
print('원본 test_array 데이터:', np.round(test_array.reshape(-1), 2))
print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))
 
원본 test_array 데이터: [0 1 2 3 4 5]
Scale된 test_array 데이터: [0.  0.2 0.4 0.6 0.8 1. ]
 
In [37]:
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_array에 Scale 변환을 할 때는 반드시 fit()을 호출하지 않고 transform() 만으로 변환해야 함. 
test_scaled = scaler.transform(test_array)
print('\n원본 test_array 데이터:', np.round(test_array.reshape(-1), 2))
print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))
 
원본 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]