[파이썬 머신러닝 완벽 가이드] 2장-사이킷런으로 시작하는 머신러닝-1
1. 사이킷런을 이용하여 붓꽃(Iris) 데이터 품종 예측하기
- 사이킷런 모듈 정리
sklearn.datasetes
: 사이킷런에서 자체적으로 제공하는 데이터 세트를 생성하는 모듈의 모임sklearn.model_selection
: 학습 데이터와 검증 데이터, 예측 데이터로 데이터를 분리하거나 최적의 하이퍼 파라미터로 평가하기 위한 다양한 모듈의 모임- 하이퍼 파라미터
- 머신러닝 알고리즘 별로 최적의 학습을 위해 직접 입력하는 파라미터들 통칭
- 하이퍼 파라미터를 통해 머신러닝 알고리즘의 성능을 튜닝할 수 있다.
- 하이퍼 파라미터
1) 데이터 세트 분리
- 데이터를 학습 데이터 및 테스트 데이터로 분리
-
train_test_split
- 붓꽃 데이터 세트를 로딩
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
import sklearn
import pandas as pd
# 붓꽃 데이터 세트를 로딩
iris = load_iris()
- Iris 데이터 세트에서 feature, target 값 가져와서 DataFrame 생성
# iris.data는 Iris 데이터 세트에서 피처(feature)만으로 된 데이터를 가지고 있음 (numpy)
iris_data = iris.data
# iris.target은 붓꽃 데이터 세트에서 레이블 값을 가지고 있음 (numpy)
iris_label = iris.target
print('iris target값:', iris_label) # [0 0 0 ... 1 1 1 ... 2 2 2 ...]
print('iris target명:', iris.target_names) # ['setosa' 'versicolor' 'virginica']
# 붓꽃 데이터 세트를 자세히 보기 위해 DataFrame으로 변환합니다.
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)
iris_df['label'] = iris.target
iris_df.head(3)
- 데이터 세트 분리
from sklearn.model_selection import train_test_split
#1.데이터 세트 분리
#train_test_split(피쳐데이터셋,레이블데이터세트,테스트데이터 세트 비율, 난수발생값)
**X_train, X_test, y_train, y_test** = **train_test_split**(iris_data, iris_label,
test_size=0.2, random_state=11)
2) 모델 학습
- 학습 데이터를 기반으로 머신러닝 알고리즘을 적용해 모델을 학습
-
fit
- DecisionTreeClassifier 객체 생성 및 모델 학습
- ML 알고리즘은 의사 결정 트리(Decision Tree) 알고리즘을 구현한 DecisionTreeClassifier를 적용함
from sklearn.tree import DecisionTreeClassifier
# DecisionTreeClassifier 객체 생성
dt_clf = DecisionTreeClassifier(random_state=11)
#2. 모델학습
# 학습 수행
dt_clf.fit(X_train, y_train)
3) 예측 수행
- 학습된 모델을 이용해 테스트 데이터의 분류를 예측
- predict
#3. 예측수행
# 학습이 완료된 DecisionTreeClassifier 객체에서 테스트 데이터 세트로 예측 수행.
**pred** = dt_clf.predict(X_test)
4) 평가
- 예측된 결과값과 테스트 데이터의 실제 결과값을 비교 → 모델 성능 평가
#4. 평가
from sklearn.metrics import accuracy_score
print('예측 정확도: {0:.4f}'.format(**accuracy_score**(y_test,**pred**))) # 0.9333
2. 교차 검증
- 과적합(Overfitting)
- 고정된 학습 데이터와 테스트 데이터로 평가를 하다보면 테스트 데이터에만 최적의 성능을 발휘할 수 있도록 편향되게 모델을 유도하는 경향이 생긴다.
- 결국 해당 테스트 데이터에만 과적합되는 학습 모델이 만들어져 다른 테스트용 데이터가 들어올 경우에는 성능이 저하되게 된다.
- 이러한 문제점을 개선하기 위해 교차 검증을 이용해 다양한 학습과 평가를 수행한다.
1) K 폴드 교차검증
- K개의 데이터 폴드 세트를 만들어서 K번만큼 각 폴드 세트에 학습, 검증, 평가를 반복적으로 수행하는 방법
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold
import numpy as np
iris = load_iris()
features = iris.data
label = iris.target
dt_clf = DecisionTreeClassifier(random_state=156)
# 5개의 폴드 세트로 분리하는 KFold 객체와 폴드 세트별 정확도를 담을 리스트 객체 생성.
kfold = KFold(n_splits=5) # shuffle 디폴트 옵션이 false -> 순차적으로 분리됨.
cv_accuracy = []
print('붓꽃 데이터 세트 크기:',features.shape[0]) # 150
n_iter = 0
# 120개, 30개로 나눠서 120개로 학습, 30개로 테스트 -> 이걸 5번 반복한다.
# KFold객체의 split( ) 호출하면 폴드 별 학습용, 검증용 테스트의 로우 인덱스를 array로 반환
for train_index, test_index in **kfold.split(features)**:
# kfold.split( )으로 반환된 인덱스를 이용하여 학습용, 검증용 테스트 데이터 추출
## train_index : numpy (fancy indexing) -> 인덱스에 해당하는 값들을 리턴
X_train, X_test = features[train_index], features[test_index]
y_train, y_test = label[train_index], label[test_index]
#학습 및 예측
dt_clf.fit(X_train , y_train)
pred = dt_clf.predict(X_test)
n_iter += 1
# 반복 시 마다 정확도 측정
accuracy = np.round(accuracy_score(y_test,pred), 4)
train_size = X_train.shape[0]
test_size = X_test.shape[0]
print('\n#{0} 교차 검증 정확도 :{1}, 학습 데이터 크기: {2}, 검증 데이터 크기: {3}'
.format(n_iter, accuracy, train_size, test_size))
print('#{0} 검증 세트 인덱스:{1}'.format(n_iter,test_index))
cv_accuracy.append(accuracy)
# 개별 iteration별 정확도를 합하여 평균 정확도 계산
print('\n## 평균 검증 정확도:', np.mean(cv_accuracy))
-
결과
#1 교차 검증 정확도 :1.0, 학습 데이터 크기: 120, 검증 데이터 크기: 30 #1 검증 세트 인덱스:[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29] #2 교차 검증 정확도 :0.9667, 학습 데이터 크기: 120, 검증 데이터 크기: 30 #2 검증 세트 인덱스:[30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59] #3 교차 검증 정확도 :0.8667, 학습 데이터 크기: 120, 검증 데이터 크기: 30 #3 검증 세트 인덱스:[60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89] #4 교차 검증 정확도 :0.9333, 학습 데이터 크기: 120, 검증 데이터 크기: 30 #4 검증 세트 인덱스:[ 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119] #5 교차 검증 정확도 :0.7333, 학습 데이터 크기: 120, 검증 데이터 크기: 30 #5 검증 세트 인덱스:[120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149] ## 평균 검증 정확도: 0.9
2) Stratified K 폴드
- 불균형한(imbalanced) 분포도를 가진 레이블 데이터 집합을 위한 K 폴드 방식
- 불균형한 분포도를 가진 레이블 데이터 집합 : 특정 레이블 값이 특이하게 많거나 매우 적어서 값의 분포가 한쪽으로 치우치는 것.
- 예 : 대출 사기 데이터 예측 :
- 대출 사기 여부를 뜻하는 레이블 (대출 사기 :1, 정상 대출 : 0)
- 대부분의 데이터는 정상 대출. 매우 작은 비율로 1 레이블 값이 존재
- 특정 데이터 세트에는 1이 상대적으로 많이 들어가 있고, 다른 반보고 학습/테스트 데이터 세트에는 그렇지 못한 결과가 발생할 수 있음
- 따라서 원본 데이터와 유사한 대출 사기 레이블 값의 분포를 학습/테스트 세트에도 유지하는 것이 매우 중요하다.
- 예 : 대출 사기 데이터 예측 :
- Stratified K 폴드는 이처럼 K 폴드가 레이블 데이터 집합이 원본 데이터 집합의 레이블 분포를 학습/테스트 세트에 제대로 분배하지 못하는 경우의 문제를 해결한다.
- Stratified K 폴드는 원본 데이터의 레이블 분포를 먼저 고려한 뒤 이 분포와 동일하게 학습과 검증 데이터를 분배한다.
import pandas as pd
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
iris_df['label']=iris.target
iris_df['label'].value_counts()
---------------------------------------------
0 50
1 50
2 50
Name: label, dtype: int6
- 레이블 값은 0,1,2 값 모두 50개로 동일.
- 하지만 데이터를 보면 같은 품종끼리 서로 몰려있음 → K=3인 KFold로 테스트했을 때 문제 발생
kfold = KFold(n_splits=3)
n_iter =0
for train_index, test_index in kfold.split(iris_df):
n_iter += 1
label_train= iris_df['label'].iloc[train_index]
label_test= iris_df['label'].iloc[test_index]
print('## 교차 검증: {0}'.format(n_iter))
print('학습 레이블 데이터 분포:\n', label_train.value_counts())
print('검증 레이블 데이터 분포:\n', label_test.value_counts())
## 교차 검증: 1
학습 레이블 데이터 분포:
1 50
2 50
Name: label, dtype: int64
검증 레이블 데이터 분포:
0 50
Name: label, dtype: int64
## 교차 검증: 2
학습 레이블 데이터 분포:
0 50
2 50
Name: label, dtype: int64
검증 레이블 데이터 분포:
1 50
Name: label, dtype: int64
## 교차 검증: 3
학습 레이블 데이터 분포:
0 50
1 50
Name: label, dtype: int64
검증 레이블 데이터 분포:
2 50
Name: label, dtype: int64
-
학습은 1,2번으로만 하고, 테스트는 0번으로만 테스트하게 됨. 즉 학습 데이터와 테스트 데이터가 서로 완전히 분리되어있음
→ 0의 경우를 전혀 학습하지 못함
→ 검증 에측 정확도는 0이 됨
- 따라서 학습도 0,1,2로 구성되어 있고, 테스트 데이터도 0,1,2로 고르게 구성되어 있어야 학습이 제대로 일어난다.
- ⇒ stratified KFold 사용
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=3)
n_iter=0
for train_index, test_index in skf.split(iris_df, iris_df['label']):
n_iter += 1
label_train= iris_df['label'].iloc[train_index]
label_test= iris_df['label'].iloc[test_index]
print('## 교차 검증: {0}'.format(n_iter))
print('학습 레이블 데이터 분포:\n', label_train.value_counts())
print('검증 레이블 데이터 분포:\n', label_test.value_counts())
## 교차 검증: 1
학습 레이블 데이터 분포:
2 34
0 33
1 33
Name: label, dtype: int64
검증 레이블 데이터 분포:
0 17
1 17
2 16
Name: label, dtype: int64
## 교차 검증: 2
학습 레이블 데이터 분포:
1 34
0 33
2 33
Name: label, dtype: int64
검증 레이블 데이터 분포:
0 17
2 17
1 16
Name: label, dtype: int64
## 교차 검증: 3
학습 레이블 데이터 분포:
0 34
1 33
2 33
Name: label, dtype: int64
검증 레이블 데이터 분포:
1 17
2 17
0 16
Name: label, dtype: int64
- 레이블 별로 동일한 비율로 할당된 것을 확인할 수 있다.
dt_clf = DecisionTreeClassifier(random_state=156)
skfold = StratifiedKFold(n_splits=3)
n_iter=0
cv_accuracy=[]
# StratifiedKFold의 split( ) 호출시 반드시 레이블 데이터 셋도 추가 입력 필요
for train_index, test_index in skfold.split(features, label):
# split( )으로 반환된 인덱스를 이용하여 학습용, 검증용 테스트 데이터 추출
X_train, X_test = features[train_index], features[test_index]
y_train, y_test = label[train_index], label[test_index]
#학습 및 예측
dt_clf.fit(X_train , y_train)
pred = dt_clf.predict(X_test)
# 반복 시 마다 정확도 측정
n_iter += 1
accuracy = np.round(accuracy_score(y_test,pred), 4)
train_size = X_train.shape[0]
test_size = X_test.shape[0]
print('\n#{0} 교차 검증 정확도 :{1}, 학습 데이터 크기: {2}, 검증 데이터 크기: {3}'
.format(n_iter, accuracy, train_size, test_size))
print('#{0} 검증 세트 인덱스:{1}'.format(n_iter,test_index))
cv_accuracy.append(accuracy)
# 교차 검증별 정확도 및 평균 정확도 계산
print('\n## 교차 검증별 정확도:', np.round(cv_accuracy, 4))
print('## 평균 검증 정확도:', np.mean(cv_accuracy))
#1 교차 검증 정확도 :0.98, 학습 데이터 크기: 100, 검증 데이터 크기: 50
#1 검증 세트 인덱스:[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 50
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 100 101
102 103 104 105 106 107 108 109 110 111 112 113 114 115]
#2 교차 검증 정확도 :0.94, 학습 데이터 크기: 100, 검증 데이터 크기: 50
#2 검증 세트 인덱스:[ 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 67
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 116 117 118
119 120 121 122 123 124 125 126 127 128 129 130 131 132]
#3 교차 검증 정확도 :0.98, 학습 데이터 크기: 100, 검증 데이터 크기: 50
#3 검증 세트 인덱스:[ 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 83 84
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 133 134 135
136 137 138 139 140 141 142 143 144 145 146 147 148 149]
## 교차 검증별 정확도: [0.98 0.94 0.98]
## 평균 검증 정확도: 0.9666666666666667
3) cross_val_score()
- 위 교차 검증(폴드 세트 설정 → for 루프에서 반복으로 학습 및 테스트 데이터의 인덱스 추출 → 반복적으로 학습과 예측을 수행하고 예측 성능 반환) 과정을 간단하게 하는 방법
- cross_val_score(estimator, X, y=None, , groups=None, scoring=None, cv=None, n_jobs=None, verbose=0, fit_params=None, pre_dispatch=’2n_jobs’, error_score=np.nan)
estimator
: Classifier 혹은 Regressor- classifier가 입력되면 Stratified K 폴드 방식으로 학습/테스트 세트를 분할
- Regressor인 경우 Stratified K 폴드 방식으로 분할할 수 없으므로 K 폴드 방식으로 분할
X
: 피처 데이터 세트y
: 레이블 데이터 세트scoring
: 예측 성능 평가 지표cv
: 교차 검증 폴드 수
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score , cross_validate
from sklearn.datasets import load_iris
import numpy as np
iris_data = load_iris()
dt_clf = DecisionTreeClassifier(random_state=156)
data = iris_data.data
label = iris_data.target
#성능 평가 지표는 정확도인 accuracy로 함
scores = cross_val_score(dt_clf , data , label , scoring='accuracy',cv=3) #Straified?
print('교차 검증별 정확도:',np.round(scores, 4))
print('평균 검증 정확도:', np.round(np.mean(scores), 4))
4) GridSearchCV - 교차 검증과 최적 하이퍼 파라미터 튜닝을 한번에
- 하이퍼 파라미터는 머신러닝 알고리즘의 주요 구성 요소이며, 이 값을 조정해 알고리즘의 예측 성능을 개선할 수 있다.
- 사이킷런은 GridSearchCV API를 이용해 Classifier나 Regressor와 같은 알고리즘에 사용되는 하이퍼 파라미터를 순차적으로 입력 → 편리하게 최적의 파라미터를 도출할 수 있는 방안 제공
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
# 데이터를 로딩하고 학습데이타와 테스트 데이터 분리
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target,
test_size=0.2, random_state=121)
dtree = DecisionTreeClassifier()
### hyper parameter 들을 dictionary 형태로 설정
parameters = {'max_depth':[1,2,3], 'min_samples_split':[2,3]}
import pandas as pd
# param_grid의 하이퍼 파라미터들을 3개의 train, test set fold 로 나누어서 테스트 수행 설정. => **6개의 파라미터 조합 X CV 3회 -> 18회의 학습/평가가 이뤄진다**.
### refit=True 가 default 임. True이면 가장 좋은 파라미터 설정으로 재 학습 시킴.
grid_dtree = GridSearchCV(dtree, param_grid=parameters, cv=3, refit=True)
# 붓꽃 Train 데이터로 param_grid의 하이퍼 파라미터들을 순차적으로 학습/평가 .
grid_dtree.fit(X_train, y_train)
# GridSearchCV 결과 추출하여 DataFrame으로 변환
scores_df = pd.DataFrame(grid_dtree.cv_results_)
scores_df[['params', 'mean_test_score', 'rank_test_score', \
'split0_test_score', 'split1_test_score', 'split2_test_score']]
print('GridSearchCV 최적 파라미터:', grid_dtree.best_params_)
# {'max_depth': 3, 'min_samples_split': 2}
print('GridSearchCV 최고 정확도: {0:.4f}'.format(grid_dtree.best_score_)) # 0.9750
# GridSearchCV의 refit으로 이미 학습이 된 estimator 반환
estimator = grid_dtree.best_estimator_
# GridSearchCV의 best_estimator_는 이미 최적 하이퍼 파라미터로 학습이 됨
pred = estimator.predict(X_test)
print('테스트 데이터 세트 정확도: {0:.4f}'.format(accuracy_score(y_test,pred))) # 0.9667
3. 데이터 전처리
- 머신러닝에서 데이터 전처리는 매우 중요하다. 입력값에 따라 결과가 크게 달라지기 때문
- Null 처리
- Null 값이 얼마되지 않는 경우 → feature의 평균값으로 대체
- Null 값이 대부분인 경우 → 해당 feature 드롭
- Null 값이 애매하게 있는 경우 → 단순히 평균값으로 대체하는 것이 아니라 업무 로직등을 상세하게 검토해야함
- 문자열 처리
- 사이킷런의 머신러닝 알고리즘은 문자열 값을 입력값으로 허용하지 않는다.
- 따라서 모든 문자열 값은 인코딩돼서 숫자형으로 변환해야한다. (주민번호나 단순 문자열 아이디 같은 예측에 도움이 안되는 불필요한 피처일 경우는 그냥 삭제)
1) 데이터 인코딩
- 레이블 인코딩 (Label encoding)
- 카테고리 피처를 코드형 숫자 값으로 변환
- 예 : 상품 데이터의 상품 구분이 TV, 냉장고, 전자레인지, 컴퓨터, 선풍기, 믹서로 돼 있다면 → TV : 1, 냉장고: 2, 전자레인지: 3, 컴퓨터: 4, 선풍기 :5, 믹서 : 6과 같은 숫자형 값으로 변환하는 것
from sklearn.preprocessing import LabelEncoder items=['TV','냉장고','전자렌지','컴퓨터','선풍기','선풍기','믹서','믹서'] # LabelEncoder를 객체로 생성한 후 , fit( ) 과 transform( ) 으로 label 인코딩 수행. encoder = LabelEncoder() encoder.fit(items) labels = encoder.transform(items) print('인코딩 변환값:',labels) # [0 1 4 5 3 3 2 2]
print('인코딩 클래스:',encoder.classes_) # ['TV' '냉장고' '믹서' '선풍기' '전자렌지' '컴퓨터'] print('디코딩 원본 값:',encoder.inverse_transform([4, 5, 2, 0, 1, 1, 3, 3])) # ['전자렌지' '컴퓨터' '믹서' 'TV' '냉장고' '냉장고' '선풍기' '선풍기']
- 단점 : 숫자 값으로 변환되면서 회귀계열의 ML 알고리즘에 이를 적용할 경우 예측 성능이 떨어지게 됨 → 숫자 값의 경우 크고 작음에 대한 특성이 작용하기 때문 → 원핫 인코딩 적용
- 원-핫 인코딩 (One-Hot encoding)
- 해당 고유 값에 매칭되는 피처만 1이 되고 나머지 피처는 0이 되게끔 인코딩 하는 방식
-
원-핫 인코딩 조건:
1) 우선 숫자형태의 값으로 변환되어 있어야 함 2) 2차원 데이터로 변환되어 있어야 함
from sklearn.preprocessing import OneHotEncoder
import numpy as np
items=['TV','냉장고','전자렌지','컴퓨터','선풍기','선풍기','믹서','믹서']
# 먼저 숫자값으로 변환을 위해 LabelEncoder로 변환합니다.
encoder = LabelEncoder()
encoder.fit(items)
labels = encoder.transform(items)
# 2차원 데이터로 변환합니다.
labels = labels.reshape(-1,1)
print('2차원 데이터로 변환후')
print(labels)
--------------------------
[[0]
[1]
[4]
[5]
[3]
[3]
[2]
[2]]
# 원-핫 인코딩을 적용합니다.
oh_encoder = OneHotEncoder()
oh_encoder.fit(labels)
oh_labels = oh_encoder.transform(labels)
print('원-핫 인코딩 데이터')
print(oh_labels.toarray())
-----------------------------
[[1. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0.]
[0. 0. 0. 0. 0. 1.]
[0. 0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0. 0.]
[0. 0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0. 0.]]
print('원-핫 인코딩 데이터 차원')
print(oh_labels.shape) # (8, 6)
- Pandas로 쉽게 원핫 인코딩 가능
import pandas as pd
df = pd.DataFrame({'item':['TV','냉장고','전자렌지','컴퓨터','선풍기','선풍기','믹서','믹서'] })
pd.get_dummies(df) #pandas 에서 제공하는 원-핫 인코딩 함수(아주 간편함)
2) 피처 스케일링과 정규화
- 서로 다른 변수의 값 범위를 일정한 수준으로 맞추는 작업을 feature scaling 이라고 한다.
- 대표적인 방법으로 표준화(Standardization)와 정규화(Normalization)이 있다.
- 표준화
- 데이터의 피처 각각이 평균이 0이고 분산이 1인 가우시간 정규 분포를 가진 값으로 변환하는 것을 의미한다.
- 표준화를 통해 변환될 피처 x의 새로운 i번째 데이터 : xi_new
- xi_new = (xi - mean(x))/stdev(x)
- 정규화
- 서로 다른 피처의 크기를 통일하기 위해 크기를 변환해주느 ㄴ개념
- 예 : 피처 A는 거리를 나타내는 변수로 값이 0 ~ 100KM로 주어지고, 피처 B는 금액을 나타내는 속성으로 값이 0 ~ 100,000,000,000원으로 주어진다면 이 변수를 모두 동일한 크기 단위로 비교하기 위해 값을 모두 최소 0~ 최대 1의 값으로 변환하는 것.
- 즉, 개별 데이터의 크기를 모두 똑같은 단위로 변경하는 것
- StandardScaler
- 표준화를 지원하기 위한 클래스
- 개별 피처를 평균이 0이고 분산이 1인 가우시안 분포를 따르도록 변환해줌
- 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()) iris_df
StandardScaler 적용 후
from sklearn.preprocessing import StandardScaler # StandardScaler객체 생성 scaler = StandardScaler() # StandardScaler 로 데이터 셋 변환. fit( ) 과 transform( ) 호출. scaler.fit(iris_df) iris_scaled = scaler.transform(iris_df) #transform( )시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 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()) iris_df_scaled
- 모든 컬럼 값의 평균이 0에 아주 가까운 값으로, 분산은 1에 아주 가까운 값으로 변환됐음을 알 수 있다.
- MinMaxScaler
- 정규화를 지원하는 클래스이며 0과 1사이의 값으로 정규화 (음수값의 경우 -1과 1사이의 값으로 변환)
- 데이터의 분포가 정규분포가 아니라고 판단되는 경우 사용됨
from sklearn.preprocessing import MinMaxScaler # MinMaxScaler객체 생성 scaler = MinMaxScaler() # MinMaxScaler 로 데이터 셋 변환. fit() 과 transform() 호출. scaler.fit(iris_df) iris_scaled = scaler.transform(iris_df) # transform()시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 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()) ------------------------------------------ feature들의 최소 값 sepal length (cm) 0.0 sepal width (cm) 0.0 petal length (cm) 0.0 petal width (cm) 0.0 dtype: float64 feature들의 최대 값 sepal length (cm) 1.0 sepal width (cm) 1.0 petal length (cm) 1.0 petal width (cm) 1.0 dtype: float64
- Scaler를 이용하여 학습 데이터와 테스트 데이터에 fit(), transform(), fit_transform() 적용 시 유의사항
- Scaler 객체를 이용해 학습 데이터 세트로 fit()과 transform()을 적용하면 테스트 데이터 세트로는 다시 fit()을 수행하지 않고 바로 transform()을 수행해야함
- 즉 학습 데이터로 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)
print('train_array')
print(train_array)
print('test_array')
print(test_array)
# 최소값 0, 최대값 1로 변환하는 MinMaxScaler객체 생성
scaler = MinMaxScaler()
# fit()하게 되면 train_array 데이터의 최소값이 0, 최대값이 10으로 설정.
scaler.fit(train_array)
# 1/10 scale로 train_array 데이터 변환함. 원본 10-> 1로 변환됨.
train_scaled = scaler.transform(train_array)
print('원본 train_array 데이터:', np.round(train_array.reshape(-1), 2))
# [ 0 1 2 3 4 5 6 7 8 9 10]
print('Scale된 train_array 데이터:', np.round(train_scaled.reshape(-1), 2))
# [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]
# 앞에서 생성한 MinMaxScaler에 test_array를 fit()하게 되면 원본 데이터의 최소값이 0, 최대값이 5으로 설정됨
scaler.fit(test_array)
# 1/5 scale로 test_array 데이터 변환함. 원본 5->1로 변환.
test_scaled = scaler.transform(test_array)
# train_array 변환 출력
print('원본 test_array 데이터:', np.round(test_array.reshape(-1), 2))
# [0 1 2 3 4 5]
print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))
# [0. 0.2 0.4 0.6 0.8 1. ]
scaler = MinMaxScaler()
scaler.fit(train_array)
train_scaled = scaler.transform(train_array)
print('원본 train_array 데이터:', np.round(train_array.reshape(-1), 2))
# [ 0 1 2 3 4 5 6 7 8 9 10]
print('Scale된 train_array 데이터:', np.round(train_scaled.reshape(-1), 2))
# [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]
# test_array에 Scale 변환을 할 때는 반드시 fit()을 다시 호출하지 않고 train에 사용되었던 스케일 그대로 가져와서 transform() 만으로 변환해야 함.
test_scaled = scaler.transform(test_array)
print('\n원본 test_array 데이터:', np.round(test_array.reshape(-1), 2))
# [0 1 2 3 4 5]
print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))
# [0. 0.1 0.2 0.3 0.4 0.5]