Think Bayes (9) 두 차원
파이썬을 활용한 베이지안 통계, 앨런 B. 다우니 지음, 권정민 옮김/한빛미디어 |
9.1 페인트볼 게임
30피트 폭에 50피트 길이의 실내 경기장에서 페인트볼 게임을 하고 있다고 가정하자. 당신은 30피트의 벽 앞에 서 있고, 근처에 숨어 있는 상대편을 찾고 있다. 벽을 따라서 같은 색의 페인트 자국이 여러 개 나 있어서, 상대편이 여기서 방금 총을 발사했다고 생각된다.
페인트 자국은 실내 경기장의 왼쪽 아래 구석에서 15, 16, 18, 21피트 거리에 나 있다. 상대편이 어디쯤 숨어 있을까?
실내 경기장의 왼쪽 아래 구석을 원점으로 하여 어떤 위치 $(\alpha, \beta)$에 총을 쏜 사람이 있다고 하고 페인트 자국은 x위치에 나타난다고 하자. 그리고 이 x와 상대방이 있는 위치가 이루는 각도를 $\theta$라고 하자.
코드는 http://thinkbayes.com/paintball.py 에서 받을 수 있다.
9.2 스윗
가설을 나타내는 스윗을 생각해보자. 각 가설은 좌표 $(\alpha, \beta)$ 쌍이다.
1 2 3 4 5 6 |
class Paintball(thinkbayes.Suite, thinkbayes.Joint): def __init__(self, alphas, betas, locations): self.locations = locations pairs = [(alpha, beta) for alpha in alphas for beta in betas] thinkbayes.Suite.__init__(self, pairs) |
실내 경기장은 폭이 30피트에 길이 50피트이므로 다음과 같이 스윗을 만든다.
1 2 3 4 5 |
alphas = range(0, 31) betas = range(1, 51) locations = range(0, 31) suite = Paintball(alphas, betas, locations) |
9.3 삼각법
이제 주어진 상대방의 위치에 대해 벽에 어떤 식의 자국을 남길 수 있는지에 대한 우도 함수를 정의하여보자.
간단한 모델로, 상대방이 어떤 방향이든 쏠 수 있다고 가정하면, 상대방은 alpha 위치의 벽을 맞출 경우가 많고, 떨어진 벽은 맞출 가능성이 적다.
상대방이 $\theta$의 각도로 총을 쏘았다고 한다면, 삼각함수를 사용하여 벽을 따라 난 자국의 확률을 계산할 수 있다.
$$x - \alpha = \beta \tan \theta$$
$$\theta = \tan^{-1}(\frac{x-\alpha}{\beta})$$
만약 벽의 위치가 주어진다면 $\theta$를 구할 수 있다.
$\theta$에 대한 첫번째 방정식을 미분하면 다음과 같다.
$$\frac{dx}{d \theta} = \frac{\beta}{cos^2 \theta}$$
이 식은 $\theta$가 증가함에 따라 대상 위치에 대한 속도에 대한 것으로 총격속도(strafing speed)라고 한다. 벽의 주어진 점을 맞출 확률은 총의 속도의 역수에 비례한다.
만약 총을 쏜 사람과 벽의 위치 좌표를 안다면 총격 속도를 계산할 수 있다.
1 2 3 4 5 |
def StrafingSpeed(alpha, beta, x): theta = math.atan2(x- alpha, beta) speed = beta / math.cos(theta)**2 return speed |
alpha
와 beta
는 총을 쏜 사람의 좌표고, x
는 벽에 난 자국의 위치다.
이제 벽의 어떤 위치를 맞출 확률을 나타내는 PMF를 계산할 수 있다.
MakeLocationPmf
는 주어진 위치에서 각 위치를 맞출 확률을 계산한다. 이는 총격 속도에 반비례 하는 값이다.
1 2 3 4 5 6 7 8 |
def MakeLocationPmf(alpha, beta, locations): pmf = thinkbayes.Pmf() for x in locations: prob = 1.0 / StrafingSpeed(alpha, beta, x) pmf.Set(x, prob) pmf.Normalize() |
9.4 우도
우도 함수를 생각해보자. MakeLocationPmf
를 사용해서 상대방 좌표 x
의 값에 대한 우도를 계산해보자.
1 2 3 4 5 6 7 |
def Likelihood(self, data, hypo): alpha, beta = hypo x = data pmf = MakeLocationPmf(alpha, beta, self.locations) like = pmf.Prob(x) return like |
alpha
와 beta
는 저격수 위치에 대한 가설이고, x
는 관측된 페인트 자국의 위치다.
이제 관찰된 값에 대하여 스윗을 갱신하자.
1 2 |
suite.UpdateSet([15, 16, 18, 21]) |
9.5 결합 분포
분포의 각 값이 여러개일 경우, 이는 상태를 나타내는 변수가 2개인 분포를 나타내므로 결합(jointly)이란 단어를 사용해서 결합 분포(joint distribution)이라고 한다.
결합 분포가 주어지면 이를 사용해서 각 변수를 하나만 사용했을 때의 분포를 계산할 수 있다. 이를 주변 분포(marginal distribution)이라고 한다.
thinkbayes.Joint
를 이용해서 주변 분포를 계산할 수 있다.
1 2 3 4 5 6 7 8 |
class Joint: def Marginal(self, i): pmf = Pmf() for vs, prob in self.Items(): pmf.Incr(vs[i], prob) return pmf |
i
는 구하고자 하는 변수의 인덱스로 여기서는 i = 0
를 alpha
, i = 1
일 경우 beta
를 가리킨다. 다음은 사용법이다.
1 2 3 4 5 6 |
marginal_alpha = suite.Marginal(0) marginal_beta = suite.Marginal(1) marginal_alpha.CredibleInterval(50) marginal_beta.CredibleInterval(50) |
9.6 조건 분포
주변 분포는 변수에 대한 정보를 독립적으로 가지고 있지만, 변수 간의 종속성에 대한 정보는 알 수 없다. 이 정보는 조건 분포(conditional distribution)을 계산하여야 한다.
1 2 3 4 5 6 7 8 9 |
class Joint: def Conditional(self, i, j, val): pmf = Pmf() for vs, prob in self.Items(): if vs[j] != val: continue pmf.Incr(vs[i], prob) pmf.Normalize() return pmf |
1 2 3 4 5 |
betas = [10, 20, 40] for beta in betas: cond = suite.Conditional(0, 1, beta) |
변수가 독립적이라면 조건 분포는 항상 동일하다. 하지만 다른 경우 변수가 상호 의존적이라고 볼 수 있다.
9.7 신뢰구간
사후 결합 확률을 시각화 하는 방법으로 신뢰 구간을 계산하는 방법이 있다. 우리가 이용해야 할 성질은, 각 변수에 따라 동일한 신뢰도를 가지는 구간이 별도로 존재한다는 것이다. 따라서 여러 차원을 가질 경우, 신뢰구간 내에 들어갈 수 있는 가능성이 가장 높은 값들을 포함하는 최대 우도 신뢰 구간을 선택하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Joint: def MaxLikeInterval(self, percentage=90): interval = [] total = 0 t = [(prob, val) for val, prob in self.Items()] t.sort(reverse=True) for prob, val in t: interval.append(val) total += prob if total >= percentage/100.0 break |
이 함수는 확률이 큰 순서로 변수가 가지는 상태를 저장한 뒤, 이들을 구간에 더해가면서 50%를 초과할 때 까지 구간의 값을 더한다.
9.8 토의
결합 분포, 주변 분포, 조건 분포에 대해서 알아보았다.
결합 분포가 주어지면 이에 대하여 주변 분포와 조건 분포를 계산할 수 있다. 조건 분포는 최소 근사 형태로 결합 분포를 만들 수 있다.