ML/사이킷런

데이터전처리- 스케일링

야뤼송 2024. 2. 6. 09:04
반응형

 

1. 스케일링이란?

데이터 스케일링이란 피처들마다 데이터값의 범위가 다 다르기 때문에 그 차이가 큰 경우 모델 학습 시 0 또는 무한으로 학습될 수 있다.

이러한 잘못된 학습을 피하기 위해변수의 값 범위(또는 분포)를 일정한 수준으로 조정해주는데 이러한 작업을 데이터 스케일링이라고 한다.

 

2.표준화

표준화는 데이터의 피처 각각이 평균이 0이고 분산이 1인 가우시안 정규 분포를 가진 값으로 변화하는 것을 의미한다.

표준화는 데이터 분포의 중심을 0으로 맞추게된다.

 

예를 들어  [20, 30, 40]을 가진 데이터가 있다고 가정한다. 이 데이터의 평균은 30이고 표준 편자는 8.16이다.

표준화를 구할 때는 Z-score 변환을 통해 구하게 되는데 다음과 같은 공식으로 계산이 된다.

위의 피처 데이터 중 20의 Z-score을 구해보면 -1.22 = 20 -30 / 8.16 로 구할 수 있고 이렇게 계산된 값들은 [-1.22, 0, 1.22] 이다.

 

참고) 가우시안 정규 분포 : 정규 분포의 가장 대표적인 꼴로 대칭을 이루는 종모양의 분포를 말한다.

출처 : 위키피디아

 

 실습

사이킷런에서는 표준화 처리를 위해 StandardScaler 클래스를 제공하고 있다. 실습은 붓꽃 데이터를 통해 확인해보자

먼저 피처들의 평균과 분산 값들을 구하면 다음과 같다.

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())

▶ 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 클래스에서는 fit(), transform()를 각각 호출하거나 fit + transform을 한번에 할 수 있는 fit_transform() 함수를 호출하여 표준화 처리를 할 수 있다.

fit() + transform()을 이용한 경우는 아래와 같으며 transform( )시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환한다.

from sklearn.preprocessing import StandardScaler

# StandardScaler객체 생성
scaler = StandardScaler()
# StandardScaler 로 데이터 셋 변환. fit( ) 과 transform( ) 호출.  
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.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

 

 

fit_transform() 함수를 호출한 결과는 다음과 같으며 fit(), transform() 각각 호출한 결과와 같음을 확인할 수 있다.

#fit + transform을 한번에
iris_fit_trnans = scaler.fit_transform(iris_df)
iris_df_scaled = pd.DataFrame(data=iris_fit_trnans, 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

 

 

3. 정규화

정규화는 서로 다른 피처의 크기를 통일하기 위해 크기를 변환해주는 개념이다.

 

예를 들어 아래와 같이 [20, 30, 40]을 가진 데이터가있다고 가정한다. 정규화는 가장 작은 값은0, 큰 값은 1로 변환하고 나머지 값들은 [0,1]의 범위를 갖게 된다.

 

 실습

사이킷런에서는 정규화 처리를 위해 MinMaxScaler 클래스를 제공하고 있다.

실습은 표준화와 동일한 데이터셋인 붓꽃 데이터를 통해 확인해보자.

 

MinMaxScaler 클래스에서는 fit(), transform(), 그리고 fit()과 transform()을 한번에 수행하는 fit_transform()를 호출하여 정규화 값을 구할 수 있다.

아래는 fit(), transform()을 각각 호출한 예제이다.

from sklearn.preprocessing import MinMaxScaler
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)

# 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())

▶ Out

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

 

 

또한, fit_transform()을 호출하여 정규화 과정을 수행가능하며 그 결과는 위와 동일함을 확인할 수 있다.

iris_fit_trnans = scaler.fit_transform(iris_df)

iris_df_scaled_trnas = pd.DataFrame(data=iris_fit_trnans, columns=iris.feature_names)
print('feature들의 최소 값')
print(iris_df_scaled_trnas.min())
print('\nfeature들의 최대 값')
print(iris_df_scaled_trnas.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

feature들의 최대 값
sepal length (cm)    1.0
sepal width (cm)     1.0
petal length (cm)    1.0
petal width (cm)     1.0
dtype: float64

 

 

4. MinMaxScaler fit(), transform() 사용 시 주의사항

 

학습할때의 스케일러 척도와 예측할때의 척도가 서로 다른 경우 문제가 발생하게 된다.

 

 실습

먼저 학습 데이터는 0 부터 10까지, 테스트 데이터는 0 부터 5까지 값을 가지는 데이터 세트로 생성한다.
Scaler클래스의 fit(), transform()은 2차원 이상 데이터만 가능하므로 reshape(-1, 1)로 차원을 변경해준다.

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)

train_array, test_array, train_array.shape

▶ Out

(array([[ 0],
        [ 1],
        [ 2],
        [ 3],
        [ 4],
        [ 5],
        [ 6],
        [ 7],
        [ 8],
        [ 9],
        [10]]),
 array([[0],
        [1],
        [2],
        [3],
        [4],
        [5]]),
 (11, 1))

 

 

정규화 수행 시 학습용 데이터는 0~10까지의 데이터를 가지고 Scal을 진행하였고 0은 0.1, 5는 0.5로 학습, 10은 1로 변환이 된다.

# 최소값 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))

▶ 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. ]

 

 

테스트 용으로 생성한 array는 0~5까지 데이터로,  min,max 값을 만들게 되고 0은 0으로, 5는 1로 변환이 된다.

학습에서 변환된 1의 원본 데이터 값은 10이지만, 테스트에서 변환된 1의 원본 데이터 값은 5가 된다.

그러다 보니 학습할때의 스케일러 척도와 예측할때의 척도가 같아야하지만 서로 상이한 문제가 발생하게 된다.

# 앞에서 생성한 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))

▶ Out

원본 test_array 데이터: [0 1 2 3 4 5]
Scale된 test_array 데이터: [0.  0.2 0.4 0.6 0.8 1. ]

 

 

위의 문제를 해결하기 위해 학습용 데이터 기준으로 fit()하여 학습하고 이 fit()이 적용된 값을 가지고 학습용과 테스트용 각각 transform 해줘야지만 동일한 기준을 가지고 정규화 값이 나오게 된다.

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))

▶ 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]

 

 

5. 표준화, 정규화 각각 언제 사용될까?

 

표준화는 데이터의  분포가 정규 분포에 가깝거나 특성 간 스케일 차이가 크게 날 때 효율적이다. 특히, 대다수의 선형 모델이나 신경망에서 사용이 된다.

 

정규화는 주로 입력 데이터의 분호가 크게 차이나지 않고, 모델이 각 특성의 중요도를 동등하게 간주할 때 유용한다.

 

어떤 방법을 선택할지 결정하는 것은 결국 데이터의 특성, 모델의 요구사항을 고려해서 선택해야한다. 일반적으로 표준화가 더 안정적이며, 대다수의 경우에서 효과적으로 사용이 된다. 그러나 특정 모델이나 데이터의 특성에 따라 정규화가 더 적합할 수 있다.

 

반응형