이전 filter method를 다룬 VIF (분산확장요인, python)에 이어서 작성하는 포스트입니다.
2022.01.11 - [공부/모델링] - VIF (분산확장요인, python)
Feature selection 방법은 크게 3가지로 나뉜다.
- Filter Method (Feature간 상관성 기반)
- Wrapper Method (Feature를 조정하며 모형을 형성하고 예측 성능을 참고하여 Feature 선택)
- Embedded Method (예측 모형 최적화, 회귀계수 추정 과정에서 각 Feature가 선택되는 방식)
이번에는 Wrapper Method 중 전진선택법에 대해 다루게 된다.
먼저 데이터를 불러오자.
사용할 데이터는 도요타 자동차 가격 데이터로 kaggle에서도 다운받을 수 있다.
https://www.kaggle.com/klkwak/toyotacorollacsv
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)
2022.01.11 - [공부/모델링] - 등분산 검정 (파이썬)
2021.11.18 - [공부/모델링] - Chi-square-test (카이제곱검정)
다음 글에서 이어집니다.
2022.01.13 - [공부/모델링] - Backward Feature Selection (후진제거법) python
'공부 > 통계학' 카테고리의 다른 글
Stepwise Feature Selection (단계선택법) python (0) | 2022.01.14 |
---|---|
Backward Feature Selection (후진제거법) python (0) | 2022.01.13 |
VIF (분산확장요인, python) (0) | 2022.01.11 |
비모수 검정 : Mann-Witney U-test (만 - 위트니 U 검정, python) (0) | 2022.01.11 |
웰치의 t 검정 : welch's t test (파이썬) (2) | 2022.01.11 |
댓글