Written on
·
1.2K
0
안녕하세요.
scaling 후 train, test로 나눠야 하는지,
train, test 분리 후 scaling을 진행해야 하는 지 헷갈립니다.
PCA에서도 마찬가지고,
PCA를 한 후에 train, test로 나눠야 하는지,
나눈 후에 PCA를 train데이터로 fit한 후, test데이터에 transform해야하는지 모르겠습니다.
Answer 1
5
안녕하십니까,
사이킷런은 데이터를 변환하는 대부분의 로직에서 fit()과 transform()을 쌍으로 사용합니다. 예를 들어 sklearn.preprocessing의 StandardScaler, MinMaxScaler 나 PCA클래스, 그리고 텍스트의 Feature Vectorization 클래스들(CountVectorizer, TFIDF등) 모드 fit()과 transform()을 같이 이용합니다.
데이터 세트가 이미 학습과 테스트 데이터 세트로 나뉘어져 있다면 Scaler 클래스를 학습데이터 세트에서 변환을 위한 기반 설정(예를 들어 학습 데이터 세트의 최대값/최소값등)을 먼저 fit()을 통해서 설정한 뒤에 이를 기반으로 학습 데이터의 transform()을 수행합니다. 이때 주의 해야할 점은 학습 데이터에서 설정된 변환을 위한 기반 설정을 그대로 테스트 데이터에도 적용해야 한다는 것입니다. 즉 학습 데이터 세트로 fit() 된 Scaler를 이용하여 테스트 데이터를 변환할 경우에는 테스트 데이터에서 다시 fit()하지 않고 반드시 그대로 이 Scaler를 이용하여 transform()을 수행해야 합니다.
가령 아래와 같이 Iris 학습 데이터 세트로 MinMaxScaler() 를 생성한 뒤 fit()하고 transform() 한 뒤 Classifier로 학습 했다면 예측 시 먼저 테스트 데이터 세트를 반드시 학습 데이터로 Scaling된 MinMaxScaler를 이용하여 fit()한 뒤 transform() 해야 됩니다. 즉 학습할 때와 동일한 기반 설정으로 동일하게 테스트 데이터를 변환해야 하는 것입니다. 학습 데이터에서 Scale된 데이터를 기반으로 Classifier가 학습이 되었기 때문에 이렇게 학습된 Classifier가 예측을 할 때에도 학습 데이터의 Scale 기준으로 테스트 데이터를 변환 한 뒤 predict해야 합니다.
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.metrics import accuracy_score
# 붓꽃 데이터 세트를 로딩합니다.
iris = load_iris()
iris_data = iris.data
iris_label = iris.target
X_train, X_test, y_train, y_test = train_test_split(iris_data, iris_label,
test_size=0.2, random_state=2)
# MinMaxScaler() Scaler객체 생성.
scaler = MinMaxScaler()
# 학습 데이터에 대해서 fit(), transform() 수행.
scaler.fit(X_train)
scaled_X_train = scaler.transform(X_train)
# 테스트 데이터에서는 다시 fit(), transform()이나 fit_transform()을 수행하지 않고 transform만 수행.
scaled_X_test = scaler.transform(X_test)
lr = LogisticRegression()
lr.fit(scaled_X_train, y_train)
pred = lr.predict(scaled_X_test)
print('예측 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))
fit_transform()을 fit() 과 transform() 함께 수행하는 메소드 입니다. 기존의 fit() 과 transform() 각각을 수행하는 번거로움을 줄여줍니다. 위 코드를 예로 들면
scaler.fit(X_train)
scaled_X_train = scaler.transform(X_train)은
=> scaled_X_train = scaler.fit_transform(X_train) 과 같이 한 라인으로 대체 될 수 있습니다.
하지만 테스트 데이터에 scaled_X_test = scaler.fit_transform(X_test)를 적용해서는 안됩니다. 이를 수행하면 scaler 객체가 기존에 학습 데이터에 fit 했던 기준을 모두 무시하고 다시 테스트 데이터를 기반으로 기준을 적용하기 때문입니다.
때문에 테스트 데이터에 fit_transform()을 적용해서는 안됩니다.
이런 번거로움을 피하기 위해 학습과 테스트 데이터로 나누기 전에 먼저 Scaling등의 데이터 전처리를 해주는 것이 좋습니다. 아래 코드에서는 학습과 테스트 데이터로 나누기 전에 Scaling을 적용합니다. fit(), transform()을 순차적으로 써도 좋고 fit_transform()으로 변환해도 무방합니다.
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.metrics import accuracy_score
# 붓꽃 데이터 세트를 로딩합니다.
iris = load_iris()
iris_data = iris.data
iris_label = iris.target
# MinMaxScaler() Scaler객체 생성.
scaler = MinMaxScaler()
# 학습 데이터, 테스트 데이터로 나누기 전에 fit과 transform 으로 변환. fit_transform() 도 무방.
scaler.fit(iris.data)
scaled_iris_data = scaler.transform(iris.data)
# scale된 iris_data로 학습과 테스트 데이터를 나눔.
X_train, X_test, y_train, y_test = train_test_split(scaled_iris_data, iris_label,
test_size=0.2, random_state=2)
lr = LogisticRegression()
lr.fit(scaled_X_train, y_train)
pred = lr.predict(scaled_X_test)
print('예측 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))
fit(), transform(), fit_transform()을 어떤 데이터 세트에 적용하냐에 따라 사용이 달라 질 수 있으며 이는 위의 Scaler 뿐만 아니라 PCA, Feature Vectorizer 클래스등 모든 Transformer 클래스에 동일하게 적용되는 규칙입니다.
요약하자면 fit()과 transform() 을 적용하는 기준은 아래와 같이 정리 할 수 있습니다.
1. 미리 Scaling을 전체 데이터 세트에 적용한 뒤에 학습과 테스트 세트로 나누는 것이 좋음.
2. 1의 상황이 안된다면, 학습 데이터 세트를 기반으로 Scaler클래스(또는 PCA등)의 fit()과 transform()으로 학습 데이터를 변환하되 학습 데이터 기반으로 fit() 된 Scaler를 이용하여 테스트 데이터의 transform()을 수행.(테스트 데이터를 기반으로 다시 fit()을 호출하거나 fit_transform()을 호출해서는 안됨)
감사합니다.