[멋사][AI] TIL - 스케일링

티나(Tina)·2022년 11월 9일

멋사AI

목록 보기
22/41

참고 : 참고_github_url

변수 스케일링

  • 표준화(Z-score) : 평균을 빼주고 표준편차로 나눠준다.

    • (X - X.mean) / std
    • 평균이 0
    • 표준편차가 1
    • 평균을 이용하여 계산해주기 때문에 이상치에 영향을 받는다. (평균: 이상치의 값에 크게 영향을 받기 때문)
  • Min-Max : 0~1 사이값으로 만든다.

    • (X - X.min) / (X.max - X.min)
    • 최솟값이 0
    • 최대값이 1
    • 변수 범위를 0과 1사이로 압축해주는 개념
    • 이상치를 포함하고 있으면 범위설정에 영향이 가기 때문에 이상치에 의해 영향을 많이 받는다.
  • Robust : 중앙값을 빼주고 IQR값으로 나눠준다. 이상치에 덜 민감

    • (X - X.median) / IQR
    • 중앙값이 0
    • 중앙값(median)을 이용하기 때문에 StandardScaler, MinMaxScaler에 비해서 이상치의 영향을 덜 받는다.

트리 알고리즘에서는 절대적인 값보다 상대적인 값에 영향을 받기 때문에 스케일링에 영향을 크게 받지 않습니다. 하지만 다른 알고리즘에서는 스케일링 값을 조정해 주면 모델의 성능이 좋아집니다.


세가지 스케일링 방식이 어떤 차이가 있는지 실습을 통해 알아보기!

# import 하고 ,해서 여러개를 한번에 불러올 수 있지만
# sklearn 에서는 따로따로 불러오는걸 권장하고 있다. 
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import RobustScaler

StandardScaler

z = (x - u) / sz = (x - x.mean) / std

  • 시리즈형태 말고 dataFrame 형태를 넣어주어야 한다.
# StandardScaler
ss = StandardScaler()
train[["SalePrice_ss"]] =  ss.fit(train[["SalePrice"]]).transform(train[["SalePrice"]])

# MinMaxScaler
mm = MinMaxScaler()
train[["SalePrice_mm"]] = mm.fit(train[["SalePrice"]]).transform(train[["SalePrice"]])

# RobustScaler
rb = RobustScaler()
train[["SalePrice_rs"]] = rb.fit(train[["SalePrice"]]).transform(train[["SalePrice"]])
  • fit() : Compute the mean and std to be used for later scaling. matrix형태의 값을 받는다. 반환값도 matrix!

  • trainform() : Call func on self producing a DataFrame with the same axis shape as self.

    • 스케일링에서 fit 은 계산하기 위한 평균, 중앙값, 표준편차가 필요하다면 해당 데이터를 기준으로 기술통계값을 구하고 그 값을 기준으로 transform 에서 계산을 적용해서 값을 변환해준다.

  • fit 은 train 에만 사용하고 transform 은 train, test 에 사용한다.

    • fit 은 test 에 사용하지 않는다. 왜냐하면 기준은 train이다. 학습을 할 때도 fit은 train 에만 해주는 것과 동일함.

  • fit().transform() = fit_transform()

ss = StandardScaler()

train['SalePrice_ss'] = ss.fit(train[['SalePrice']]).transform(train[['SalePrice']])

train['SalePrice_ss'] = ss.fit_transform(train[['SalePrice']])

# fit_transform :  fit과 transfrom을 한 번에해준다.

  • describe 로 비교해보기

    train[["SalePrice", "SalePrice_ss", "SalePrice_mm", "SalePrice_rs"]].describe()

  • histogram 비교하기

_ = train[["SalePrice", "SalePrice_ss", "SalePrice_mm", "SalePrice_rs"]].hist(bins=50, figsize=(12,8))


로그 트랜스포메이션도 같이 해주기

# 로그 트랜스포메이션만
train["SalePrice_log1p"] = np.log1p(train["SalePrice"])

# Standard Scale 한 것에 log 트랜스포메이션
train["SalePrice_ss_log1p"] = np.log1p(train["SalePrice_ss"])

# log 트랜스포메이션 한것에  Standard Scale
train[["SalePrice_log1p_ss"]] = ss.fit_transform(train[["SalePrice_log1p"]])

train[["SalePrice_ss", "SalePrice_log1p", "SalePrice_ss_log1p", "SalePrice_log1p_ss"]].hist(bins=50, figsize=(10,8));

  • SalePrice_log1p_ss 가장 표준정규분포에 가깝다!!

  • SalePrice_log1p 도 정규분포에 가깝다.

  • 표준정규분포를 만들어주면 성능이 좋아질 수 있지만, 이상치가 왜곡이 되서 오히려 안좋아 질 수도 있다. 상황에 따라 다른 것!


