2020. 6. 19. 14:44ㆍML in Python/Python
실습에 사용될 데이터 : Toyota Corolla Data (Toyota Corolla 모델 차 가격/기능 데이터)
회귀분석을 할 때 다중공선성이 발생하면, 데이터 분석의 신뢰성이나 예측 정확도를 떨어뜨린다. 이러한 문제를 하기 위한 방법 중 하나로 데이터 선정/전처리 과정에서 "변수선택"이 매우 중요하다.
변수 선택법(Variable Selection)은
1. 전진선택법(Forward Selection)
2. 후진소거법(Backward Elimination)
3. 단계적선택법(Stepwise Selection)
이 있다.
이 변수 선택법들을 알아가기 위해 Python을 통한 실습을 진행해보자. 이전 전치리과정과 모델 확인 과정은
이전게시물 : 변수선택법(1)에 존재한다. 학습이 목적이라면 보고 오는 것이 좋다.
link : https://todayisbetterthanyesterday.tistory.com/9
0. 변수선택법 (전체 경우의 수를 찾는 방법)
# 변수선택을 통해 형성한 모델의 AIC를 구하는 함수
# AIC가 낮을 수록 모델이 좋다고 평가된다.
def processSubset(X,y,feature_set):
model = sm.OLS(y,X[list(feature_set)]) # Modeling
regr = model.fit() # model fitting
AIC = regr.aic # model's AIC
return {"model" : regr, "AIC" : AIC}
print(processSubset(X = train_x, y = train_y, feature_set = feature_columns[0:5]))
# 전체 변수의 AIC test
processSubset(X=train_x, y=train_y, feature_set = feature_columns)
import time
import itertools
# getBest : 가장 낮은 AIC를 가지는 모델을 선택하고 저장하는 함수
def getBest(X,y,k):
tic = time.time() # 시작 시간
results = [] # 결과 저장 공간
for combo in itertools.combinations(X.columns.difference(['const'],k)) :
# 각 변수 조합을 고려한 경우의수
combo = (list(combo)+['const'])
# 상수항을 추가하여 combo를 결성
results.append(processSubset(X,y,feature_set = combo)) # 모델링된것을 저장
# 만약 k=2이면 여기서 두가지 변수만 뽑아서 경우의 수를 분석하여
# 저장 후 그 중 AIC가 가장 낮은 모델을 선택하도록 함
models = pd.DataFrame(results) # 데이터프레임으로 모델결과 변환
best_model = models.loc[models['AIC'].argmin()] # argmin은 최소값의 인덱스를 뽑는 함수
toc = time.time() # 종료 시간
print("Processed", models.shape[0], "models on", k, "predictors in",(toc - tic),"seconds.")
return best_model
print(getBest(X=train_x, y = train_y, k=2))
위의 함수는 전체 변수의 가능한 조합을 모두 확인하는 함수이다. 좋은 변수를 선택하여 모델을 만들 수 있겠지만, 문제는 변수의 총 수와 k가 증가할때마다 시간이 기하급수적으로 증가하는 문제가 생긴다. 그렇기 때문에 "변수를 선택하는 방법"을 선정해야한다.
# 변수 선택에 따른 학습시간과 저장
models = pd.DataFrame(columns=["AIC","model"])
tic = time.time()
for i in range(1,4):
models.loc[i] = getBest(X=train_x, y=train_y,k=i)
toc = time.time()
print("Total elapsed time:",(toc-tic),"seconds.")
# 선택된 변수의 개수(1,2,3)별 가장낮은 AIC를 보유한 모델들이 들어있는 DF
models
# 가장 AIC가 낮은 3번째 모델의 OLS결과를 출력
models.loc[3,"model"].summary()
# 모든 변수를 모델링한 것과 비교
print("full model Rsquared:","{:.5f}".format(fitted_full_model.rsquared))
print("full model AIC:","{:.5f}".format(fitted_full_model.aic))
print("full model MSE:","{:.5f}".format(fitted_full_model.mse_total))
print("selected model Rsquared:","{:.5f}".format(models.loc[3,"model"].rsquared))
print("selected model AIC:","{:.5f}".format(models.loc[3,"model"].aic))
print("selected model MSE:","{:.5f}".format(models.loc[3,"model"].mse_total))
1. 전진선택법
### 전진석택법(step=1)
def forward(X,y,predictors):
# predictor - 현재 선택되어있는 변수
# 데이터 변수들이 미리정의된 predictors에 있는지 없는지 확인 및 분류
remaining_predictors = [p for p in X.columns.difference(['const']) if p not in predictors]
tic = time.time()
results = []
for p in remaining_predictors :
results.append(processSubset(X=X,y=y,feature_set=predictors+[p]+['const']))
# 데이터프레임으로 변환
models = pd.DataFrame(results)
# AIC가 가장 낮은 것을 선택
best_model = models.loc[models['AIC'].argmin()]
toc = time.time()
print("Processed ",models.shape[0]. "models on", len(predictors)+1, "predictors in", (toc-tic))
print("Selected predictors:",best_model["model"].model.exog_names,"AIC: ",best_model[0])
return best_model
### 전진선택법 모델
def forward_model(X,y):
Fmodels = pd.DataFrame(columns=["AIC","model"])
tic = time.time()
# 미리 정의된 데이터 변수
predictors = []
# 변수 1~10개 : 0-9 -> 1-10
for i in range(1,len(X,columns.difference(['const']))+1):
Forward_result = forward(X=X,y=y,predictors=predictors)
if i > 1 :
if Forward_result["AIC"] > Fmodel_before:
break
Fmodels.loc[i] = Forward_result
predictors = Fmodels.loc[i]["model"].model.exog_names
Fmodel_before = Fmodels.loc[i]["AIC"]
predictors = [k for k in predictors if k != 'const']
toc = time.time()
print("Total elapsed time:",(toc-tic), "seconds.")
return (Fmodels['model'][len(Fmodels['model'])])
Forward_best_model = forward_model(X=train_x, y=train_y)
Forward_best_model.aic
Forward_best_model.summary()
2. 후진소거법
### 후진소거법(step=1)
def backward(X,y,predictors):
tic = time.time()
results = []
# 데이터 변수들이 미리 정의된 predictors 조합 확인
for combo in itertools.combinations(predictors, len(predictors) - 1):
results.append(processSubset(X=X,y=y,feature_set=list(combo)+['const']))
models = pd.DataFrame(results)
# 가장 낮은 AIC를 가진 모델을 선택
best_model = models.loc[models['AIC'].argmin()]
toc = time.time()
print("Processed ",models.shape[0], "models on", len(predictors) - 1, "predictors in",(toc-tic))
print("Selected predictors:",best_model['model'].model.exog_names,' AIC:',best_model[0])
return best_model
def backward_model(X,y) :
Bmodels = pd.DataFrame(columns=["AIC","model"], index = range(1,len(X.columns))
tic = time.time()
predictors = X.columns.difference(['const'])
Bmodel_before = processSubset(X,y,predictors)['AIC']
while (len(predictors) > 1):
Backward_result = backward(X=train_x, y= train_y, predictors=predictors)
if Backward_result['AIC'] > Bmodel_before :
break
Bmodels.loc[len(predictors) -1] = Backward_result
predictors = Bmodel.loc[len(predictors) - 1]['model'].model.exog_names
Bmodel_before = Backward_result["AIC"]
predictors = [k for k in predictors if k != 'const']
toc = time.time()
print("Total elapsed time:",(toc-tic),"seconds.")
return (Bmodels["model"].dropna().iloc[0]
Backward_best_model = backward_model(X=train_x, y= train_y)
Backward_best_model.aic
Backward_best_model.summary()
3. 단계적선택법
def Stepwise_model(X,y):
Stepmodels = pd.DataFrame(columns = ["AIC","model"])
tic = time.time()
predictors = []
Smodel_before = processSubset(X,y,predictors + ['const'])['AIC']
# 변수 1~10개 0-9 -> 1-10
for i in range(1,len(X.columns.difference(['const']))+1) :
Forward_result = forward(X=X,y=y,predictors = predictors) # constant added
print('forward')
predictors = Stepmodels.loc[i]['model'].model.exog_names
predictors = [k for k in predictors if k != 'const']
Backward_result = backward(X=X,y=y,predictors = predictors)
if Backward_result["AIC"] < Forward_result["AIC"]
Stepmodels.loc[i] = Backward_result
predictors = Stepmodels.loc[i]["model"].model.exog_names
Smodel_before = Stepmodels.loc[i]["AIC"]
predictors = [k for k in predictors k != "const"]
print('backward')
if Stepmodels.loc[i]["AIC"] > Smodel_before:
break
else :
Smodel_before = Stepmodels.loc[i]["AIC"]
toc = time.time()
print("Total elapsed time:",(toc-tic),"seconds.")
return (Stepmodels["model"][len(Stepmodels["model"])])
Stepwise_best_model.aic
4. 성능평가
# number of params
print(Forward_best_model.params.shape, Backward_best_model.params.shape, Stepwise_best_model.params.shape)
# 모델에 의해 예측된/추정된 값 = test_y
pred_y_full = fitted_full_model.predict(test_x)
pred_y_forward = Forward_best_model.predict(test_x[Forward_best_model.model.exog_names])
pred_y_backward = Backward_best_model.predict(test_x[Backward_best_model.model.exog_names])
pred_y_stepwise = Stepwise_best_model.predict(test_x[Stepwise_best_model.model.exog_names])
# MSE, RMSE, MAE, MAPE 4가지 지표를 통해 예측성능을 확인할 예정
perf_mat = pd.DataFrame(columns=["ALL", "FORWARD", "BACKWARD", "STEPWISE"],index =['MSE', 'RMSE','MAE', 'MAPE'])
# MAPE의 함수
def mean_absolute_percentage_error(y_true, y_pred):
y_true, y_pred = np.array(y_true), np.array(y_pred)
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
from sklearn import metrics # 나머지는 sklearn에서 활용
# 성능지표
perf_mat.loc['MSE']['ALL'] = metrics.mean_squared_error(test_y,pred_y_full)
perf_mat.loc['MSE']['FORWARD'] = metrics.mean_squared_error(test_y,pred_y_forward)
perf_mat.loc['MSE']['BACKWARD'] = metrics.mean_squared_error(test_y,pred_y_backward)
perf_mat.loc['MSE']['STEPWISE'] = metrics.mean_squared_error(test_y,pred_y_stepwise)
perf_mat.loc['RMSE']['ALL'] = np.sqrt(metrics.mean_squared_error(test_y, pred_y_full))
perf_mat.loc['RMSE']['FORWARD'] = np.sqrt(metrics.mean_squared_error(test_y, pred_y_forward))
perf_mat.loc['RMSE']['BACKWARD'] = np.sqrt(metrics.mean_squared_error(test_y, pred_y_backward))
perf_mat.loc['RMSE']['STEPWISE'] = np.sqrt(metrics.mean_squared_error(test_y, pred_y_stepwise))
perf_mat.loc['MAE']['ALL'] = metrics.mean_absolute_error(test_y, pred_y_full)
perf_mat.loc['MAE']['FORWARD'] = metrics.mean_absolute_error(test_y, pred_y_forward)
perf_mat.loc['MAE']['BACKWARD'] = metrics.mean_absolute_error(test_y, pred_y_backward)
perf_mat.loc['MAE']['STEPWISE'] = metrics.mean_absolute_error(test_y, pred_y_stepwise)
perf_mat.loc['MAPE']['ALL'] = mean_absolute_percentage_error(test_y, pred_y_full)
perf_mat.loc['MAPE']['FORWARD'] = mean_absolute_percentage_error(test_y, pred_y_forward)
perf_mat.loc['MAPE']['BACKWARD'] = mean_absolute_percentage_error(test_y, pred_y_backward)
perf_mat.loc['MAPE']['STEPWISE'] = mean_absolute_percentage_error(test_y, pred_y_stepwise)
print(perf_mat)
위의 표를 보면 4가지 모두 모든 변수를 넣었을때 오차와 비슷하다는 것을 확인할 수 있다. 하지만, 모든 변수를 넣은 모델은 변수가 37개나 되기에, 학습의 효율성 측면에서 Full 변수 모델보다 효율적이다. 그리고 다중공선성 과적합과 같은 문제가 발생할 때, 변수를 줄이는 방법을 통해서 모델의 신뢰성을 높일 수 있을 것이다.
'ML in Python > Python' 카테고리의 다른 글
[Python]회귀계수 축소법 실습 - Ridge,Lasso (0) | 2020.06.24 |
---|---|
[Python]로지스틱회귀분석 실습 (2) | 2020.06.20 |
[Python]변수선택법 실습(1) - 변수선택법 실습 이전단계, 불필요한 변수 제거 및 가변수 추가 ~ 다중공선성 확인작업 (변수선택법의 코드는 (2)에서) (9) | 2020.06.16 |
[Python]다중회귀분석 실습 - 모델해석과 다중공선성 확인하기 (0) | 2020.06.13 |
[Python]다중회귀분석 실습 - 데이터 불러오기부터 회귀계수까지 (1) | 2020.06.13 |