본문 바로가기
공부/통계학

Forward feature selection (전진선택법) python

by signature95 2022. 1. 12.
728x90
반응형

이전 filter method를 다룬 VIF (분산확장요인, python)에 이어서 작성하는 포스트입니다.

2022.01.11 - [공부/모델링] - VIF (분산확장요인, python)

 

VIF (분산확장요인, python)

Feature selection 방법은 크게 3가지로 나뉜다. Filter Method (Feature간 상관성 기반) Wrapper Method (Feature를 조정하며 모형을 형성하고 예측 성능을 참고하여 Feature 선택) Embedded Method (예측 모형..

signature95.tistory.com

 

Feature selection 방법은 크게 3가지로 나뉜다.

  1. Filter Method (Feature간 상관성 기반)
  2. Wrapper Method (Feature를 조정하며 모형을 형성하고 예측 성능을 참고하여 Feature 선택)
  3. Embedded Method (예측 모형 최적화, 회귀계수 추정 과정에서 각 Feature가 선택되는 방식)

이번에는 Wrapper Method 중 전진선택법에 대해 다루게 된다.

 

 

먼저 데이터를 불러오자.

사용할 데이터는 도요타 자동차 가격 데이터로 kaggle에서도 다운받을 수 있다.

 

https://www.kaggle.com/klkwak/toyotacorollacsv

 

ToyotaCorolla.csv

 

www.kaggle.com

import pandas as pd

data = pd.read_csv('https://raw.githubusercontent.com/signature95/tistory/main/dataset/ToyotaCorolla.csv')

data.info()

출력 결과

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1436 entries, 0 to 1435
Data columns (total 37 columns):
 #   Column            Non-Null Count  Dtype 
---  ------            --------------  ----- 
 0   Id                1436 non-null   int64 
 1   Model             1436 non-null   object
 2   Price             1436 non-null   int64 
 3   Age_08_04         1436 non-null   int64 
 4   Mfg_Month         1436 non-null   int64 
 5   Mfg_Year          1436 non-null   int64 
 6   KM                1436 non-null   int64 
 7   Fuel_Type         1436 non-null   object
 8   HP                1436 non-null   int64 
 9   Met_Color         1436 non-null   int64 
 10  Automatic         1436 non-null   int64 
 11  cc                1436 non-null   int64 
 12  Doors             1436 non-null   int64 
 13  Cylinders         1436 non-null   int64 
 14  Gears             1436 non-null   int64 
 15  Quarterly_Tax     1436 non-null   int64 
 16  Weight            1436 non-null   int64 
 17  Mfr_Guarantee     1436 non-null   int64 
 18  BOVAG_Guarantee   1436 non-null   int64 
 19  Guarantee_Period  1436 non-null   int64 
 20  ABS               1436 non-null   int64 
 21  Airbag_1          1436 non-null   int64 
 22  Airbag_2          1436 non-null   int64 
 23  Airco             1436 non-null   int64 
 24  Automatic_airco   1436 non-null   int64 
 25  Boardcomputer     1436 non-null   int64 
 26  CD_Player         1436 non-null   int64 
 27  Central_Lock      1436 non-null   int64 
 28  Powered_Windows   1436 non-null   int64 
 29  Power_Steering    1436 non-null   int64 
 30  Radio             1436 non-null   int64 
 31  Mistlamps         1436 non-null   int64 
 32  Sport_Model       1436 non-null   int64 
 33  Backseat_Divider  1436 non-null   int64 
 34  Metallic_Rim      1436 non-null   int64 
 35  Radio_cassette    1436 non-null   int64 
 36  Tow_Bar           1436 non-null   int64 
dtypes: int64(35), object(2)
memory usage: 415.2+ KB

그리고 sklearn의 train_test_split을 가져와서 데이터를 분리한다.

from sklearn.model_selection import train_test_split

# Feature, target 분리
df = data.drop(columns = {'Price', 'Id', 'Model'})
target = data['Price']

# train, test 데이터 분리 (8 : 2)
X_train, X_test, y_train, y_test = train_test_split(df, target, test_size=0.2, shuffle=True, random_state=34)

# 연료 변수가 object이므로 더미화 진행 (type : 3개)
X_train = pd.get_dummies(X_train)
X_test = pd.get_dummies(X_test)

먼저 전진선택법으로 feature selection 과정 없이 바로 OLS 회귀를 시도해본다.

# OLS 회귀를 위한 라이브러리 호출
import statsmodels.api as sm

# add_constant를 통해 상수항 생성
X_train = sm.add_constant(X_train)

# 모델 형성 및 결과 출력
model = sm.OLS(y_train, X_train).fit()
model.summary()

결과 출력

                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  Price   R-squared:                       0.906
Model:                            OLS   Adj. R-squared:                  0.904
Method:                 Least Squares   F-statistic:                     327.2
Date:                Wed, 12 Jan 2022   Prob (F-statistic):               0.00
Time:                        02:09:30   Log-Likelihood:                -9659.8
No. Observations:                1148   AIC:                         1.939e+04
Df Residuals:                    1114   BIC:                         1.956e+04
Df Model:                          33                                         
Covariance Type:            nonrobust                                         
====================================================================================
                       coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------------
Age_08_04         -123.0813      3.882    -31.709      0.000    -130.697    -115.465
Mfg_Month          -99.3575     10.030     -9.906      0.000    -119.037     -79.678
Mfg_Year             1.9901      0.818      2.432      0.015       0.385       3.595
KM                  -0.0161      0.001    -12.730      0.000      -0.019      -0.014
HP                  23.7477      3.362      7.064      0.000      17.151      30.344
Met_Color          -27.6293     75.421     -0.366      0.714    -175.612     120.353
Automatic          425.3048    148.485      2.864      0.004     133.963     716.647
cc                  -0.0869      0.078     -1.116      0.265      -0.240       0.066
Doors               85.0947     39.542      2.152      0.032       7.510     162.679
Cylinders           -0.0330      0.002    -15.142      0.000      -0.037      -0.029
Gears              165.4233    202.827      0.816      0.415    -232.543     563.389
Quarterly_Tax       13.0932      1.778      7.363      0.000       9.604      16.583
Weight               8.4347      1.211      6.967      0.000       6.059      10.810
Mfr_Guarantee      217.9115     73.397      2.969      0.003      73.900     361.923
BOVAG_Guarantee    429.2382    123.585      3.473      0.001     186.754     671.723
Guarantee_Period    66.0271     14.265      4.629      0.000      38.038      94.016
ABS               -363.5526    126.413     -2.876      0.004    -611.586    -115.519
Airbag_1           171.9706    243.669      0.706      0.480    -306.132     650.073
Airbag_2           -25.7073    128.554     -0.200      0.842    -277.943     226.528
Airco              206.1457     87.896      2.345      0.019      33.686     378.606
Automatic_airco   2269.8082    189.464     11.980      0.000    1898.062    2641.554
Boardcomputer     -336.0481    115.845     -2.901      0.004    -563.347    -108.749
CD_Player          245.9519     97.957      2.511      0.012      53.751     438.152
Central_Lock      -177.1558    139.214     -1.273      0.203    -450.306      95.995
Powered_Windows    500.6008    140.942      3.552      0.000     224.059     777.143
Power_Steering      47.5105    280.255      0.170      0.865    -502.377     597.398
Radio              457.9836    657.484      0.697      0.486    -832.064    1748.031
Mistlamps           14.8378    108.159      0.137      0.891    -197.380     227.056
Sport_Model        377.4451     86.339      4.372      0.000     208.041     546.850
Backseat_Divider  -259.3296    128.036     -2.025      0.043    -510.548      -8.111
Metallic_Rim       187.7640     94.034      1.997      0.046       3.260     372.268
Radio_cassette    -605.8313    657.744     -0.921      0.357   -1896.388     684.726
Tow_Bar           -214.7932     78.290     -2.744      0.006    -368.406     -61.181
Fuel_Type_CNG    -1029.3034    213.488     -4.821      0.000   -1448.186    -610.420
Fuel_Type_Diesel   137.5537    175.440      0.784      0.433    -206.676     481.783
Fuel_Type_Petrol   891.7414    181.901      4.902      0.000     534.835    1248.648
==============================================================================
Omnibus:                       95.104   Durbin-Watson:                   2.068
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              497.925
Skew:                           0.130   Prob(JB):                    7.53e-109
Kurtosis:                       6.216   Cond. No.                     1.10e+16
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The smallest eigenvalue is 5.87e-20. This might indicate that there are
strong multicollinearity problems or that the design matrix is singular.

결정계수 (R-squared)를 보면 매우 높게 나오고 P값도 유의한게 많아보이는데, 이는 겉으로만 좋아보이는 것이다.

아직 VIF도 고려하지 않았고, 아무런 검정도 하지 않았기 때문이다. 

 

위에서 시행한 OLS 분석은 사실상 통계적 유의성을 보장하지 못한다.
기본적으로 OLS 가정에 해당한 변수간 독립성, 등분산성, 정규성 등을 검정하지 않았고,
오차항의 독립성도 검증되지 않았기 때문이다.

 

사실 이를 해결하기 위해서 여러 검정을 실시해야 하지만, 이번 포스트에서는 전진선택만을 활용하여 feature selection을 진행하는 것이 목적이기에 그에 맞춰 코드를 작성해볼 것이다.

 

 

그렇다면, 바로 전진선택법으로 넘어가도록 한다. 

## 전진 단계별 선택법

# feature 및 target
variables = X_train.columns.tolist() 
y = y_train 

# 선택된 변수들 list 생성
forward_valriables = []

# 전진선택시 P 값을 고려할 때, 선택과 제거 임계치 설정    
sl_enter = 0.05
sl_remove = 0.05

# 각 스텝별로 선택된 변수들
sv_per_step = [] 
# 각 스텝별 수정된 결정계수
adj_r_squared_list = []
# 스텝
steps = []
step = 0


while len(variables) > 0:
    remainder = list(set(variables) - set(forward_valriables))
    pval = pd.Series(index=remainder) ## 변수의 p-value
    ## 기존에 포함된 변수와 새로운 변수 하나씩 돌아가면서 
    ## 선형 모형을 적합한다.
    for col in remainder: 
        X = X_train[forward_valriables+[col]]
        X = sm.add_constant(X)
        model = sm.OLS(y,X).fit(disp=0)
        pval[col] = model.pvalues[col]
 
    min_pval = pval.min()
    if min_pval < sl_enter: ## 최소 p-value 값이 기준 값보다 작으면 포함
        forward_valriables.append(pval.idxmin())
        ## 선택된 변수들에대해서
        ## 어떤 변수를 제거할지 고른다.
        while len(forward_valriables) > 0:
            selected_X = X_train[forward_valriables]
            selected_X = sm.add_constant(selected_X)
            selected_pval = sm.OLS(y,selected_X).fit(disp=0).pvalues[1:] ## 절편항의 p-value는 뺀다
            max_pval = selected_pval.max()
            if max_pval >= sl_remove: ## 최대 p-value값이 기준값보다 크거나 같으면 제외
                remove_variable = selected_pval.idxmax()
                forward_valriables.remove(remove_variable)
            else:
                break
        
        step += 1
        steps.append(step)
        adj_r_squared = sm.OLS(y,sm.add_constant(X_train[forward_valriables])).fit(disp=0).rsquared_adj
        adj_r_squared_list.append(adj_r_squared)
        sv_per_step.append(forward_valriables.copy())
    else:
        break

각 step 별 선택된 feature에 대하여 adj R^2 값을 plot으로 그려보자

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10,10))
fig.set_facecolor('white')
 
