이번 포스팅은 데이터 정규화(Normalisation)에 대해서 알아보도록 하겠습니다.
정규화(Normalisation)가 중요한 이유?
머신러닝 알고리즘은 데이터가 가진 feature(특성)들을 비교하여 데이터의 패턴을 찾습니다.
그런데 여기서 주의해야 할 점은 데이터가 가진 feature의 스케일이 심하게 차이가 나는 경우 문제가 되기 때문이다.
데이터의 차이는 모델의 성능을 좌우하기 때문에 신경망 같은 알고리즘들은 데이터의 스케일에 굉장히 민감합니다.
그래서 알고리즘들에 맞게 데이터의 특성 값들을 조절하게 되는데요, 보통 특성마다 스케일을 조정하여 데이터를 변경시킵니다.
예시를 한번 보겠습니다.
우선, 기본적으로 필요한 라이브러리를 임포트 해줍니다.
왼편의 그림은 데이터를 전처리 하기 전인 원본 데이터, 오른쪽은 각종 전처리 방법을 사용했을 때의 4가지 모습을 보여주고 있습니다.
본격적으로 전처리 방법에 대해 간단히 이야기해보겠습니다.
StandardScaler
scikit-learn의 StandardScaler는 각 특성의 평균을 0, 분산을 1로 변경하여 모든 특성이 같은 크기를 가지게 합니다. 하지만 최솟값과 최댓값 크기를 제한하지는 않습니다. 공식은 다음과 같습니다.
σ는 표준편차를 의미하고, x는 특성 값, 평균을 의미합니다. 이 결과를 표준 점수 또는 z-점수(z-score)라고도 합니다.
RobustScaler
RobustScaler는 일단 특성들이 같은 스케일을 갖게 된다는 것은 StandaradScaler와 비슷하나, 평균과 분산 대신 중간값 mediummedium과 사분위 값 quartilequartile을 사용합니다.
여기서 중간값이란 x보다 작은 수가 절반이고, x보다 큰 수가 절반인 x를 의미합니다. 단순히 평균이라고도 생각할 수 있는데요, 좌표 평면을 활용하기 때문에 각 사분위 별 개수가 중요합니다.
1 사분위 값은 x보다 작은 수가 전체 개수의 1/4인 x이고, 3 사분위는 x보다 큰 수가 전체 개수의 1/4인 x를 의미합니다. 공식은 다음과 같습니다.
q2는 중간값, q1은 1 사분위 값, q3은 3 사분위 값입니다.
이러한 방식 때문에 RobustScaler는 전체 데이터와 아주 동떨어진 데이터 포인트에 영향을 받지 않습니다. 이런 이상한 (멀리 떨어진 데이터)를 이상치(outlier) 라고 합니다. 이는 다른 스케일 조정 기법에서는 문제가 될 수도 있습니다.
MinMaxScaler
MinMaxScaler는 모든 특성이 정확하게 0과 1 사이에 위치하도록 데이터를 변경합니다. 2차원 데이터셋일 경우에는 모든 데이터가 x축의 0 ~ 1, y축은 0 ~ 1 사이의 사각 영역에 담기게 됩니다. 공식은 다음과 같습니다.
Normalizer
Normalizer는 매우 다른 스케일 조정 기법입니다. 이 방식은 특성 벡터의 유클리디안 길이가 1이 되도록 데이터 포인트를 조정합니다. 다른 정규 기법인 StandardScaler, RobustScaler, MinMaxScaler 기법은 특성들의 열 (특성)의 통계치를 사용하지만, Normalizer는 행(데이터 포인트)마다 각기 정규화됩니다.
다른 말로 하면 지름이 1인 원( 3차원 일 땐 구 )에 데이터 포인트를 투영하게 됩니다. 이 말은 각 데이터 포인트가 다른 비율로 (길이에 반비례하여) 스케일이 조정된다는 뜻이 됩니다. 이러한 정규화(normalizationnormalization)는 특성 벡터의 길이는 상관없고 데이터의 방향(또는 각도) 만이 중요할 때 많이 사용합니다.
데이터 변환 적용하기
여러 종류의 변환을 알아보았습니다. cancer 데이터셋에 커널 SVM(SVC)를 적용시키고 MinMaxScaler를 적용시켜 보겠습니다.
sklearn.preprocessing 모듈은 사이킷런에서 각종 전처리 작업을 위한 파이썬 클래스를 내장하고 있습니다.
MinMaxScaler 내부에는 fit 메서드가 존재합니다.
이 메서드는 모델을 훈련시키기 위해 존재하는 메서드가 아닌 각 특성마다의 최소, 최댓값을 계산해 줍니다.
따라서 특성을 의미하는 X_train만 넘겨줍니다.(y_train)은 사용하지 않습니다.
실제 fit 메서드를 통한 변환을 적용시키려면 transform() 메서드를 사용합니다.
transform은 새로운 데이터 표현(representation)을 만들 때 사용하는 메서드입니다.
변환된 배열 크기(shape)는 원본 배열과 동일합니다.
스케일 조정 후를 살펴보면 모든 특성의 최솟값과 최댓값이 각각 0과 1로 바뀐 것이 확인됩니다.
이 데이터에 SVM 모델을 적용하려면 테스트 데이터셋도 스케일 조정이 되어야 합니다. 이번엔 X_test를 조정하겠습니다.
이상하게도 똑같이 스케일을 조정했지만 0 또는 1이 나오지 않습니다. 그리고 0과 1의 범위를 넘어가 버리는 값도 존재하는 것이 확인됩니다.
모든 스케일 모델들은 항상 훈련 세트와 테스트 세트에 같은 변환을 적용시켜야 합니다. transform 메서드는 테스트 세트의 최솟값과 범위를 사용하지 않고, 항상 훈련 세트의 최솟값을 빼고 훈련 세트의 범위로 나눕니다. 간단하게 공식으로 살펴보면 다음과 같습니다.
훈련 데이터와 테스트 데이터의 스케일을 같은 방법으로 조정하기
지도 학습 모델에서 테스트 세트를 사용하려면 훈련 세트와 테스트 세트에 같은 변환을 적용해야 한다는 점이 중요합니다.
일단 이번 예제에서는 위와 반대로, 테스트 세트의 최솟값과 범위를 사용했을 때 어떤 일들이 일어나는지 보겠습니다.
from sklearn.datasets import make_blobs
# 인위적인 데이터 생성하기
X, _ = make_blobs(n_samples=50, centers=5, random_state=4, cluster_std=2)
# 훈련 세트와 테스트 세트로 나누기
X_train, X_test = train_test_split(X, random_state=5, test_size=.1)
# 훈련 세트와 테스트 세트의 산점도 그리기
fig, axes = plt.subplots(1,3,figsize=(13, 4))
axes[0].scatter(X_train[:, 0], X_train[:, 1], c=mglearn.cm2(0), label="훈련 세트", s=60)
axes[0].scatter(X_test[:, 0], X_test[:, 1],c=mglearn.cm2(1), label="테스트 세트", s=60, marker='^')
axes[0].legend(loc='upper left')
axes[0].set_title("원본 데이터")
# MinMaxScaler를 사용해 스케일 조정하기
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 스케일이 조정된 데이터의 산점도 그리기
axes[1].scatter(X_train_scaled[:, 0], X_train_scaled[:, 1], c=mglearn.cm2(0), label="훈련 세트", s=60)
axes[1].scatter(X_test_scaled[:, 0], X_test_scaled[:, 1], c=mglearn.cm2(1), label="테스트 세트", s=60, marker='^')
axes[1].set_title("스케일 조정된 데이터")
# 테스트 세트의 스케일을 따로 조정하기
# 테스트 세트의 최솟값은 0, 최댓값이 1이 됨
# 절대로 이렇게 사용하지 말것!
test_scaler = MinMaxScaler()
test_scaler.fit(X_test)
X_test_scaled_badly = test_scaler.transform(X_test)
# 잘못 조정된 데이터의 산점도 그리기
axes[2].scatter(X_train_scaled[:, 0], X_train_scaled[:, 1], c=mglearn.cm2(0), label="훈련 세트", s=60)
axes[2].scatter(X_test_scaled_badly[:, 0], X_test_scaled_badly[:, 1],
marker='^', c=mglearn.cm2(1), label="테스트 세트", s=60)
axes[2].set_title("잘못 조정된 데이터")
for ax in axes:
ax.set_xlabel("특성 0")
ax.set_ylabel("특성 1")
첫 번째 그림은 단순히 2차원 원본 데이터셋이며, 훈련 세트는 파란 동그라미, 테스트 세트는 빨간 세모로 표시합니다.
두 번째 그래프는 같은 데이터를 MinMaxScaler를 이용해 스케일을 조절하였는데, 각 그래프의 눈금 빼고는 모양이 변한 것이 없습니다.
하지만, 테스트 데이터(세모)의 최솟값과 최댓값이 0과 1은 아닙니다.
문제는 세 번째 데이터입니다. 훈련 세트와 테스트 세트에 대해 각각 스케일을 조정한 경우, 각 데이터셋이 서로 다르게 스케일 되었기 때문에 삼각형의 배치가 뒤죽박죽 되었습니다.
지도 학습에서 데이터 전처리 효과
다시 cancer 데이터셋으로 돌아와서, SVC를 학습시킬 때 MinMaxScaler의 효과를 확인해 보도록 하겠습니다.
from sklearn.svm import SVC
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0)
svm = SVC(C=100)
svm.fit(X_train, y_train)
print("테스트 세트 정확도: {:.2f}".format(svm.score(X_test, y_test)))
스케일이 조정되지 않은 원본 데이터의 정확도는 63%의 정확도 밖에 표현하지 못합니다. 다음은 스케일 조정 후의 학습 결과입니다.
# MinMaxScaler 사용
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 조정된 데이터로 SVM 학습
svm.fit(X_train_scaled, y_train)
# 스케일 조정된 테스트 세트의 정확도
print("스케일 조정된 테스트 세트의 정확도: {:.2f}".format(svm.score(X_test_scaled, y_test)))
단순히 스케일만 조정했을 뿐인데 그 효과는 매우 큰 것이 확인됩니다.
스케일을 조정하는 모든 파이썬 클래스들은 fit과 transform을 제공하므로 손쉽게 전처리 알고리즘을 바꿔낼 수 있습니다.
# 평균 0, 분선 1을 갖도록 스케일 조정하기
from sklearn.preprocessing import StandardScaler
# StandaradScaler 사용
scaler = StandardScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 조정된 데이터로 SVM 학습
svm.fit(X_train_scaled, y_train)
# 스케일 조정된 테스트 세트의 정확도
print("스케일 조정된 테스트 세트의 정확도: {:.2f}".format(svm.score(X_test_scaled, y_test)))
지금까지 데이터 학습 훈련을 위한 스케일링에 대하여 알아보았습니다.
다음 포스팅에서는 One-Hot-Encoding에 대하여 알아보도록 하겠습니다.
'Programming > 특성 공학' 카테고리의 다른 글
[Machine Learning]지도 학습 (0) | 2023.04.14 |
---|---|
[데이터 전처리]수치 변환 (1) | 2023.04.04 |
[Machine Learning]일변량 통계 (0) | 2023.03.28 |
[데이터 전처리]구간분할과 이산화 & 상호작용과 다항식 (0) | 2023.03.21 |
[데이터 전처리]연속형과 범주형 (One Hot Encoding) (0) | 2023.03.16 |