이산화

이산화란 수치형 데이터를 일정 기준으로 나누어 그룹화하는 것!

Equal width binning(범위를 기준으로 나누는 방법)

pd.cut : 한 분할 안에 몇 개가 들어가는지와 무관하게 전체 수치 범위에 대해 n분할

  • 사용자가 이산화를 할 수치를 직접 입력하게 됩니다.

Equal frequency binning(빈도를 기준으로 나누는 방법)

pd.qcut : 개수를 기준으로 n분할

  • 계산한 특정 분위수를 기반으로 해서 이산화를 수행
# pd.cut 해주기
train["SalePrice_cut"] = pd.cut(train["SalePrice"], bins=4, labels=[1,2,3,4])

# pd.qcut 해주기
train["SalePrice_qcut"] = pd.qcut(train["SalePrice"], q=4, labels=[1,2,3,4])

# 히스토그램, cut, qcut 시각화하기
fig, axes = plt.subplots(1,3, figsize=(20,6))
_ = sns.histplot(data=train, x="SalePrice", bins=4,  ax=axes[0]).set_title("SalePrice_hist")
_ = sns.countplot(data=train, x="SalePrice_cut", ax=axes[1]).set_title("SalePrice_cut")
_ = sns.countplot(data=train, x="SalePrice_qcut", ax=axes[2]).set_title("SalePrice_qcut")

  • hist 는 bins 로 막대의 개수를 설정할 수 있는데 pd.cut 과 같은 개념이다.

  • pd.qcut 은 상대평가와 유사한 개념이기 때문에 pd.qcut 으로 데이터를 분할하게 되면 비슷한 비율로 나눠주게 된다.

  • 머신러닝에서 데이터를 분할해서 연속된 수치데이터를 이산화 해주는 이유 : 머신러닝 알고리즘에 힌트를 줄 수도 있고, 너무 세분화된 조건으로 오버피팅(과대적합)되지 않도록 도움을 줄 수 있다.


인코딩

인코딩이란 Categorical Feature를 Numerical Feature로 변환하는 것!

  • Orginal Encoding : 피처의 고유값들을 임의의 숫자로 바꾼다.
    • 결과가 벡터, 1차원 형태로 나온다.
    • 순서가 있는 명목형 데이터에 사용한다. (ex. 1분기, 2분기)
    • 데이터에 추가적인 가치를 더해주지 않는데, 순서가 없는 데이터에 적용해 주게 되면 크고 작은 의미가 있다고 생각하고 연산이 들어갈지도 모른다!
    • df["X"].astype("category").cat.codes
  • One Hot Encoding : 피쳐가 흩어져 있을 뿐 정보는 유지된다.
    • 결과가 matrix, 2차원 형태로 나온다.
    • 순서가 없는 명목형 데이터에 사용한다. (ex. 주택종류 등) 순서나 크기를 비교할 수 없는 범주형 데이터에 사용!
    • 단, 피처가 너무 많이 만들게 되면 계산에 시간이 오래 걸린다.
    • pd.get_dummies(df["X"])

판다스로 인코딩 했을때의 단점!

pandas.get_dummies는 train 데이터의 특성을 학습하지 않는다. 그냥 해당 dataFrame 에 dummies 를 만들어 주는 방법이기 때문에, pandas 의 get_dummies 를 사용해서 인코딩 하면 train, test 따로 인코딩을 하게 된다.
그러면 train 과 test 의 데이터가 다를경우 다른 feature 를 만들어 주게된다.

사이킷런의 원핫인코딩은 train 데이터로만 학습해서 진행하기에 test에만 존재하는 데이터를 인코딩하지 않는다. 그리고 train데이터에만 있는 카테고리도 test 데이터에 적용해 줄 수 있다.
즉, feature 를 train 기준으로 맞춰 줄 수 있다!


sklearn 으로도 인코딩 해보기


from sklearn.preprocessing import OrdinalEncoder
oe = OrdinalEncoder()
oe.fit_transform(train[["x"]])

from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder()
ohe.fit_transform(train[["x"]]).toarray()


다항식 파생변수

  • 수치형 데이터의 특징이 잘 구분 되지 않을 때, power transform 등을 통해 값을 제곱을 해주거나 하면 특징이 좀 더 구분 될 수 있다.
  • 이 방식이 신호가 될 수도 소음이 될 수도 있다.
profile
열심히 사는 중

0개의 댓글