변수분포문제 - 피쳐와 라벨간 약한 관계 또는 비선형 관계일때

2021-07-28

.

Data_Preprocessing_TIL(20210728)

[학습자료]

패스트캠퍼스 온라인 강의 “파이썬을 활용한 데이터 전처리 Level UP 올인원 패키지 Online.” 를 공부하고 정리한 내용입니다.

URL : https://fastcampus.co.kr/data_online_preprocess

[학습내용]

  • 변수분포 문제란 일반화된 모델을 학습하는데 어려움이 있는 분포를 가지는 변수가 있어서, 일반화된 모델을 학습하지 못하는 문제

  • 변수분포 문제를 해결하지 않아도 모델학습 자체는 가능하나 당연히 좋은 성능을 낼 수 없다.

  • 변수분포 문제의 대표적인 다섯가지

1) 피쳐과 라벨간 약한관계 또는 비선형 관계일때

2) 이상치 포함하는 데이터가 있을때

3) 피쳐간에 상관성이 강해서 문제가 발생하는 경우

4) 변수간에 스케일 차이가 커서 발생하는 문제

5) 데이터가 정규분포를 따르지 않고 일반분포(알수없는 분포)를 따르는 경우

  • 피쳐와 라벨간 약한관계 또는 비선형 관계일때는 어떤게 문제냐

피쳐와 라벨간 관계가 없거나 매우 약하다면, 어떠한 전처리 및 모델링을 하더라도 예측력이 높은 모델을 만들 수 없다.

사실 일반적으로는 피쳐와 라벨간에 관계가 있지만 이를 잘 못찾는 경우가 대다수이다. 예를 들어서 피쳐와 라벨간에 비선형 관계가 존재하는 경우인데 피쳐와 라벨간 비선형 관계가 존재한다면, 적절한 전처리를 통해 모델 성능을 크게 향상 시킬수 있다.

선형회귀 같은 경우에 x와 y가 아래 그림과 같이 곡선의 2차원 모양이다 라고 하면 x를 그대로 쓰는게 아니라 x의 제곱을 쓰면 더 좋은 성능이 좋을 것이다. 그리고 아래에 로지스틱 회귀 모델 사례 처럼 데이터의 구간에 대한 패턴을 파악하고 적절하게 나누면 또 좋은 성능을 낼 것이다.

1

참고로 대다수의 머신러닝 모델은 선형식(y=wx+b)을 포함한다.

피쳐가 만약에 10개정도 된다면 피쳐 하나하나 그래프를 그려가면서 관계를 확인하면 되기 때문에 큰 문제는 없을 것이다. 하지만 피쳐가 그이상으로 많다면 이를 일일히 하나씩 확인하는 것이 어려울 것이다. 또한 그래프만 찍어본다고 해서 이게 정말로 관계가 있는건지는 확신할수도 없다. 하나의 피쳐만 하나의 레벨에 영향을 주는게 아니기 때문이다. 여러개의 피쳐가 하나의 라벨에 동시에 영향을 주는 경우가 일반적일 것이다. 이를 제대로 보기 위해서는 다차원 그래프를 그려봐야 하는데 차원이 3차원 이상만 되더라도 그릴수가 없는 지경이다. 결론적으로 그래프를 그려서 관계를 확인한다는 것은 쉽지 않다.

  • 그러면 어떻게 하면 되냐

간단한 방법으로는 어떤 관계가 라벨에 관계가 있는지 모르니까 피쳐별로 다 라벨과의 관계를 그려보는 것이다. x 제곱도 만들어보고, 로그 x도 만들어보고, exp(x)도 만들어보고, 아니면 두 컬럼을 더해보고, 빼보고 하는 등의 피쳐들을 만들어보는 것이다.

가장 이상적인 해결방안은 각 피쳐에 대해, 피쳐와 라벨 간 관계를 나타내는 그래프를 통해 적절한 피쳐 변환을 수행해야 한다. 하지만 피쳐갯수가 많고, 다른 피쳐에 의한 영향도가 존재하는 등 그래프를 통해 적절한 변환 방법을 선택하는 것은 쉽지 않아, 다양한 변환방법을 사용하여 피쳐를 생성한 뒤 피쳐선택을 수행해야 한다.

  • 실습

