본문 바로가기
Programming/Python

데이터 전처리2 (Data Scaling)

from sklearn.datasets import load_iris
import pandas as pd
from sklearn.preprocessing import StandardScaler  # 표준화 스케일링 함수
import seaborn as sns
import matplotlib.pyplot as plt
import scipy as sp
import scipy.stats

iris = load_iris()  # 붓꽃 데이터 셋을 로딩, DataFrame으로 변환 
iris_data = iris.data
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)

표준화: 입력된 x들을 평균 0이고 분산 1인 표준 정규 분포로 변환하는 것.  StandardScaler 잘 알아두자!

표준화는 전처리의 한 방법이다.

단점: 데이터 내 이상치 有 -> 평균 분산에 큰 왜곡 -> 부적절한 방법.

 

 

기존 평균 분산값 확인

print('feature 들의 평균 값')
print(iris_df.mean())
print('\nfeature 들의 분산 값')
print(iris_df.var())

feature 들의 평균 값
sepal length (cm)    5.843333
sepal width (cm)     3.057333
petal length (cm)    3.758000
petal width (cm)     1.199333
dtype: float64

feature 들의 분산 값
sepal length (cm)    0.685694
sepal width (cm)     0.189979
petal length (cm)    3.116278
petal width (cm)     0.581006
dtype: float64

 

 

표준화 스케일링 함수 StandardScaler 사용: 학습 -> 변환 필요.

scaler = StandardScaler()  # StandardScaler객체 생성 (1)
scaler.fit(iris_df)   # StandardScaler가 iris_df 데이터 학습  (2)
iris_scaled = scaler.transform(iris_df)  # 그리고 데이터 변형 transform (3)
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
#transform( )시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환 (4)

즉, scaler로 객체 생성 -> fit으로 학습 -> transform으로 데이터 변형 -> df로 다시 변환

하면 표준화 스케일링 함수 적용 완료!

 

 

 

표준화하기

print('feature 들의 평균 값')
print(iris_df_scaled.mean())
print('\nfeature 들의 분산 값')
print(iris_df_scaled.var())

feature 들의 평균 값
sepal length (cm)   -1.690315e-15
sepal width (cm)    -1.842970e-15
petal length (cm)   -1.698641e-15
petal width (cm)    -1.409243e-15
dtype: float64

feature 들의 분산 값
sepal length (cm)    1.006711
sepal width (cm)     1.006711
petal length (cm)    1.006711
petal width (cm)     1.006711
dtype: float64

 

 

# 각 값들의 정규 분포 모양 비교
f,ax = plt.subplots(1,2,figsize=(8,5))

# 표준화 전 정규분포 
x0 = iris_df['petal length (cm)'].dropna().values
sns.distplot(x0, kde=False, rug=False, fit =sp.stats.norm, ax = ax[0]) 
#커널 밀도 함수, 러그밀도함수 는 안보이고(False) / 정규분포만 보이게(Fit)
#norm = normal. 정규분포로 바꿔라

# 표준화 이후 정규 분포 
x1 = iris_df_scaled['petal length (cm)'].values
sns.distplot(x1, kde=False, rug=False, fit =sp.stats.norm, ax = ax[1]) 
plt.show()

 

  • Z score가 -2 미만이거나 2 이상인 값을 추려내는 과정을 거쳤다.
  • 이후 해당 값들의 인덱스를 outlier list에 담았고, 표준화를 거친 데이터에서 해당 인덱스 만 삭제했다.
  • 이렇게 이상치를 제거하는 과정을 거쳤고 총 11개의 이상치가 삭제되었다.

 

 

 

이상치 제거하기

 

z score: 자료가 평균으로 표준편차 몇 배만큼 떨어져 있는지. 양은 평균보다 높음. 음은 평균보다 낮음.

# check Z score 
df_Zscore = pd.DataFrame()
outlier_dict = {}
outlier_idx_list = []

for one_col in iris_df_scaled.columns:
#     print("Check",one_col)
#     print("sp.stats.zscore(iris_df_scaled[one_col])",sp.stats.zscore(iris_df_scaled[one_col]))
    df_Zscore[f'{one_col}_Zscore'] = sp.stats.zscore(iris_df_scaled[one_col])
    print("df_Zscore",df_Zscore)
