Sign In

[데이터 전처리] 수치형 변수 전처리

Y
Yerim
  1. ML
  2. DataAnalysis

피처 스케일링 feature scaling

•
피처 스케일링은 데이터의 값을 변환하는 것을 의미한다.
•
주어진 데이터의 범위를 계산을 통해 새롭게 바꾼다.
•
특정 알고리즘은 큰 범위를 가진 데이터에 가중치를 두기도 하고, 어떤 알고리즘은 학습 과정의 효율성에 영향을 미치기도 한다.

피처 스케일링 유의점

1.
스케일링은 분포를 바꾸는 작업이 아니다.
2.
스케일링은 이상치를 제거하는 작업이 아니다.
3.
꼭 필요한 작업인지, 어느 피처에 어떤 스케일러를 사용하는게 좋은지 생각해 보자.
4.
스케일링 함수는 정확하게 사용하다.
a.
.fit(): 스케일러가 사용하는 변수 정보 설정 (StandardScaler의 경우 평균, 표준편차)
b.
.transform(): 설정된 값을 바탕으로 피처 변환
c.
.fit_transform(): fit과 transform 모두 실행
5.
스케일러를 저장하는 습관을 갖자.

피처 스케일링 방법의 선택기준

표준화
정규화
목적
평균 0, 표준편차 1이 되도록 변환
2개 이상 피처에서 단위가 다를 때 표준화를 통해 같은 기준으로 비교 가능
피처 범위를 [0, 1] 혹은 특정 범위 [a, b]로 변환
표현 & 용어
표준화 (Standardization)
표준화를 Unit variano라고 표현
정규화 (Normalization)
파이썬 패키지
StandardScaler: 평균, 표준편차 사용
RoboustScaler: 중앙값, IQR 사용
MinMaxScaler: 최대/최솟값
MaxAbsScaler: 최대 절댓값
주요사항
기존 변수가 정규분포를 가질 때 더 적합
평균 0, 표준편차 1을 가진다고 해서 분포 자체가 표준 정규분포가 되지는 않음
분포가 바뀌지 않음
이상치에 민감
변환 후 표준편차가 줄어들 수 있음

표준화 Stnadardization

x_{scaled} = \frac{x-mean}{sd}
•
표준정규분포, z-score
•
평균이 1, 표준편차가 1을 갖도록 변환
•
표준편차 값이 1일 때 단위 분산 (Unit Variance)라고 한다.
•
표준화 작업이 피처를 표준정규분포로 바꿔주지는 않는다.
→ 평균, 표준편차는 변하지만 왜도와 첨도는 변하지 않음
•
이상치 영향을 받는다.

StandardScaler

•
표준화를 쉽게 지원하기 위한 클래스
•
개별 피처를 평균이 0이고 분산이 1인 값으로 변환
•
사이킷런 RBF 커널 SVM, 선형회귀, 로지스틱 회귀는 데이터가 가우신 반포 가정, 표준화를 적용하는 것은 예측 성능 향상에 중요한 요소
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())
•
StandardScaler 객체를 생성 후에 fit()과 trnasform() 메서드에 변환 대상 피처 데이터 세트를 입력하고 호출하면 간단하게 변환
•
transform()을 호출할 때 스케일 변환된 데이터 세트가 넘파이의 ndarray이므로 이를 DataFrame으로 변환해 평균값 분산값 다시 확인해야한다.
from sklearn.preprocessing import StandardScaler

# StandardScaler
scaler = StandardScaler()               # 객체생성
scaler.fit(iris_df)                     # fit
iris_scaled = scaler.transform(iris_df) # 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())
import matplotlib.pyplot as plt

iris_df_standarded= (iris_df - iris_df.mean()) / iris_df.std()

# 기존 데이터셋 시각화
plt.title('Origin Dataset')
plt.hist(iris_df)
plt.legend(iris_df.columns)
# 표준화한 데이터셋 시각
plt.title('Standarded Dataset')
plt.hist(iris_df_standarded)
plt.legend(iris_df_scaled.columns)

로버스트(Robus)

•
건강한, 강력한
•
이상치에 크게 영향받지 않는 통계치
•
ex) 중간값, 사분위 범위(Interquartiel Range; IQR)

Robust Scaling

x_{scaled} = \frac{x_i - Q_2}{Q_3 - Q_1}
•
4분위수 range
•
표준화에서는 mean, std값 이용하여 계산
•
robust는 median, IQR 이용하여 계산
•
로버스트 스케일을 진행한다고 이상치가 없어지거나 비대칭도가 줄어들지는 않는다.
from sklearn.preprocessing import RobustScaler

# RobustScaler
robust_scaler = RobustScaler()
robust_scaler.fit(iris_df)
iris_scaled = robust_scaler.transform(iris_df)

# 데이터프레임으로 변환
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())

정규화