다양한 변환방법을 사용하여 피쳐를 생성해서 모델링을 해보고, 피쳐를 생성하지 않은 모델과 성능을 비교해보자

import os
import pandas as pd

os.chdir(r"C:/Users/user/Desktop/aa/5. 머신러닝 모델의 성능 향상을 위한 전처리\데이터")

df = pd.read_csv("Combined_Cycle_Power_Plant.csv")
df
T V AP RH EP
0 8.34 40.77 1010.84 90.01 480.48
1 23.64 58.49 1011.40 74.20 445.75
2 29.74 56.90 1007.15 41.91 438.76
3 19.07 49.69 1007.22 76.79 453.09
4 11.80 40.66 1017.13 97.20 464.43
... ... ... ... ... ...
9563 15.12 48.92 1011.80 72.93 462.59
9564 33.41 77.95 1010.30 59.72 432.90
9565 15.99 43.34 1014.20 78.66 465.96
9566 17.65 59.87 1018.58 94.65 450.93
9567 23.68 51.30 1011.86 71.24 451.67

9568 rows × 5 columns

# 특징과 라벨 분리
X = df.drop('EP', axis = 1)
Y = df['EP']
# 신규 데이터 생성
# 특징이 추가된 데이터를 부착할 데이터
X_added = X.copy() 

import numpy as np
# 로그와 제곱 관련 변수만 추가
for col in X.columns:
    X_added[col + '_squared'] = X[col] ** 2
    X_added[col + '_log'] = np.log(X[col])

X_added
T V AP RH T_squared T_log V_squared V_log AP_squared AP_log RH_squared RH_log
0 8.34 40.77 1010.84 90.01 69.5556 2.121063 1662.1929 3.707947 1.021798e+06 6.918537 8101.8001 4.499921
1 23.64 58.49 1011.40 74.20 558.8496 3.162940 3421.0801 4.068856 1.022930e+06 6.919091 5505.6400 4.306764
2 29.74 56.90 1007.15 41.91 884.4676 3.392493 3237.6100 4.041295 1.014351e+06 6.914880 1756.4481 3.735524
3 19.07 49.69 1007.22 76.79 363.6649 2.948116 2469.0961 3.905804 1.014492e+06 6.914949 5896.7041 4.341074
4 11.80 40.66 1017.13 97.20 139.2400 2.468100 1653.2356 3.705245 1.034553e+06 6.924740 9447.8400 4.576771
... ... ... ... ... ... ... ... ... ... ... ... ...
9563 15.12 48.92 1011.80 72.93 228.6144 2.716018 2393.1664 3.890186 1.023739e+06 6.919486 5318.7849 4.289500
9564 33.41 77.95 1010.30 59.72 1116.2281 3.508855 6076.2025 4.356068 1.020706e+06 6.918003 3566.4784 4.089667
9565 15.99 43.34 1014.20 78.66 255.6801 2.771964 1878.3556 3.769076 1.028602e+06 6.921855 6187.3956 4.365135
9566 17.65 59.87 1018.58 94.65 311.5225 2.870736 3584.4169 4.092176 1.037505e+06 6.926165 8958.6225 4.550186
9567 23.68 51.30 1011.86 71.24 560.7424 3.164631 2631.6900 3.937691 1.023861e+06 6.919546 5075.1376 4.266054

9568 rows × 12 columns

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression as LR

# 5겹 교차 검증 기반의 평가 수행
X_score = cross_val_score(LR(), X, Y, cv = 5, scoring = 'neg_mean_absolute_error').mean()
X_added_score = cross_val_score(LR(), X_added, Y, cv = 5, scoring = 'neg_mean_absolute_error').mean()

# 결론적으로 성능이 좋아졌다. 
print("특징 추가 전:{}, 특징 추가 후:{}".format(X_score, X_added_score))
특징 추가 전:-3.6282513807290457, 특징 추가 후:-3.332221506696368