#     print("이상치 딕트 저장",one_col)
    outlier_dict[one_col] = df_Zscore[f'{one_col}_Zscore'][(df_Zscore[f'{one_col}_Zscore']>2)|(df_Zscore[f'{one_col}_Zscore']<-2)]
#     print("이상치 딕트 저장",outlier_dict)
    outlier_idx_list.append(list(outlier_dict[one_col].index))
#     print("이상치 리스트에 인덱스 저장",outlier_idx_list)
    if len(outlier_dict[one_col]):
        print(one_col,'Has outliers\n', outlier_dict[one_col])
    else:
        print(one_col,"Has Not outlier")
    print()


print("Before", iris_df_scaled.shape)
all_outlier_idx = sum(outlier_idx_list,[])
iris_df_scaled = iris_df_scaled.drop(all_outlier_idx)
print("After (drop outlier)", iris_df_scaled.shape)

df_Zscore      sepal length (cm)_Zscore
0                   -0.933238
1                   -1.197004
2                   -1.460769
3                   -1.592652
4                   -1.065121
..                        ...
145                  1.176886
146                  0.649355
147                  0.913121
148                  0.517472
149                  0.121824

[118 rows x 1 columns]
sepal length (cm) Has Not outlier

df_Zscore      sepal length (cm)_Zscore  sepal width (cm)_Zscore
0                   -0.933238                 1.605641
1                   -1.197004                -0.119911
2                   -1.460769                 0.570310
3                   -1.592652                 0.225199
4                   -1.065121                 1.950751
..                        ...                      ...
145                  1.176886                -0.119911
146                  0.649355                -1.845463
147                  0.913121                -0.119911
148                  0.517472                 1.260530
149                  0.121824                -0.119911

[118 rows x 2 columns]
sepal width (cm) Has Not outlier

df_Zscore      sepal length (cm)_Zscore  sepal width (cm)_Zscore  \
0                   -0.933238                 1.605641   
1                   -1.197004                -0.119911   
2                   -1.460769                 0.570310   
3                   -1.592652                 0.225199   
4                   -1.065121                 1.950751   
..                        ...                      ...   
145                  1.176886                -0.119911   
146                  0.649355                -1.845463   
147                  0.913121                -0.119911   
148                  0.517472                 1.260530   
149                  0.121824                -0.119911   

     petal length (cm)_Zscore  
0                   -1.450590  
1                   -1.450590  
2                   -1.510418  
3                   -1.390761  
4                   -1.450590  
..                        ...  
145                  0.822897  
146                  0.703239  
147                  0.822897  
148                  0.942554  
149                  0.763068  

[118 rows x 3 columns]
petal length (cm) Has Not outlier

df_Zscore      sepal length (cm)_Zscore  sepal width (cm)_Zscore  \
0                   -0.933238                 1.605641   
1                   -1.197004                -0.119911   
2                   -1.460769                 0.570310   
3                   -1.592652                 0.225199   
4                   -1.065121                 1.950751   
..                        ...                      ...   
145                  1.176886                -0.119911   
146                  0.649355                -1.845463   
147                  0.913121                -0.119911   
148                  0.517472                 1.260530   
149                  0.121824                -0.119911   

     petal length (cm)_Zscore  petal width (cm)_Zscore  
0                   -1.450590                -1.387813  
1                   -1.450590                -1.387813  
2                   -1.510418                -1.387813  
3                   -1.390761                -1.387813  
4                   -1.450590                -1.387813  
..                        ...                      ...  
145                  0.822897                 1.385575  
146                  0.703239                 0.857310  
147                  0.822897                 0.989376  
148                  0.942554                 1.385575  
149                  0.763068                 0.725244  

[118 rows x 4 columns]
petal width (cm) Has Not outlier

Before (118, 4)
After (drop outlier) (118, 4)

 

 

 

 

