2022/01/16/SUN
qqplot
- qqplot은
분위수대조도로 불리는 정규모집단 가정을 하는 방법 중 하나이다.- 수집 데이터를 표준정규분포의 분위수와 비교하여 그리는 그래프로 데이터의 정규성 가정에 대한 검토를 가능하게 한다.
- 모집단이 정규성을 따른다면 직선의 형태로 그려지게 된다.
- qqplot은 표준정규분포의 분위수와 이에 대응하는 분포(측정한 실제 데이터의 분포)의 분위수를 x,y 좌표평면에 plotting 하는 방법이다.
- x축, y축 및 (대략) 예상 분위수에 따라 정렬된 샘플 값을 살펴볼 때, 그림의 일부 섹션에 있는 값이 이론적인 분포에서 가정하는 것보다 더 집중되어 있는지 아니면 덜 집중되어 있는지를 확인할 수 있다.
- 정규 분포와 마찬가지로 t 분포의 모양도 매끄럽다.
- 정규 분포와 마찬가지로 t 분포도 대칭형이다.
- 표준 정규 분포(또는 z 분포)와 마찬가지로 t 분포의 평균도 0이다.
- 정규 분포에서는 모집단 표준편차를 알고 있다고 가정하지만 t 분포에서는 이러한 가정을 내리지 않는다.
- t 분포는 자유도에 의해 정의된다. 자유도는 표본 크기와 관련이 있다.
- 자유도가 높은 곡선은 더 높이 올라가고 꼬리가 얇습니다
- t 분포는 모집단 표준편차를 알 수 없거나 두 가지 모두 적용될 때 작은 표본 크기에 가장 유용하다.
- 표본 크기가 커질수록 t 분포가 정규 분포와 비슷해진다.
- 표본 표준편차를 근거로 한다.
- z분포 더 두꺼운 꼬리를 갖는다.
- 자유도가 클수록 곡선이 z 분포에 더 근접
- 일반적으로 표본크기가 30이상인 경우 t분포 대신 z분포를 사용할 수 있다. 예를 들어 자유도가 30정도이면 t분포는 z분포와 매우 유사.
- 표본 평균을 이용해 정규 분포의 평균을 해석할 때 주로 사용
- qqplot은 두 변수간의 분포를 비교하기 위해 사용되는 그래프이다. 일반적으로 주어진 데이터와 정규분포를 비교하여 정규분포 가정이 적정한지에 대해 검토하는 데 널리 사용된다. 하지만 정규분포에 국한할 필요없이 두 분포의 비교에 활용할 수 있다.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from scipy import stats
np.random.seed(990310)
x=np.random.normal(size=1000,loc=2,scale=1.5)
y=stats.t.rvs(df=10,size=1000)/np.sqrt(10/8)*1.5 + 2
- 우리가 관측한 $x_1,\dots,x_{1000}$이 $N(2,1.5^2)$에서 나온 샘플인지 알아보고 싶다고 해보자
(1) 관측한 값을 순서대로 나열하여 $x_{(1)},x_{(2)}, \dots, x_{(1000)}$을 만든다.
x[:2]
- $x_1=0.2315625,\quad x_2=2.28762212$
x.sort()
- 오름차순으로 정렬中, 내림차순은 reverse=True입력
x[:2]
- $x_{(1)}= -2.57649273,\quad x_{(2)}=-2.52319957$
(2) 파이썬이나 R로 $N(2,1.5^2)$에서 1000개의 정규분포를 생성. 그리고 순서대로 나열하여 $\tilde{x}_{(1)},\tilde{x}_{(2)}, \dots, \tilde{x}_{(1000)}$를 만든다.
(3) $x_{(1)}\approx \tilde{x}_{(1)}, \dots , x_{(1000)}\approx \tilde{x}_{(1000)}$ 이면 x는 정규분포일것
- 그런데 $\tilde{x}_{(1)},\tilde{x}_{(2)}, \dots, \tilde{x}_{(1000)}$은 시뮬레이션을 할때마다 다른값이 나올테니까 불안정한 느낌이 든다. $\to$ 이론적인 값을 계산하자.
xx는 표준정규분포
xx = (x-np.mean(x)) / np.std(x,ddof=1) # ddof = 모표준편차
xx[:2]
- 실제우리가 관측한값
print(stats.norm.ppf(0.001))
print(stats.norm.ppf(0.002))
- 이론적인 값
- 분위수
m=[i/1000 for i in np.arange(1000)+1]
q=[]
for i in range(len(m)):
q=q+[stats.norm.ppf(m[i])]
q[:2]
- $xx \approx q$ 을 확인하기 위해서 $(q,q)$그래프와 $(q,xx)$의 그래프를 그려서 겹쳐보자.
plt.plot(q,xx,'o')
plt.plot(q,q,'-')
- 해석: 점들이 주황색선 근처에 모여있을수록 정규분포에 가깝다.
- 결국은 "정규분포 sample에서 나온 게 맞는 것 같다"라는 결론
- 아래와 같이 쉽게 그릴수도 있다. (우리가 그린그림과 조금 다르게 보인다)
- stats.probplot 함수를 통해서 주어진 데이터와 정규분포(다른 분포도 가능)와의 qqplot을 그릴 수 있다.
_ = stats.probplot(x,plot=plt)
- 자세히보면 조금 다르게 그려지긴 하는데 이는 $m=(\frac{1}{1000},\dots,\frac{999}{1000},\frac{1000}{1000})$와 같이 계산하지 않고 약간 보정한값을 계산하기 때문임
- stats.probplot? 을 통하여 확인한 결과 아래와 같은 코드로 구현됨
### 보정하는방법1 n=len(xx) m=[((i+1)-0.3175)/(n+0.365) for i in range(n)] m[-n]=0.5**(1/n) m[0]=1-m[-n]
- 프로그램에 따라서 아래와 같이 보정하는 경우도 있음
### 보정하는방법2 m=[(i-3/8)/(n+1/4) for i in np.arange(1000)+1]
- 또 자세히보면 stats.probplot은 y축에 표준화 전의 x값이 있음을 알 수 있음.
- 정규분포와 t분포의 qqplot을 그려서 비교해보자.
- 정규분포
_ = stats.probplot(x,plot=plt)
- t분포: 푸른점들이 대체로 붉은선위에 놓여있는듯 하지만 양끝단에서는 그렇지 않다. (중앙부근은 정규분포와 비슷하지만, 꼬리부분은 정규분포와 확실히 다르다)
- 왼쪽꼬리: 이론적으로 나와야 할 값보다 더 작은값이 실제로 관측됨
- 오른쪽꼬리: 이론적으로 나와야 할 값보다 더 큰값이 실제로 관측됨
- 해석: 이 분포는 정규분포보다 두꺼운 꼬리를 가진다.
_ = stats.probplot(y,plot=plt) # t분포
fig , (ax1,ax2) = plt.subplots(1,2)
_ = stats.probplot(x,plot=ax1)
_ = stats.probplot(y,plot=ax2)
fig
fig.set_figwidth(8)
fig
ax1.set_title('normal dist')
ax2.set_title('t dist')
fig
- 박스플랏, 히스토그램, qqplot을 그려보자.
fig, ax =plt.subplots(2,3)
ax
(ax1,ax2,ax3), (ax4,ax5,ax6) = ax
sns.boxplot(x,ax=ax1)
sns.histplot(x,kde=True,ax=ax2)
_ = stats.probplot(x,plot=ax3)
sns.boxplot(y,ax=ax4)
sns.histplot(y,kde=True,ax=ax5)
_ = stats.probplot(y,plot=ax6)
fig
fig.set_figwidth(10)
fig.set_figheight(8)
fig.tight_layout()
fig
m = [i/1000 for i in np.arange(1000)+1]
- $m=\big\{\frac{i}{1000}: i \in \{1,2,3,\dots,1000\} \big\}=\big\{\frac{1}{1000},\frac{2}{1000},\dots,\frac{1000}{1000} \big\}$
- 방법1
q=[]
for i in range(len(m)):
q=q+[stats.norm.ppf(m[i])]
q[:5]
- 방법2
q=[stats.norm.ppf(m[i]) for i in range(len(m))]
q[:5]
- 방법3
q=list(map(stats.norm.ppf, m))
q[:5]
- 방법4
stats.norm.ppf(m)[:5]