x_{new} = \frac{x - x_{min}}{x_{max} - x_{min}}
•
새로운 x의 값은 x의 평균을 뺀 값을 피처 x의 표준편차로 나눈 값으로 계산
•
데이터의 범위를 0부터 1까지로 변환하여 데이터 분포를 조정하는 방법이다.
x_i new = \frac{x_i}{\sqrt{x_i^2 + y_i^2 +z_i^2}}
•
사이킷런 전처리에서 제공하는 Normalizer 모듈과 일반적인 정규화는 약간의 차이가 있음
•
사이킷런의 Normalizer 모듈은 선형대수에서의 정규화 개념 적용, 개별 벡터의 크기를 맞추기 위해 변환 의미
•
즉, 개별 벡터를 모든 피처 벡터의 크기로 나눔, 세 개의 피처 x,y,z가 있으면 새로운 데이터 x_new는 원래 값에서 세 개의 피처의 i번째 피처 값에 해당하는 크기를 합한 값으로 나눠줌 (정규 벡터화)
•
앞의 4가지 스케일러는 각 특성(열)의 통계치를 이용하여 진행됩니다.
•
그러나 Normalizer 의 경우 각 샘플(행)마다 적용되는 방식입니다.
•
이는 한 행의 모든 특성들 사이의 유클리드 거리(L2 norm)가 1이 되도록 스케일링합니다.
•
일반적인 데이터 전처리의 상황에서 사용되는 것이 아니라 모델(특히나 딥러닝) 내 학습 벡터에 적용하며,
•
특히나 피쳐들이 다른 단위(키, 나이, 소득 등)라면 더더욱 사용하지 않습니다.
from sklearn.preprocessing import Normalizer

# 변형 객체 생성
normal_scaler = Normalizer()
normal_scaler.fit(iris_df)

# 훈련 데이터 스케일링
X_train_scaled = normal_scaler.transform(iris_df)

# 데이터프레임 변환
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())

MinMax Scaler

x_{scaled} = \frac{x-x_{min}}{x_{max}-x_{min}}
•
최대/최솟값으로 범위 변환
•
피처 범위를 0과 1로, 혹은 특정 값으로 제한할 수 있다.
•
정규화를 진행해도 왜도, 첨도, 이상치 여부는 원래 값과 같다.
•
이상치의 영향을 많이 받는다.
•
데이터에 이상치가 있을 경우 최솟값 혹은 최댓값으로 설정된다.
•
따라서 스케일링 전 정리해야 할 이상치가 없는지 확인하는 것이 바람직하다.
from sklearn.preprocessing import MinMaxScaler

# 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('\nfeature들의 최댓값')
print(iris_df_scaled.max())
import matplotlib.pyplot as plt

iris_df_standarded= (iris_df - iris_df.max()) / (iris_df.max() - iris_df.min())

# 기존 데이터셋 시각화
plt.title('Origin Dataset')
plt.plot(iris_df)
plt.legend(iris_df.columns)
# 정규화한 데이터셋 시각
plt.title('Standarded Dataset')
plt.plot(iris_df_standarded)
plt.legend(iris_df_scaled.columns)
df = pd.DataFrame([[166, 18],
                  [172, 25],
                  [158, 30],
                  [182, 21],
                  [161, 26],
                  [155, 15]])
df.columns = ['height', 'age']
df_new = (df - df.min())/(df.max() - df.min())

# 시각화
plt.title('Origin Dataset')
plt.plot(df)
plt.legend(df.columns)
plt.title('Scaled Dataset')
plt.plot(df_new)
plt.legend(df_new.columns)

MAxAbsScaler

x_{scaled} = \frac{x_i}{abs(X_{max})}
•
절대값으로
•
피처 값을 최대 절댓값으로 나누면 스케일링 된 피처 범위가 -1에서 1 사이로 설정
•
피처 각 값에 최솟값을 빼지 않는 다는 것이 MinMax와 다르다.
•
데이터가 0인 것은 피처 스케일링 이후에도 0
•
피처에 0이 많으면 희소 데이터 (Sparse Data)라고 하는데, 스케일링 한 후에도 희소성 유지 가능
from sklearn.preprocessing import MaxAbsScaler

# MaxAbsScaler
maxabs_scaler = MaxAbsScaler()
maxabs_scaler.fit(iris_df)
iris_scaled = maxabs_scaler.transform(iris_df)

# 데이터프레임으로 변환
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())
import matplotlib.pyplot as plt

iris_df_standarded= (iris_df) / (iris_df.abs().max())

# 기존 데이터셋 시각화
plt.title('Origin Dataset')
plt.plot(iris_df)
plt.legend(iris_df.columns)
# 정규화한 데이터셋 시각
plt.title('Standarded Dataset')
plt.plot(iris_df_standarded)
plt.legend(iris_df_scaled.columns)
df = pd.DataFrame([[1.0, 18],
                  [0.8, 25],
                  [-0.5, 30],
                  [-1.8, 21],
                  [1.2, 26],
                  [0.6, 15]])
df.columns = ['sight', 'age']
df_new = df/df.abs().max()

# 시각화
plt.title('Origin Dataset')
plt.plot(df)
plt.legend(df.columns)
plt.title('Scaled Dataset')
plt.plot(df_new)
plt.legend(df_new.columns)
Yerim-DevNote
Subscribe to 'Yerim-DevNote'
Subscribe to my site to be the first to receive notifications and emails about the latest updates, including new posts.
Join Slashpage and subscribe to 'Yerim-DevNote'!
Subscribe
👍