반응형
- 이 공부는 다음 멋진 책과 함께 합니다. 위키북스와 저자님 너무나도 감사합니다.
Feature Scaling
- Feature Scaling : 서로 다른 변수의 값 범위를 일정한 수준으로 맞추는 작업
- 표준화(Standardization) : 데이터의 피처 각각을 평균 0, 분산 1인 가우시안 정규 분포를 가진 값으로 변환
- 정규화(Normalization) : 서로 다른 피처의 크기를 통일하기 위해 크기를 변환
- 사이킷런의 전처리에서 제공하는 Normalizer 모듈과 일반적인 정규화는 약간 차이가 있습니다.
- Normalizer 모듈 - 선형대수에서의 정규화 개념 → 개별 벡터의 크기를 맞추기 위해 변환(개별 벡터를 모든 피터 벡터의 크기로 나눠줍니다.)
- 용어를 다음과 같이 지칭하겠습니다.
- 피처 스케일링 - 일반적인 의미의 표준화, 정규화
- 벡터 정규화 - 선형대수 개념의 정규화
- 대표적인 피처 스케일링 클래스인 StandardScaler와 MinMaxScaler를 알아보겠습니다.
StandardScaler - 표준화
- RBF 커널(가우시안 방사형 기저 함수)을 사용하는 서포트 벡터 머신, 선형 회귀, 로지스틱 회귀는 데이터가 가우시안 분포를 가지고 있다고 가정하고 구현됐기 때문에 사전에 표준화를 적용하는 것은 예측 성능 향상에 중요한 요소가 될 수 있습니다.
- 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())
- StandardScaler를 이용해 각 피처를 한 번에 표준화를 하여 변환하겠습니다.
from sklearn.preprocessing import StandardScaler
# StandardScaler 객체 생성
scaler = StandardScaler()
# StandardScaler로 데이터셋 변환. fit()과 transform() 호출
scaler.fit(iris_df)
iris_scaler = scaler.transform(iris_df)
print(iris_scaler)
- 이를 DataFrame으로 변환하여 평균, 분산값을 구하겠습니다.
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())
- feature들의 평균값은 0에 가까워지고, 분산값은 1에 가까워지게 변환되었습니다.
MinMaxScaler - 정규화 : 데이터 값을 0~1사이의 범위 값으로 변환
- 데이터 값에 음수가 포함되어 있다면 -1 ~ 1 사이의 값으로 변환됩니다.
- 데이터 분포가 가우시안 분포가 아닐 경우에 Min, Max, Scale을 적용해 볼 수 있습니다.
from sklearn.preprocessing import MinMaxScaler
# MinMaxScaler 객체 생성
scaler = MinMaxScaler()
# MinMaxScaler로 데이터 셋 변환. fit()과 transform() 호출
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)
print(iris_scaled)
- 아까와 마찬가지로 ndarray값으로 반환되었지만 값에서 차이가 보이시나요?
- 최솟값, 최댓값을 구해보겠습니다.
# transform()을 하여 변환된 데이터넷은 Numpy ndarray 형태이다. 이를 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())
- 모든 피처에서 0에서 1 사이의 값으로 변환되는 스케일링이 적용되었습니다.
학습 데이터와 테스트 데이터의 스케일링 변환 시 유의점
- fit() - 데이터 변환을 위한 기준 정보 적용(최댓값, 최솟값 설정 등)
- transform() - 설정된 정보를 이용해 데이터 변환
- 주의가 필요합니다!
- 학습 데이터로 fit()이 적용된 스케일링 기준 정보를 그대로 테스트 데이터에 적용!!!(테스트 데이터에서 다시 fit()을 수행하지 않음)
- 그렇지 않고, 테스트 데이터로 다시 새로운 스케일링 기준 정보를 만들게 되면 학습 데이터와 테스트 데이터의 스케일링 기준 정보가 서로 달라기지 때문에 올바른 예측 결과를 도출할 수 없습니다.
- 다음 코드를 통해서 테스트 데이터에 fit()을 적용하면 어떤 문제가 생기는 지 확인해보겠습니다.
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)
- train_array부터 변환하겠습니다.
# MinMaxScaler 객체에 별도의 feature_range 파라미터 값을 지정하지 않으면 0~1 값으로 변환
scaler = MinMaxScaler()
# fit()을 하면 train_array 데이터의 최솟값이 0, 최댓값이 10으로 설정
scaler.fit(train_array)
# 1/10 scale로 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))
- 원본 값에서 모두 1/10 scale로 변환되었음을 알 수 있습니다.
- 이번에는 테스트 데이터 셋을 변환하겠습니다.
# fit()을 하면 test_array 데이터의 최솟값이 0, 최댓값이 5으로 설정
scaler.fit(test_array)
# 1/5 scale로 test_array데이터를 변환함
test_scaled = scaler.transform(test_array)
print('원본 test_array 데이터 : ', np.round(test_array.reshape(-1), 2))
print('Scale된 test_array 데이터 :', np.round(test_scaled.reshape(-1), 2))
- 학습 데이터와 테스트 데이터의 Scaling이 맞지 않지요? 이렇게 되면 학습 데이터와 테스트 데이터의 서로 다른 원본값이 동일한 값으로 변환되는 결과를 초래합니다.(예 : train 10, test 5 가 모두 1.0으로 변환됨)
- 머신러닝 모델은 학습 데이터를 기반으로 학습되므로 반드시 테스트 데이터는 학습 데이터의 스케일링 기준을 따라야 하므로, 학습 데이터로 이미 fit()이 적용된 Scaler 객체를 이용하여 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))
- 학습 데이터와 테스트 데이터 모두 동일하게 1/10 scale이 적용되었습니다.
- 이와 마찬가지로, fit_transform()은 학습 데이터에서 상관없지만 테스트 데이터에서는 절대 사용해서는 안됩니다.
- 따라서 실수를 방지하기 위해서는 전체 데이터 셋에 Scaling을 적용한 후 학습 데이터 세트와 테스트 데이터 세트로 분리하는 방법을 사용합니다.
지금까지 함께 머신러닝에서의 데이터 전처리 작업에 대하여 학습했습니다.
이제 실전 예제를 통해 연습하면서 익숙해지는 시간을 가지도록 하겠습니다.
오늘도 감사합니다.
'Python > Machine Learning' 카테고리의 다른 글
[ML]_분류 모형의 평가 지표 - Confusion Matrix, ROC 곡선 (2) | 2023.10.14 |
---|---|
[ML]_타이타닉 생존자 예측하기(kaggle data 사용) (1) | 2023.10.03 |
[ML]_데이터 전처리 >> 데이터 인코딩(Label & One-Hot) (0) | 2023.08.28 |
[ML]_하이퍼 파라미터 튜닝(GridSeachCV) (0) | 2023.08.27 |
[ML]_파라미터도 있는데 하이퍼 파라미터는 또 뭐야? (0) | 2023.08.27 |