font_size = 15
plt.xticks(steps,[f'step {s}\n'+'\n'.join(sv_per_step[i]) for i,s in enumerate(steps)], fontsize=1)
plt.plot(steps, adj_r_squared_list, marker='o')
    
plt.ylabel('adj_r_squared',fontsize=font_size)
plt.grid(True)
plt.show()

그리고 최종 선정된 feature는 다음과 같다. (전진선택은 feature가 추가가 된 후 제거되지 않는 단점도 있음)

['Cylinders', 'Mfg_Year', 'Automatic_airco', 'HP', 'Weight', 'KM', 'Powered_Windows',
'Quarterly_Tax', 'Fuel_Type_Petrol', 'Guarantee_Period', 'BOVAG_Guarantee', 
'Sport_Model', 'Tow_Bar', 'Airco', 'ABS', 'Mfr_Guarantee', 'Boardcomputer', 
'Fuel_Type_CNG', 'CD_Player', 'Automatic', 'Mfg_Month', 'Age_08_04', 'Backseat_Divider', 
'Metallic_Rim', 'Doors']

총 25개가 선정되었음

전진 선택법 수행 후 다시 OLS를 출력해보자

print(model.summary())

>>>

			OLS Regression Results                            
==============================================================================
Dep. Variable:                  Price   R-squared:                       0.906
Model:                            OLS   Adj. R-squared:                  0.904
Method:                 Least Squares   F-statistic:                     450.9
Date:                Wed, 12 Jan 2022   Prob (F-statistic):               0.00
Time:                        02:33:34   Log-Likelihood:                -9662.8
No. Observations:                1148   AIC:                         1.938e+04
Df Residuals:                    1123   BIC:                         1.950e+04
Df Model:                          24                                         
Covariance Type:            nonrobust                                         
====================================================================================
                       coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------------
