[변수 선택 및 생성]중요 변수 선택 및 파생 변수 만들기-2

2020. 1. 9. 22:52분석 Python/Data Preprocessing

728x90

이전 글 https://data-newbie.tistory.com/382

저번 글에서 피드백을 받은 PolynomialFeatures와 추가적인 2가지 변수가 아닌 중요 변수 조합을 시각화하는 그림을 만들어봤다.
대신 polynomial은 곱하기 연산으로만 이루어져서, 나누기라던지, 빼기는 표현이 되지 않지만, 쉽게 쓸 수 있다는 장점이 있어서 좋은 것 같다.

import matplotlib.pyplot as plt
import numpy as np
import pandasa as pd
import saeborn as sns
from scipy.stats import wasserstein_distance as wd , ks_2samp as ks , energy_distance as ed

일단 중요 변수는 저번 글에서 뽑았으니 그대로 사용하자.

중요 변수 :  ['V2', 'V5', 'V7', 'V9', 'V10', 'V15', 'V16', 'V28']

일단은 저 중요 변수의 조합인 8C2 = 28개 x (곱하기(4)) = 112개를 만들어보자.

 

import itertools
important =  ['V2', 'V5', 'V7', 'V9', 'V10', 'V15', 'V16', 'V28']
newcol = ["+" , "-" , "x", "/"]
# combinations
a = list(itertools.combinations(important , 2))

이제는 시각화를 해보자 그러면 112 x 4로 시각화를 해보자.
추가로 ks , energy distance  , wasserstein distance 총 3가지를 같이 보여주는 것으로 바꿨다.

fig , axes = plt.subplots(nrows=len(a) ,ncols=len(newcol),
                          figsize=(20,80) )
plt.subplots_adjust(left=0.05, bottom=0.01, right=0.99, 
                    top=0.99, wspace=None, hspace=0.7)
ax = axes.flatten()
combinations = list(map(list,itertools.product(a, newcol))) ## 112
for idx , col in enumerate(combinations) : 
    one , two = col[0]
    cal = col[1]
    name = "{} {} {}".format(one , cal , two)
    if cal == "+" :
        data[name] = (data.loc[: , one] + data.loc[: , two])
    elif cal == "/" :
        data[name] = (data.loc[: , one] / data.loc[: , two])
    elif cal == "-" :
        data[name] = (data.loc[: , one] - data.loc[: , two])
    elif cal == "x" :
        data[name] = (data.loc[: , one] * data.loc[: , two])
    target1 = data.loc[idx1 , [name]].dropna()
    target0 = data.loc[idx0 , [name]].dropna()
    m = MinMaxScaler(feature_range=(-1,1))
    target1 = m.fit_transform(target1)
    target0 = m.fit_transform(target0)
    sns.distplot(target1 , ax = ax[idx])
    sns.distplot(target0 , ax = ax[idx])
    kdist , b = ks(np.squeeze(target1) , np.squeeze(target0))
    wdist = wd(np.squeeze(target1) , np.squeeze(target0))
    edist = ed(np.squeeze(target1) , np.squeeze(target0))
    msg = "[{}] | ed : {} | ks : {} | wd : {}".format(name , 
                                                np.round(edist,3),
                                                np.round(kdist,3),
                                                np.round(wdist,3),
                                               )
    ax[idx].set_title(msg , fontsize=  10)
    
plt.savefig("./New.png")
plt.show()

이런 식의 그림을 얻을 수 있다!

이제는 polynomialfeature를 통해서 만들어보자.

from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(4 , interaction_only=True ,include_bias=False)
important =  ['V2', 'V5', 'V7', 'V9', 'V10', 'V15', 'V16', 'V28']
#poly.fit_trans
poly_result = poly.fit(data[important])
poly_result = poly.transform(data[important])
cols = ["poly_{}".format(i) for i in range(poly_result.shape[1])]
output = pd.DataFrame(poly_result , columns= cols)
poly_result.shape ## (85347, 162)

이제 162개의 새로운 변수가 만들어졌는데, 이러면 너무 많으니 분포 간 거리를 재서 1보다 클 경우에만 쓰는 식으로 정하였다.

store = []
for idx , col in enumerate(cols) : 
    target1 = output.loc[idx1 , [col]].dropna()
    target0 = output.loc[idx0 , [col]].dropna()
    m = MinMaxScaler(feature_range=(-1,1))
    target1 = m.fit_transform(target1)
    target0 = m.fit_transform(target0)
    wdist = wd(np.squeeze(target1) , np.squeeze(target0))
    if wdist > 1 :
        store.append(col)
        
len(store)  ## 39

그러면 남은 개수는 162 -> 39개의 유용한 변수들로만 압축했다.
이제 다시 애들을 위의 그림과 동일하게 시각화해보자.

fig , axes = plt.subplots(nrows=10 ,ncols=4,
                         figsize=(20,20) )
plt.subplots_adjust(left=0.05, bottom=0.01, right=0.99, 
                    top=0.99, wspace=None, hspace=0.7)
ax = axes.flatten()
for idx , col in enumerate(store) : 
    target1 = output.loc[idx1 , [col]].dropna()
    target0 = output.loc[idx0 , [col]].dropna()
    m = MinMaxScaler(feature_range=(-1,1))
    target1 = m.fit_transform(target1)
    target0 = m.fit_transform(target0)
    
    kdist , b = ks(np.squeeze(target1) , np.squeeze(target0))
    wdist = wd(np.squeeze(target1) , np.squeeze(target0))
    edist = ed(np.squeeze(target1) , np.squeeze(target0))
    
    sns.distplot(target1 , ax = ax[idx])
    sns.distplot(target0 , ax = ax[idx])
    
    msg = "[{}] | ed : {} | ks : {} | wd : {}".format(col , 
                                                np.round(edist,3),
                                                np.round(kdist,3),
                                                np.round(wdist,3),
                                               )
    ax[idx].set_title(msg , fontsize=  10)
plt.savefig("./New2.png")
plt.show()

polynomial feature를 쓰면 n차 interaction까지 반영할 수 있다.
대신에 아쉽게도 나누기 빼기 더하기 같은 것은 할 수가 없다.

이런 식으로 유용한 변수를 얻어서 변수에 추가하면 모델링하는데 도움이 될 것이라고 생각한다.

- 끝 -

728x90