ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Keras] 튜토리얼12 - Scikit-learn의 Scaler
    💫 Computer Science/Python & AI Framework 2020. 1. 5. 21:29

    ● 스케일링(Scaling)이란?

    스케일링이란 데이터 전처리 과정의 하나 입니다.

     

    • 데이터의 값이 너무 크거나 혹은 작은 경우에 모델 알고리즘 학습과정에서 0으로 수렴하거나 무한으로 발산해 버릴 수 있는 것을 방지하거나, 예측 값이 범위를 벗어나는 입력데이터의 값에 더 큰 영향을 받는 것을 방지합니다.
    • 스케일링을 통해 다타원의 값들을 비교 분석하기 쉽게 만들어 줍니다.
    • 자료의 overflow나 underflow를 방지하고 최적화 과정에서 안정성 및 수렴 속도를 향상시킵니다.

     

    예를 들어 키와 몸무게가 입력 데이터로 주어지고 라벨데이터는 100m달리기에 걸리는 시간을 예측한다고 하면, 키와 몸무게는 서로 범위, Unit이 다르기 때문에 더 큰 값을 가진 키 값이 결과 값에 더 큰 영향을 미치는 것을 방지하기 위해 키와 몸무게 데이터의 유닛을 맞춰주는 작업을 해야합니다. 그럴때 사용하는 것이 바로 Scaling입니다.

     

     

     

     

    ○ 회귀분석에서 조건수

    함수의 조건수(condition numger)는 인자에서 작은 변화의 비율에 대해 함수가 얼마나 크게 변하는지에 대한 인자 측정치 입니다. 조건수가 크면 약간의 오차만 있어도 해가 전혀 다른 값을 갖게 됩니다. 따라서 조건수가 크면 회구분석을 사용한 예측값도 오차가 커지게 됩니다.

     

    조건수가 커지는 경우는(회귀분석에서),

     

    변수들의 단위 차이가 있는 경우

    -> 스케일링으로 해결

     

    상관관계가 큰 독립 변수들이 있는 경우

    -> 변수 선택이나 PCA를 사용한 차원 축소 등으로 해결

     

    독립 변수나 종속 변수가 심하게 한쪽으로 치우친 분포를 보이는 경우(독립 변수와 종속 변수 간의 관계가 곱셈 혹은 나눗셈으로 연결된 경우 종속 변수와 예측치가 비선형 관계를 보이는 경우)

    -> 로그 함수 혹은 제곱근 함수를 사용하여 변환된 변수를 사용하면 회귀 성능이 향상될 수도 있습니다. 금액 처럼 튼 수치 데이터에 로그를 취하게 되는 이유이기도 합니다.

     

     

     

     

     

    ○ Scaler의 종류

     

    Standard Scaler

     

    - 기존 변수에 범위를 정규 분포로 변환

    - (x - x의 평균값) / (x의 표준편차)

    - 데이터의 최소, 최대 값을 모를 경우 사용

     

    각 피처의 평균을 0, 분산을 1로 변경합니다. 모든 특성들이 같은 스케일을 갖게 됩니다. 평균을 제거하고 데이터를 단위 분산으로 조정합니다. 그러나 이상치가 있다면 평균과 표준편차에 영향을 미쳐 변환된 데이터의 확산은 매우 달라지게 됩니다. 따라서 이상치(Outlier)가 있는 경우 균형 잡힌 척도를 보장할 수 없게 됩니다.

     

     

     

    Robust Scaler

     

    - StandardScaler에 의한 표준화보다 동일한 값을 더 넓게 분포

    - 이상치(outlier)를 포함하는 데이터를 표준화하는 경우

     

    모든 특성들이 같은 크기를 갖는다는 점에서 Standard Scaler와 비슷하지만, 평균과 분산 대신 Median과 IQR(interquartile range)을 사용하며, 이상치(Outlier)의 영향을 최소화 합니다. StandardScaler와 비교해보면 표준화 후 동일한 값을 더 넓게 분포 시키고 있음을 확인 할 수 있습니다.

    (IQR = Q3 - Q1 : 25% ~ 75% 타일의 값을 다룬다.)

     

     

     

     

     

     

     

    MinMax Scaler

     

    - 데이터를 0-1사이의 값으로 변환

    - (x - x의 최소값) / (x의 최대값 - x의 최소값)

    - 데이터의 최소, 최대 값을 알 경우 사용

     

    모든 피처가 0과 1사이에 값을 가집니다. 최대값이 1이 되고 최소값이 0이 되도록 스케일링 합니다. 데이터가 2차원 셋일 경우, x축과 y축 값 모두 0과 1사이의 값을 가집니다. 상치가 있는 경우 변환된 값이 매우 좁은 범위로 압축될 수 있습니다. MinMax 역시 이상치(Outlier)의 존재에 민감합니다.

    MaxAbs Scaler라는 것도 있는데, 최대 절대값과 0이 각 1, 0이 되도록 하여 양수 데이터로만 구성되게 스케일링 하는 기법입니다.

     

     

     

    Normalizer

     

    Standard Scaler, Robust Scaler, MinMax Scaler는 각 컬럼의 통계치를 이용한다면, Normalizer는 각 로우마다 정규화 됩니다. Normalizer는 유클리드 거리가 1이 되도록 데이터를 조정합니다.(L2 Distance)

    Normalize를 하게 되면 Spherical contour(구형 윤곽)을 갖게 되는데, 이렇게 하면 좀 더 빠르게 학습할 수 있고 과대적합 확률을 낮출 수 있습니다.

     

     

     

     

     

    데이터 분포별 변환 결과

    변환 분포를 살펴보면 StandardScaler와 RobustScaler의 변환된 결과가 대부분 표준화된 유사 형태의 데이터 분포로 반환된다.

    MinMaxScaler특정값에 집중되어 있는 데이터가 그렇지 않은 데이터 분포보다 1표준편차에 의한 스케일 변화값이 커지게 된다. 한쪽으로 쏠림 현상이 있는 데이터 분포는 형태가 거의 유지된채 범위값이 조절되는 결과를 보인다.

    MaxAbsScaler의 경우, MinMaxScaler와 유사하나 음수와 양수값에 따른 대칭 분포를 유지하게 되는 특징이 있다.

    그리고 마지막 이미지를 통해 살펴보면, 대부분의 스케일링 기법에서 아웃라이어는 변환 효과를 저해하는 요소임이 드러난다.

    유의해야할 점은, 스케일링시 Feature별로 크기를 유사하게 만드는 것은 중요하지만, 그렇다고 모든 Feature의 분포를 동일하게 만들 필요는 없다.

    특성에 따라 어떤 항목은 원본데이터의 분포를 유지하는 것이 유의할 수 있다. 예로 데이터가 거의 한 곳에 집중되어 있는 Feature를 표준화시켜 분포를 같게 만들었을때 작은 단위의 변화가 큰 차이를 나타내는 것으로 반영될 수 있기 때문이다.

    (출처)

     

     

     

     

    ○ Scikit-Learn에서 구현

     

    - Scaler의 fit()transform()

    fit() : 데이터 변환을 학습, 학습용 데이터에만 적용
    transform() : 실제 데이터의 스케일을 조정, 학습용 데이터와 테스트 데이터에 적용

     

     

    MinMax Scaler

     

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    from numpy import array, transpose
    from keras.models import Sequential
    from keras.layers import Dense, LSTM
     
     
    = array([[1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7],
                [6,7,8], [7,8,9], [8,9,10], [9,10,11], [10,11,12],
                [20000,30000,40000], [30000,40000,50000], [40000,50000,60000]])
    = array([4,5,6,7,8,9,10,11,12,13,50000,60000,70000])
     
    from sklearn.preprocessing import MinMaxScaler
    scaler = MinMaxScaler()
    scaler.fit(x) # 실행
    = scaler.transform(x) # 전환 evaluate, preidict과정 같은 것
    # print(x)
    # [[0.00000000e+00 0.00000000e+00 0.00000000e+00]
    #  [2.50006250e-05 2.00008000e-05 1.66675000e-05]
    #  [5.00012500e-05 4.00016001e-05 3.33350001e-05]
    #  [7.50018750e-05 6.00024001e-05 5.00025001e-05]
    #  [1.00002500e-04 8.00032001e-05 6.66700002e-05]
    #  [1.25003125e-04 1.00004000e-04 8.33375002e-05]
    #  [1.50003750e-04 1.20004800e-04 1.00005000e-04]
    #  [1.75004375e-04 1.40005600e-04 1.16672500e-04]
    #  [2.00005000e-04 1.60006400e-04 1.33340000e-04]
    #  [2.25005625e-04 1.80007200e-04 1.50007500e-04]
    #  [4.99987500e-01 5.99983999e-01 6.66649999e-01]
    #  [7.49993750e-01 7.99992000e-01 8.33325000e-01]
    #  [1.00000000e+00 1.00000000e+00 1.00000000e+00]]
     
    print(x.shape) # (13,3)
    print(y.shape) # (13,)
     
    model = Sequential()
    model.add(Dense(10, activation = 'relu', input_shape=(3,)))
    model.add(Dense(10))
    model.add(Dense(1))
     
    model.compile(optimizer='adam', loss='mse')
    model.fit(x, y, epochs=100, verbose=2, batch_size=1)
     
    x_input = array([25,35,45]) # (3,)
    x_input = x_input.reshape(1,3)
    x_input = scaler.transform(x_input)
    # x, y에서 사용한 scaler 가중치 그대로 사용해야한다. x_input의 점위는 25-45
    # 잘못된 예제. 전처리는 한꺼번에, 나중에 스케일하면 매핑값과에서 문제가 생길 수 있음
     
    yhat = model.predict(x_input)
    print(yhat)
     
    # activation='linear'가 default
    cs

     

    # 데이터의 구조가 선형회귀 모델에 사용하기 적합하지 않음

    # 모델이 잘 인식할 수 있게 데이터를 전처리 해주어야 함

    # 소수의 데이터가 값이 크다. 예측값을 100이나 1000으로 주어져도 10000단위로 예측 될 가능성이 많다.

    # 정규화 필요 -> 그 중 하나 MinMax Scaler 1~70000의 범위를 0~1사이로

    # xi–min(x)/max(x)–min(x) , xi 데이터의 각 계수

    # The MinMaxScaler is the probably the most famous scaling algorithm, and follows the following formula for each feature:

    # It essentially shrinks the range such that the range is now between 0 and 1 (or -1 to 1 if there are negative values).

    # This scaler works better for cases in which the standard scaler might not work so well. If the distribution is not Gaussian

    # or the standard deviation is very small, the min-max scaler works better.

    # However, it is sensitive to outliers, so if there are outliers in the data, you might want to consider the Robust Scaler below.

     

    # 연산이 빨라지고 예측률도 올라가지만 여전히 데이터가 치우쳐있다는 문제점이 있음

    # x값을 스케일해도 y값과 매핑되는 값은 변함이 없으므로 y값 스케일 해줄 필요 없음

     

     

     

     

    Robust Scaler

     

    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
    30
    31
    32
    33
    34
    from numpy import array, transpose
    from keras.models import Sequential
    from keras.layers import Dense, LSTM
     
    = array([[1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7],
                [6,7,8], [7,8,9], [8,9,10], [9,10,11], [10,11,12],
                [20000,30000,40000], [30000,40000,50000], 
                [40000,50000,60000], [100,200,300]])
    = array([4,5,6,7,8,9,10,11,12,13,50000,60000,70000,400])
     
    print(x.shape) # (14,3)
    print(y.shape) # (14,)
     
    from sklearn.preprocessing import RobustScaler, MaxAbsScaler
    scaler = RobustScaler()
    scaler.fit(x)
    = scaler.transform(x)
     
    # train : predict = 13 : 1
    x_train = x[:13]
    x_predict = x[13:]
    y_train = y[:13]
     
    model = Sequential()
    model.add(Dense(100, activation = 'relu', input_shape=(3,)))
    model.add(Dense(50))
    model.add(Dense(10))
    model.add(Dense(1))
     
    model.compile(optimizer='adam', loss='mse')
    model.fit(x_train, y_train, epochs=800, verbose=2, batch_size=1)
     
    yhat = model.predict(x_predict)
    print(yhat)
    cs

     

    # 잘 사용하지는 않음

    # RobustScaler(X): 중앙값(median)이 0, IQR(interquartile range)이 1이 되도록 변환.

    # MaxAbsScaler(X): 0을 기준으로 절대값이 가장 큰 수가 1또는 -1이 되도록 변환

     

     

     

     

    Standard Scaler

     

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    from numpy import array, transpose
    from keras.models import Sequential
    from keras.layers import Dense, LSTM
     
    = array([[1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7],
                [6,7,8], [7,8,9], [8,9,10], [9,10,11], [10,11,12],
                [20000,30000,40000], [30000,40000,50000], 
                [40000,50000,60000], [100,200,300]])
    = array([4,5,6,7,8,9,10,11,12,13,50000,60000,70000,400])
     
    print(x.shape) # (14,3)
    print(y.shape) # (14,)
     
    from sklearn.preprocessing import MinMaxScaler, StandardScaler
    scaler = StandardScaler()
    scaler.fit(x)
    = scaler.transform(x)
     
    # train : predict = 13 : 1
    x_train = x[:13]
    x_predict = x[13:]
    y_train = y[:13]
     
    model = Sequential()
    model.add(Dense(100, activation = 'relu', input_shape=(3,)))
    model.add(Dense(50))
    model.add(Dense(10))
    model.add(Dense(1))
     
    model.compile(optimizer='adam', loss='mse')
    model.fit(x_train, y_train, epochs=800, verbose=2, batch_size=1)
     
    # x값 중 1개 잘라서 predict로 사용
    yhat = model.predict(x_predict)
    print(yhat)
     
    # RESULT
    # [[401.8668]] , [[420.38123]] ...
    # 데이터가 들쑥 날쑥이라 결과 값이 좋지 않음.
    cs

     

    # StandardScalar 평균이 0과 표준편차가 1이 되도록 변환. 데이터가 치우쳐져 있을 경우

    # 정규화 공식 x - 평균 / 표준편차 https://m.blog.naver.com/algosn/221308973343

    # 넓게 분포된 데이터들 보다 모여진 데이터가 더 예측률이 좋다.

     

     

     

    Normalization(정규화)

     

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    # 1. 데이터
    import numpy as np
    = np.array(range(1,101)) # 1~100
    = np.array(range(1,101))
     
    from sklearn.model_selection import train_test_split
    x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=66, test_size=0.4)
    x_test, x_val, y_test, y_val = train_test_split(x_test, y_test, random_state=66, test_size=0.5)
     
    # 2. 모델 구성
    from keras.models import Sequential
    from keras.layers import Dense, BatchNormalization, Dropout
    model = Sequential()
    model.add(Dense(1000, input_shape=(1,), activation='relu'))
    model.add(Dense(1000))
    model.add(BatchNormalization()) # 두번째 레이어의 가중치를 모아주는 역할
    model.add(Dropout(0.2))
    model.add(Dense(1000))
    model.add(BatchNormalization())
    model.add(Dense(1000))
    model.add(BatchNormalization())
    model.add(Dense(1000))
    model.add(Dense(1))
     
    # 3. 훈련
    model.compile(loss='mse', optimizer='adam', metrics=['mse'])
    model.fit(x_train, y_train, epochs=100, batch_size=1, validation_data=(x_val, y_val))
     
    # 4. 평가 예측
    loss, mse = model.evaluate(x_test, y_test, batch_size=1)
    print('acc : ', mse)
     
    y_predict = model.predict(x_test)
    print(y_predict)
     
    # RMSE 구하기
    from sklearn.metrics import mean_squared_error
    def RMSE(y_test, y_predict):
        return np.sqrt(mean_squared_error(y_test, y_predict))
    print('RMSE : ', RMSE(y_test, y_predict)) 
     
    # R2 구하기
    from sklearn.metrics import r2_score
    r2_y_predict = r2_score(y_test, y_predict)
    print('R2 : ', r2_y_predict)
    cs
     

    # Normalization 일반화

    # 일반화() 정규화(MinmaxScaler) 표준화(StandardScaler) -> 정리하기

    # 일반화는 레이어단계, 정규 표준화는 데이터단계

    # 레이어의 가중치(w)를 표준화 하는 것...

    # BatchNormalization과 Dropout 같이 써도 에러는 나지 않지만

    # 같이쓰면 과적합 회피가 잘되는지는 않음 통상적으로 둘 중 하나만 사용

    # GAN이라는 기법에서는 같이 사용

     

    댓글

Designed by Tistory.