정규화 작업

  • 반드시 이상치 제거 과정을 거친 후 정규화 작업 한다!
  • 제거과정 없으면 해당 이상치로 인해 나머지 값들은 0에 가까운 숫자로 왜곡되게 정규화될 가능성이 높다.
  • 정규화는 minmaxscaler 로 한다. 정규화 한후 데이터의 최대 최소 값이 1/0 으로 정돈
  • StandardScaler와 같이 객체설정 -> fit()로 학습 -> transform()로 변형 -> df로 다시 맞추면 된다.
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

 

 

즉 이 방법도 이상치 有 -> 데이터 왜곡 문제점 有

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MaxAbsScaler(): 모든 절댓값 in [0, 1] -> 0 기준 가장 큰 수가 -1 or 1. -> 이상치 영향받는 단점 똑같이 有

여기 예제부터는 머신러닝 개념이 들어가있다.

import sklearn
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer

cancer = load_breast_cancer()

cancer_df = pd.DataFrame(data=cancer.data, columns=cancer.feature_names)
cancer_df['target'] = cancer.target

X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, 
                                                    test_size=0.2, random_state=3)
dtc = DecisionTreeClassifier()
dtc.fit(X_train, y_train)  # split 및 분류 method 상태.



from sklearn.preprocessing import MaxAbsScaler  # 도입
 
mas = MaxAbsScaler()  #객체화
mas.fit(X_train)      #훈련셋 학습
X_train_scaled = mas.transform(X_train)
X_test_scaled = mas.transform(X_test)    # train과 test에 적용
dtc.fit(X_train_scaled, y_train)       # fit()에 train 
print('모델의 정확도 :', round(dtc.score(X_test_scaled, y_test), 4))

모델의 정확도 : 0.8947

 

X_train_scaled_mas = X_train_scaled.reshape(13650,1)

plt.hist(X_train_scaled_mas, bins=30, color='yellow', alpha = 0.7)
plt.title('MaxAbsScaler')
plt.show()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

RobustScaler(): StandardScaler와 유사. 그러나 SS는 평균, 분산 사용.

                           RS는 median(중간값, quartile(사분위값) 사용 -> 이상치 영향 방지

                            -> SS보다 RS가 표준화 후 데이터가 더 넓게 분포

 

from sklearn.preprocessing import RobustScaler

rbs = RobustScaler() # 객체화
X_train_scaled = rbs.fit_transform(X_train)  # 변형
X_test_scaled = rbs.transform(X_test)   # 적용
dtc.fit(X_train_scaled, y_train)  # 학습
print('모델의 정확도 :', round(dtc.score(X_test_scaled, y_test), 4))

모델의 정확도 : 0.9035

 

X_train_scaled_rbs = X_train_scaled.reshape(13650,1)

plt.hist(X_train_scaled_rbs, bins=30, color='pink', alpha = 0.7)
plt.title('RobustScaler')
plt.show()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Normalizer() : 각 row로 정규화 (앞 4개는 coulmns; feature 통계치 이용했음)

                  -> 각 row 모든 피쳐들 사이 유클리드 거리 = 1로 데이터 값 설정 -> 빠른 학습 & overfitting 방지

from sklearn.preprocessing import Normalizer

norm = Normalizer()
X_train_scaled = norm.fit_transform(X_train)  # 훈련 및 변형
X_test_scaled = norm.transform(X_test)   # 변형
dtc.fit(X_train_scaled, y_train)    # 훈련
print('모델의 정확도 :', round(dtc.score(X_test_scaled, y_test), 4))

모델의 정확도 : 0.9123

 

 

 

X_train_scaled_norm = X_train_scaled.reshape(13650,1)

plt.hist(X_train_scaled_norm, bins=30, alpha = 0.7)
plt.title('Normalizer')
plt.show()

 

 

결론: dataset과 사용하는 알고리즘에 따라 가장 적절한 스케일링 방법이 다르다


featureing (데이터 특성 조정) 예제

tips['per_one_bill'] = round(tips.total_bill / tips['size'], 2)  #반올림해서 정리

 

 

더미함수 예제 (카테고리형을 범주형으로 만들어 모형구축할 때 필요. 물론 ML때는 encord() 사용)

pd.get_dummies(df, columns = ['married','gender','nation'])

 

 

 

 

 

 

 

728x90
반응형