ADP 실기 13장 Linear Regression Analysis
본 게시물은 통계적 선형 회귀분석에 대해 소개한다.
1. 단순 회귀분석
1.1 Category
- 문제 풀이시 가장 먼저 확인해야 할 것은 데이터의 타입
1.2 Evaluation
-
단순 선형 회귀분석
- R-square: 총 변동 중에 설명된 변동의 비율 ☞ 값이 높을수록 새로운 값을 추정하여도 믿을 만함
- RMSE: 분산 분석에서의 SSE를 자유도 n-2로 나눈 것이 MSE이며, 이에 루트를 취한 값
-
다중 선형 회귀분석
- Adjusted R-square: 독립변수가 2개 이상일 때 사용되며, 독립변수가 늘어날 수록 R-square 값이 커지는 것에 대한 패널티를 적용한 것
📍 자유도
- 보통 빅데이터 분석에서는 n이 커진다면 1, 2 값의 차이는 의미가 없어 자유도로 나누지 않고 n으로 나눔
1.3 Considerations
-
모형이 데이터를 잘 적합하고 있는가
- 모형의 잔차가 특정 패턴을 이루고 있지 않아야 함
-
회귀 모형이 통계적으로 유의한가
- F 통계량을 사용하며, 이를 통해 얻은 p-value가 유의수준보다 작아야 함
- H0: 회귀 모형이 유의하지 않음
- H1: 회귀 모형이 유의함
- F 통계량을 사용하며, 이를 통해 얻은 p-value가 유의수준보다 작아야 함
-
모형은 데이터를 얼마나 설명할 수 있는가
- R-square를 통해 설명력을 확인함
-
모형 내의 회귀계수는 유의한가
- 각 독립변수에 대해 회귀 계수를 검정
- 독립변수의 회귀계수는 t 통계량을 사용하며, 이를 통해 얻은 P-value가 유의수준보다 작아야 함
1.4 Parameters
statsmodels.formula.api.ols(formula, data, subset=None, drop_cols=None, *args, **kwargs)
- formular: 모델을 지정하는 공식을 작성
- data: 모델에 적용할 데이터
- drop_cols: 삭제할 데이터 컬럼
1.5 Methods
- model.summary(): 모델 적합 결과를 요약하여 제시
- model.parmas: 변수들의 회귀계수
- model.predict(): 새로운 데이터에 대한 예측 값
1.6 Implementation
😗 집의 평수와 가격의 선형 회귀 분석
import pandas as pd
import numpy as np
house = pd.read_csv("https://raw.githubusercontent.com/ADPclass/ADP_book_ver01/main/data/kc_house_data.csv")
house = house[["price","sqft_living"]]
## 독립변수와 종속변수의 선형 가정
house.corr()
- 분석 진행 전, 독립변수와 종속변수 간의 상관계수를 확인
from statsmodels.formula.api import ols
import matplotlib.pyplot as plt
# 변수 할당
y = house['price']
X = house[['sqft_living']]
# 단순 선형 회귀 모형 적합
lr = ols('price ~ sqft_living',data=house).fit()
y_pred = lr.predict(X)
# 시각화
plt.scatter(X, y) ## 원 데이터 산포도
plt.plot(X, y_pred, color='red') ## 회귀직선 추가
plt.xlabel('sqft_living', fontsize=10)
plt.ylabel('price',fontsize=10)
plt.title('Linear Regression Result')
plt.show()
lr.summary()
📍 모형 해석
-
모형이 데이터를 잘 적합하는가?
-
원본 데이터와 회귀선을 시각화 후, 데이터의 분포를 보고 판단
-
0에서 멀어질 수록 오차가 커짐 ☞ 잔차의 분산이 증가 (=등분산성이 벗어남)
☞ 모델이 데이터를 잘 설명하고 있지 않음
-
-
회귀 모형이 통계적으로 유의한가?
- F 통계량과 P-value를 확인
- p-value < 0.05 이므로 유의함
- F 통계량과 P-value를 확인
-
모형은 데이터를 얼마나 설명할 수 있는가?
- R-square가 0.493으로 모형이 전체 데이터의 49.3%를 설명
- 통계적으로 유의하다고 모델의 성능이 좋은 것은 아님
- 지표가 좋고 나쁨은 산업별로 다름
- R-square가 0.493으로 모형이 전체 데이터의 49.3%를 설명
-
모형 내의 회귀계수는 유의한가?
- t 통계량과 p-value를 확인
- P-value < 0.05 이므로 유의함
- t 통계량과 p-value를 확인
2. 다중 회귀분석
2.1 다중공선성
선형 회귀분석에서 독리변수들 간에 강한 상관관계가 나타나는 문제로, 정확한 회귀계수 추정과 독립변수의 해석을 어렵게 하고, 모델의 일반화 능력을 저하시킴
-
독립변수간 상관계수를 구하여 상관성이 0.9 이상일 경우
-
두 독립변수의 회귀분석을 통해 얻은 허용오차(1-R-square)가 0.1 이하일 경우
-
VIF 값이 10 이상일 경우
1.2 변수선택법
모형 내 설명변수가 증가할 수록 데이터 관리 비용이 필요하기에, 종속변수에 영향을 미치는 유의미한 독립변수만을 선택하여 최적의 회귀 방정식을 도출하는 과정
- 전진 선택법: 하나씩 변수를 추가하여 지표를 확인
- 후진 제거법: 모든 변수를 추가한 뒤 하나씩 제거하며 지표를 확인
- 단계적 선택법: 변수를 추가, 제거하며 모델의 지표를 확인
📍 모델의 지표
-
F-통계량
-
AIC
1.3 Implementation
😗차 가격에 영향을 미치는 변수들로 모형 구축
import pandas as pd
# 데이터 불러오기
Cars = pd.read_csv("https://raw.githubusercontent.com/ADPclass/ADP_book_ver01/main/data/Cars93.csv")
Cars.info()
# Column Non-Null Count Dtype
--- ------ -------------- -----
4 Price 93 non-null float64
6 MPG.city 93 non-null int64
7 MPG.highway 93 non-null int64
11 EngineSize 93 non-null float64
13 RPM 93 non-null int64
18 Length 93 non-null int64
19 Wheelbase 93 non-null int64
24 Weight 93 non-null int64
- 다양한 변수 중 분석을 위해 사용할 변수들
import numpy as np
import statsmodels.api as sm
import statsmodels.formula.api as smf
# ols 모델의 formula을 정의할 때, 일부 특수문자는 쓸 수 없기에, 컬럼 특수문자 제거
Cars.columns = Cars.columns.str.replace(".","")
model = smf.ols(formula ="Price ~ EngineSize + RPM + Weight+ Length + MPGcity + MPGhighway", data = Cars)
result = model.fit()
result.summary()
- 검정 결과 p-value < 0.05임으로 모델은 유의함
- Adj R-square가 0.542로 낮은 수치
Cars[['EngineSize','RPM', 'Weight','Length','MPGcity','MPGhighway']].corr()
- 다중 공선성을 파악하기 위한 상관관계 분석
- MPGcity와 MPGhighway 중 어느것을 제거해야할지 확인
from patsy import dmatrices
from statsmodels.stats.outliers_influence import variance_inflation_factor
# 독립변수와 종속변수를 데이터프레임으로 나누어 저장하는 함수
y,X = dmatrices("Price ~ EngineSize + RPM + Weight+ Length + MPGcity + MPGhighway",
data = Cars,return_type ="dataframe")
# 독립변수끼리의 VIF 값을 계산하여 데이터프레임으로 만드는 과정
vif_list = []
for i in range(1,len(X.columns)):
vif_list.append([variance_inflation_factor(X.values,i), X.columns[i]])
pd.DataFrame(vif_list,columns=['vif','variable'])
- VIF 결과 MPGcity < MPGhighway 이므로 MPGcity 제거
model = smf.ols(formula ="Price ~ EngineSize + RPM + Weight + MPGhighway", data = Cars)
result = model.fit()
result.summary()
- 공선성을 제거하였음에도 AdjR-square 값이 변화 없음
- 무분별한 변수 사용이 문제
- MPGcity를 제거했을때, MPGhighway의 p-value가 낮아짐
- 유의한 변수임에도 다중 공선성으로 유의하지 않게 표현될 수 있음
import time
import itertools
import pandas as pd
import statsmodels.api as sm
def processSubset(X, y, feature_set):
model = sm.OLS(y, X[list(feature_set)]) # Modeling
regr = model.fit() # 모델 학습
AIC = regr.aic # 모델의 AIC
return {"model": regr, "AIC": AIC}
# 전진선택법
def forward(X, y, predictors):
# 데이터 변수들이 미리 정의된 predictors에 있는지 없는지 확인 및 분류
remaining_predictors = [p for p in X.columns.difference(['Intercept']) if p not in predictors]
results = []
for p in remaining_predictors:
results.append(processSubset(X=X, y=y, feature_set=predictors + [p] + ['Intercept']))
# 데이터프레임으로 변환
models = pd.DataFrame(results)
# AIC가 가장 낮은 것을 선택
best_model = models.loc[models['AIC'].argmin()] # index
print("Processed ", models.shape[0], "models on", len(predictors) + 1, "predictors in")
print('Selected predictors:', best_model['model'].model.exog_names, ' AIC:', best_model[0])
return best_model
# 후진소거법
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) + ['Intercept']))
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 Stepwise_model(X, y):
Stepmodels = pd.DataFrame(columns=["AIC", "model"])
tic = time.time()
predictors = []
Smodel_before = processSubset(X, y, predictors + ['Intercept'])['AIC']
for i in range(1, len(X.columns.difference(['Intercept'])) + 1):
Forward_result = forward(X=X, y=y, predictors=predictors)
print('forward')
Stepmodels.loc[i] = Forward_result
predictors = Stepmodels.loc[i]["model"].model.exog_names
predictors = [k for k in predictors if k != 'Intercept']
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 if k != 'Intercept']
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 = Stepwise_model(X=X, y=y)
Stepwise_best_model.summary()
📍 해석
단계적 선택법을 통해 다중 선형 회귀 모델을 채택하였고, Adj R-square 값이 0.547로 모델이 전체 데이터의 54.7%를 설명할 수 있다. 설명력이 높은 모델은 아니므로 추가적인 변수를 찾아 데이터를 보완해야 할 필요성이 있다. (회귀 계수와 p-value를 통해 영향력 체크)
📍 AIC vs p-value
- 실무에선 AIC도 중요하지만 분석가가 판단하여 모델을 선정
- p-value가 높더라도 포함된 모델을 선택할 수 있음
댓글남기기