` 1

신경망(Neural Network)뿐 아니라 대부분 모델에서 학습을 수행하기 전에 데이터 값의 범위를 정규화(Normalization), 표준화(Standardization) 하는 것은 매우 중요합니다.

이러한 처리 방법을 사용해서 값의 범위를 비슷하게 만들거나 평균이 1인 정규 분포 형태로 만들어주는 것은 학습 시에 큰 도움이 됩니다.

하지만 현실 데이터에선 값의 범위가 균형적(balanced)이거나 정규분포 형태를 거의 보기 어렵고, 주로 꼬리가 치우친(Skewed or unbalanced) 형태를 띄고 있는데요. Skewed Data는 모델 입력으로 사용하기 전, 전처리 과정(Preprocessing or Engineering)에서 어떤 처리 방법을 사용할지 한번쯤은 고민하게 만드는 골치아픈 데이터입니다.

출처: 위키백과

이때, 기본적으로 세 가지 방법을 후보로 생각해볼 수 있습니다.

  1. Min-Max Scaler; 정규화
  2. Standard Mean/Std Scaler; 표준화
  3. Apply Log-function; 로그화

이 방법들을 통해 성능을 많이 향상시킬 수 있는데, 이뿐 아니라 Gaussian Rank 방법을 추가로 고려해볼 수 있습니다.

Gaussian Rank 방법은 Numeric Feature Distribution을 Normal Distribution으로 변형시켜줍니다.

  1. -1 ~ 1 사이의 값(clipped value)을 순서(sorted)매깁니다.
  2. 순서 값에 오차역함수(inverse error function)을 적용하여 마치 Normal Distribution처럼 만듭니다.

오차역함수(inverse error function)

Gaussian Rank 방법은 Porto Seguro's Safe Driver Prediction(캐글 대회, 아래 URL 참고) 1등 솔루션 인터뷰를 보면,
Min-Max Scaler나 Standard mean/std Scaler보다 더 좋은 성능으로 가장 좋았다고 나와있습니다.

 

Porto Seguro’s Safe Driver Prediction | Kaggle

 

www.kaggle.com

 

총 세 가지 구현 방법을 찾게되었는데, 아래 세 개 코드를 참고하시길 바랍니다.

  1. NumPy 구현 - 1 (Github 참조) : https://github.com/affjljoo3581/Job-Recommend-Competition
  2. NumPy 구현 - 2 (Kaggle 참조) : https://www.kaggle.com/tottenham/10-fold-simple-dnn-with-rank-gauss
  3. sklearn - QuantileTransformer 활용 (Kaggle 참조)
    https://www.kaggle.com/kushal1506/moa-pytorch-0-01859-rankgauss-pca-nn

< 공통 사용 모듈 Import >

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from scipy.special import erfinv
from sklearn.preprocessing import QuantileTransformer

np.random.seed(42)

먼저, 예제로 사용할 더미 데이터를 생성합니다.

# 데이터 생성
X = (np.random.randn(200, 1) * 5 + 10) ** 2
df = pd.DataFrame(X)
df.head()

 

1. NumPy 구현 - 1

Gaussian Rank 적용

epsilon = 1e-4
noise_scale = 0.001

gaussian_noise = np.random.normal(0, 1, df[df.columns[0]].shape)
transformed_data = df[df.columns[0]] + noise_scale * df[df.columns[0]].max() * gaussian_noise

data_rank = np.argsort(np.argsort(transformed_data))
data_rank = 2 * data_rank / data_rank.max() - 1

clipped_data_rank = np.clip(data_rank, -1 + epsilon, 1 - epsilon)
# 오차역함수 적용
transformed_data = erfinv(clipped_data_rank)

결과 확인

plt.figure(figsize = (10, 5))

plt.subplot(1, 2, 1)
plt.hist(df[df.columns[0]])
plt.title('Before')

plt.subplot(1, 2, 2)
plt.hist(transformed_data)
plt.title('After Gaussian Rank')

plt.tight_layout()
plt.show()

Gaussian Rank - 1

2. NumPy 구현 - 2

함수 정의

def rank_gauss(x):
    N = x.shape[0]
    temp = x.argsort()
    
    rank_x = temp.argsort() / N
    rank_x -= rank_x.mean()
    rank_x *= 2
    
    efi_x = erfinv(rank_x)
    efi_x -= efi_x.mean()
    return efi_x
    
transformed_data = rank_gauss(df[df.columns[0]])

결과 확인

Gaussian Rank - 2

3. sklearn QuantileTransformer 활용

transformer = QuantileTransformer(n_quantiles=100,random_state=0, output_distribution="normal")
transformer.fit(X)

transfored_data = transformer.transform(X)

결과 확인

Gaussian Rank - 3