Cylinders           -0.0320      0.002    -16.253      0.000      -0.036      -0.028
Mfg_Year             2.4642      0.667      3.697      0.000       1.156       3.772
Automatic_airco   2292.5767    178.935     12.812      0.000    1941.493    2643.661
HP                  23.4782      3.250      7.224      0.000      17.102      29.855
Weight               8.3748      1.198      6.992      0.000       6.025      10.725
KM                  -0.0161      0.001    -12.846      0.000      -0.019      -0.014
Powered_Windows    507.5704    139.303      3.644      0.000     234.246     780.894
Quarterly_Tax       13.0361      1.719      7.583      0.000       9.663      16.409
Fuel_Type_Petrol   785.8087    280.370      2.803      0.005     235.701    1335.916
Guarantee_Period    65.5132     13.923      4.706      0.000      38.196      92.830
BOVAG_Guarantee    444.7764    121.280      3.667      0.000     206.816     682.737
Sport_Model        390.1581     82.996      4.701      0.000     227.314     553.002
Tow_Bar           -231.0339     76.223     -3.031      0.002    -380.589     -81.478
Airco              212.6361     84.683      2.511      0.012      46.480     378.792
ABS               -348.4905     98.143     -3.551      0.000    -541.054    -155.927
Mfr_Guarantee      209.2126     72.094      2.902      0.004      67.758     350.667
Boardcomputer     -316.2576    113.947     -2.775      0.006    -539.831     -92.684
Fuel_Type_CNG    -1164.3102    338.900     -3.436      0.001   -1829.259    -499.362
CD_Player          256.5195     94.533      2.714      0.007      71.038     442.001
Automatic          401.9744    146.726      2.740      0.006     114.086     689.863
Mfg_Month         -100.0338      9.958    -10.046      0.000    -119.572     -80.496
Age_08_04         -122.0024      3.737    -32.643      0.000    -129.336    -114.669
Backseat_Divider  -230.6905    115.667     -1.994      0.046    -457.639      -3.742
Metallic_Rim       207.7290     88.582      2.345      0.019      33.924     381.534
Doors               82.5542     38.725      2.132      0.033       6.573     158.535
Central_Lock      -170.1247    137.086     -1.241      0.215    -439.099      98.850
==============================================================================
Omnibus:                       93.622   Durbin-Watson:                   2.066
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              477.911
Skew:                           0.136   Prob(JB):                    1.67e-104
Kurtosis:                       6.149   Cond. No.                     2.97e+18
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The smallest eigenvalue is 8.07e-25. This might indicate that there are
strong multicollinearity problems or that the design matrix is singular.

