[STBDA2023] 05wk-019: MinMaxScaler를 이용한 전처리

Author

김보람

Published

October 8, 2023

해당 자료는 전북대학교 최규빈 교수님 2023학년도 2학기 빅데이터분석특강 자료임

05wk-019: MinMaxScaler를 이용한 전처리

최규빈
2023-10-05

1. 강의영상

https://youtu.be/playlist?list=PLQqh36zP38-ywZaSM1Sud-5KrwZr3CwCb&si=EknsMgx3Yq6jmOoF

2. Imports

import numpy as np
import pandas as pd
import sklearn.preprocessing 

3. MinMaxScaler()

A. 모티브

- 예제자료 로드

df = pd.read_csv('https://raw.githubusercontent.com/guebin/MP2023/main/posts/employment.csv').loc[:7,['toeic','gpa']]
df
toeic gpa
0 135 0.051535
1 935 0.355496
2 485 2.228435
3 65 1.179701
4 445 3.962356
5 65 1.846885
6 290 0.309928
7 730 0.336081

- 모형을 돌려보고 해석한 결과

u = X.toeic*0.00571598 + X.gpa*2.46520018 -8.45433334
v = 1/(1+np.exp(-u))
v # 확률같은것임
  • 토익이 중요해? 아니면 학점이 중요해?

토익은 990점 만점이고 gpa는 4.5만점이므로 위의 수식에서 바로 계산하는 것보단 스케일링을 해주자

  • 얼만큼 중요해?

- 모티브: 토익점수를 0-1사이로 맞추고 gpa도 0-1사이로 맞추면 해석이 쉽지 않을까?

B. 사용방법

- 스케일러 생성

sclr = sklearn.preprocessing.MinMaxScaler()

- fit, transform

sclr.fit(df)
MinMaxScaler()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
sclr.transform(df)
array([[0.08045977, 0.        ],
       [1.        , 0.07772319],
       [0.48275862, 0.55663499],
       [0.        , 0.28847292],
       [0.43678161, 1.        ],
       [0.        , 0.45907256],
       [0.25862069, 0.06607128],
       [0.76436782, 0.07275881]])
  • 제일 큰값은 1 제일 작은 값은 0으로 맞춰줌

- fit_transform

sclr.fit_transform(df)
array([[0.08045977, 0.        ],
       [1.        , 0.07772319],
       [0.48275862, 0.55663499],
       [0.        , 0.28847292],
       [0.43678161, 1.        ],
       [0.        , 0.45907256],
       [0.25862069, 0.06607128],
       [0.76436782, 0.07275881]])

C. 잘못된 사용

- sclr.fit()sclr.fit_transform()은 입력으로 2차원 자료구조를 기대한다. (그중에서도 은근히 numpy array를 기대함)

sclr.fit_transform(df['toeic']) # df['toeic']는 1차원 자료구조
ValueError: Expected 2D array, got 1D array instead:
array=[135. 935. 485.  65. 445.  65. 290. 730.].
Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.
df['toeic']
0    135
1    935
2    485
3     65
4    445
5     65
6    290
7    730
Name: toeic, dtype: int64
sclr.fit_transform(df[['toeic']]) # df[['toeic']]는 2차원 자료구조
array([[0.08045977],
       [1.        ],
       [0.48275862],
       [0.        ],
       [0.43678161],
       [0.        ],
       [0.25862069],
       [0.76436782]])
df[['toeic']]
toeic
0 135
1 935
2 485
3 65
4 445
5 65
6 290
7 730

4. minmax_scale()

A. 사용방법

- scaler를 오브젝트로 따로 만들지 않고 함수형으로 구현

sklearn.preprocessing.minmax_scale(df)
array([[0.08045977, 0.        ],
       [1.        , 0.07772319],
       [0.48275862, 0.55663499],
       [0.        , 0.28847292],
       [0.43678161, 1.        ],
       [0.        , 0.45907256],
       [0.25862069, 0.06607128],
       [0.76436782, 0.07275881]])

- 이것은 심지어 1차원 자료구조에도 적용가능하다.

sklearn.preprocessing.minmax_scale(df['toeic'])
array([0.08045977, 1.        , 0.48275862, 0.        , 0.43678161,
       0.        , 0.25862069, 0.76436782])

- 열별로 스케일링을 하는게 아니라 행별로 스케일링을 하는 것도 가능하다. (여기서는 필요없지만..)

sklearn.preprocessing.minmax_scale(df,axis=1)
array([[1., 0.],
       [1., 0.],
       [1., 0.],
       [1., 0.],
       [1., 0.],
       [1., 0.],
       [1., 0.],
       [1., 0.]])

B. discussions

