본문 바로가기
데이터 분석/데이터 분석

[회귀 분석] 2. 잔차도(Residual plot)와 QQ plot 그리기

by 부자 꽁냥이 2020. 9. 18.

안녕하세요~~ 꽁냥이에요!!

 

잔차도는 선형 회귀 모형의 적합성을 확인해보기 위한 그래프입니다. 또한 잔차의 절댓값(또는 제곱)과 설명변수의 그래프를 통하여 오차의 등분산성이 적합한지 1차적으로 확인할 수 있지요.

 

그리고 QQ plot은 선형 모형의 정규성 가정을 시각적으로 테스트하는데 활용됩니다.

 

따라서 이번 포스팅에서는 잔차도와 QQ plot을 그려보는 방법에 대해서 알아보겠습니다.

 

1. 잔차도

2. QQ-Plot


   1. 잔차도

먼저 이번 포스팅에서 사용할 데이터를 다운 받아주세요.

 

toluca_company_dataset.csv
0.00MB

 

이번 포스팅에서 필요한 모듈을 임포트하고 데이터를 불러볼게요.

 

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['axes.unicode_minus'] = False ## 마이나스 '-' 표시 제대로 출력
import pandas as pd

from scipy.stats import norm
from statsmodels.formula.api import ols

df = pd.read_csv('./toluca_company_dataset.csv') ## 데이터

 

 

먼저 Work_hours를 반응 변수로, Lot_size를 설명 변수로 하는 단순 선형 회귀 모형을 적합합니다. 모형 적합에 대한 설명은 여기를 참고하세요.

 

## 선형 모형 적합
fit = ols('Work_hours ~ Lot_size',data=df).fit()

 

이제 잔차도를 그려볼게요.

 

sqrt_mse = np.sqrt(fit.mse_resid) ## square root of mse
std_res = fit.resid/sqrt_mse ## studentized residual

## 잔차도 x축 Lot_size
fig = plt.figure(figsize=(8,8))
fig.set_facecolor('white')

font_size = 15

plt.scatter(df['Lot_size'],std_res) ## 잔차도 출력

plt.xlabel('Lot Size', fontsize=font_size)
plt.ylabel('Residual', fontsize=font_size)
plt.show()

 

line 1~2

잔차도를 그릴 때 기존 잔차 값에서 잔차 제곱 합의 제곱근을 나누어 줍니다. 

 

위 코드를 실행하면 아래와 같은 잔차도를 얻게 됩니다.

 

 

그림을 보니 Lot Size와 잔차 사이의 특별한 패턴은 보이지 않아요. 따라서 선형 모형이 적합한 것 같다고 1차적으로 판단을 내릴 수 있지요.

 

다음은 오차의 등분산성을 확인하기 위한 그림을 그려보겠습니다. Lot Size를 x축으로 하고 잔차의 절댓값을 y축으로 하는 산포도를 그릴 거예요.

 

## 잔차의 절대값 vs Lot_size
sqrt_mse = np.sqrt(fit.mse_resid) ## square root of mse
std_res = fit.resid/sqrt_mse ## studentized residual
abs_res = np.abs(std_res) ## absolute value

fig = plt.figure(figsize=(8,8))
fig.set_facecolor('white')

font_size = 15

plt.scatter(df['Lot_size'],abs_res) ## 잔차도 출력

plt.xlabel('Lot Size', fontsize=font_size)
plt.ylabel('Absolute Value of Residual', fontsize=font_size)
plt.show()

 

위 코드를 실행하면 아래와 같은 그림이 나올 거예요.

 

 

Lot Size에 따른 잔차의 절대값이 특별한 패턴을 보이지 않는 것 같아요. 따라서 1차적으로 오차의 분산은 Lot Size에 영향을 받지 않으며 이는 오차의 등분산성 가정을 위배하지 않는다고 판단할 수 있어요.

반응형

   2. QQ plot

이번에는 QQ plot을 그려볼게요. QQ plot을 그리기 위해서는 잔차값과, 잔차를 오름차순으로 나열 했을 때의 순위 그리고 정규분포 가정하에서 잔차의 이론값이 필요합니다.

 

여기서 잔차의 이론 값은 아래와 같이 구합니다.

 

$$\sqrt{MSE}\times z((k-0.375)/(n+0.25)) $$

 

여기서 $MSE$는 잔차제곱합 평균, $k$는 잔차의 순위, $n$은 데이터의 개수 그리고 $z(p)$는 정규분포에서 $p$ 분위수를 의미합니다. QQ plot에 대해서 더 자세한 설명은 여기를 참고하세요.

 

이제 잔차의 이론 값을 x축에 그리고 잔차 값을 y축에 그리면되지요. 이것이 QQ plot입니다. 

 

## qq plot
sqrt_mse = np.sqrt(fit.mse_resid) ## square root of mse

num_const = 0.375 ## 백분위 분자 수정 계수
denom_const = 0.25 ## 백분위 분모 수정계수

## 오름차순으로 정렬했을 때 잔차의 순위
rank = [sorted(fit.resid).index(x)+1 for x in fit.resid] ## 인덱스가 0부터 시작하므로 1을 더한다.

expected_value = [] ## 이론적 잔차값
for i in range(len(fit.resid)):
    p = (rank[i]-num_const)/(len(fit.resid)+denom_const) ## 백분위
    expected_value.append(sqrt_mse*norm.ppf(p))

fig = plt.figure(figsize=(8,8))
fig.set_facecolor('white')

font_size = 15

plt.scatter(expected_value,fit.resid) ## 잔차도 출력
plt.plot(expected_value,expected_value,color='red')
plt.xlabel('Expected', fontsize=font_size)
plt.ylabel('Residual', fontsize=font_size)
plt.show()

 

위 코드를 실행해보면 아래와 같은 그림이 나올 거예요.

 

 

QQ plot을 그려본 결과 일직선 형태로 나오는 것을 보니 정규성 가정에도 위배되지 않는다고 1차적으로 판단할 수 있어요. QQ plot은 scipy에서 제공하는 probplot을 이용하여 그릴 수 있습니다.

 

from scipy.stats import probplot

fig = plt.figure(figsize=(8,8))
fig.set_facecolor('white')

ax = fig.add_subplot()
probplot(fit.resid, dist='norm',plot=ax) ## qq plot 출력
plt.show()

 

probplot에 대한 설명은 여기를 참고하세요. 위 코드를 실행하면 아래와 같이 QQ plot이 그려집니다.

 

 

앞서 본 QQ plot과 다른점은 x 축에 단위가 다릅니다. 왜냐하면 앞에서 본 것은 평균은 0, 분산은 잔차의 분산 추정값을 따르는 정규분포의 이론적 분위수를 사용했고 probplot은 표준정규분포에서의 이론적 분위수를 사용하기 때문입니다. 하지만 직선에 가깝다는 결론은 동일하므로 오차의 정규성을 만족한다고 볼 수 있어요.


댓글


맨 위로