전진선택법 수행으로 각 feature의 P 값은 다 5% 미만으로 유의하게 도출되었다.

하지만 앞에서 언급하였듯 OLS의 기본가정에 대한 검정을 수행하지 않았기 때문에 해당 결과는 유의하다고 하기 어려울 것이다.

따라서 각 변수에 대한 coef 해석이나 다른 부분에 대해서는 자세한 언급을 하지 않도록한다.

 

정규성 검정, 등분산성, 독립성 검정은 다음 포스트를 참고하면된다.

2022.01.11 - [공부/모델링] - 정규성 검정 (Python)

 

정규성 검정 (Python)

정규성을 확인하는 방법은 시각적으로 표를 그려보는 방법, 통계 검정을 통해 확인하는 방법이 존재합니다. 시각화 Q-Q plot 통계 검정  Shapiro - Test Anderson - Test KS - Test Normal-Test Jarque_bera - Te..

signature95.tistory.com

2022.01.11 - [공부/모델링] - 등분산 검정 (파이썬)

 

등분산 검정 (파이썬)

등분산검정(Equal-variance test)은 두 정규성을 만족하는 데이터에서 생성된 두 개의 데이터 집합으로부터 두 정규분포의 모분산이 같은지 확인하기 위한 검정이다. 바틀렛(bartlett), 플리그너(fligner),

signature95.tistory.com

2021.11.18 - [공부/모델링] - Chi-square-test (카이제곱검정)

 

Chi-square-test (카이제곱검정)

카이제곱 분포 χ2 분포는 k개의 서로 독립적인 표준정규 확률변수를 각각 제곱한 다음 합해서 얻어지는 분포이다. 이 때 k를 자유도라고 하며, 카이제곱 분포의 매개변수가 된다. 카이제곱 분

signature95.tistory.com

 

 

다음 글에서 이어집니다.

2022.01.13 - [공부/모델링] - Backward Feature Selection (후진제거법) python

 

Backward Feature Selection (후진제거법) python

이전 Wrapper method를 다룬 Forward Feature Selection (전진선택법, python)에 이어서 작성하는 포스트입니다. 2022.01.12 - [공부/모델링] - Forward feature selection (전진선택법) python Forward feature s..

signature95.tistory.com

 

728x90

댓글