- 언뜻 보기에는 MinMaxScaler 보다 minmax_scale이 좋아보이는데, 생각보다 일반적으로 minmax_scale을 사용하지는 않음. 이유는 아래와 같음.

  1. 파이썬을 쓰는 사람들이 함수형 접근방식보다 객체지향 접근방식을 선호한다. (이건 제생각)
  2. 학습데이터와 테스트데이터의 스케일링시 동일한 변환을 유지하는 상황에서는 MinMaxScaler 가 유리함.
  3. inverse_transform 메서드를 같은 부가기능을 제공함.

5. (tr,test)의 스케일링

- 주어진 자료가 아래와 같이 train/test로 나누어져 있다고 가정해보자.

X = np.array([1.0, 2.0, 3.0, 4.0, 5.0]).reshape(-1,1)
XX = np.array([1.5, 2.5, 3.5]).reshape(-1,1)
X,XX
(array([[1.],
        [2.],
        [3.],
        [4.],
        [5.]]),
 array([[1.5],
        [2.5],
        [3.5]]))

A. 잘못된 스케일링 방법 – 비효율의 문제

sklearn.preprocessing.minmax_scale(X)
array([[0.  ],
       [0.25],
       [0.5 ],
       [0.75],
       [1.  ]])
sklearn.preprocessing.minmax_scale(XX)
array([[0. ],
       [0.5],
       [1. ]])

- 이 방법은 전략적으로 비효율적인 문제이지, 치팅과 관련된 치명적인 잘못은 아니다.

  • 만약에 어떠한 경우에 이러한 전처리 방식이 오히려 전략적이라고 판단될 경우 사용할수도 있음.

B. 올바른 스케일링 방법

- 방법1

sclr = sklearn.preprocessing.MinMaxScaler()
sclr.fit(X) # 
MinMaxScaler()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
sclr.transform(X)
array([[0.  ],
       [0.25],
       [0.5 ],
       [0.75],
       [1.  ]])
sclr.transform(XX)
array([[0.125],
       [0.375],
       [0.625]])

- 방법2

sclr = sklearn.preprocessing.MinMaxScaler()
sclr.fit_transform(X)
array([[0.  ],
       [0.25],
       [0.5 ],
       [0.75],
       [1.  ]])
sclr.transform(XX)
array([[0.125],
       [0.375],
       [0.625]])

C. scaled_value \(\in\) [0,1]?

- 주어진 자료가 아래와 같다고 하자.

X = np.array([1.0, 2.0, 3.0, 4.0, 3.5]).reshape(-1,1)
XX = np.array([1.5, 2.5, 5.0]).reshape(-1,1)
sclr = sklearn.preprocessing.MinMaxScaler()
sclr.fit_transform(X)
sclr.transform(XX)
array([[0.16666667],
       [0.5       ],
       [1.33333333]])
  • 스케일링된 값이 1보다 클 수도 있다.

D. 아주 잘못된 스케일링 방법 – 정보누수

- 주어진 자료가 아래와 같다고 하자.

X = np.array([1.0, 2.0, 3.0, 4.0, 3.5]).reshape(-1,1)
XX = np.array([1.5, 2.5, 5.0]).reshape(-1,1)

- 데이터를 합친다.. (미쳤어??)

np.concatenate([X,XX])
array([[1. ],
       [2. ],
       [3. ],
       [4. ],
       [3.5],
       [1.5],
       [2.5],
       [5. ]])

- 합친데이터에서 스케일링

sklearn.preprocessing.minmax_scale(np.concatenate([X,XX]))[:5]
array([[0.   ],
       [0.25 ],
       [0.5  ],
       [0.75 ],
       [0.625]])

- 이러한 전처리 방식을 정보누수라고 한다. (대회 규정에 따라서 탈락사유에 해당함)

6. inverse_transform

arr = sclr.fit_transform(df)
arr 
array([[0.08045977, 0.        ],
       [1.        , 0.07772319],
       [0.48275862, 0.55663499],
       [0.        , 0.28847292],
       [0.43678161, 1.        ],
       [0.        , 0.45907256],
       [0.25862069, 0.06607128],
       [0.76436782, 0.07275881]])
sclr.inverse_transform(arr).round(5)
array([[1.35000e+02, 5.15300e-02],
       [9.35000e+02, 3.55500e-01],
       [4.85000e+02, 2.22843e+00],
       [6.50000e+01, 1.17970e+00],
       [4.45000e+02, 3.96236e+00],
       [6.50000e+01, 1.84689e+00],
       [2.90000e+02, 3.09930e-01],
       [7.30000e+02, 3.36080e-01]])
df
toeic gpa
0 135 0.051535
1 935 0.355496
2 485 2.228435
3 65 1.179701
4 445 3.962356
5 65 1.846885
6 290 0.309928
7 730 0.336081

inverse_transform한거랑 df한 거랑 값 보면 비슷—