#think-bayes #probability #study


이 장에서는 인구 수를 세거나 인구의 크기를 추정하는 것과 관련된 문제를 다룬다. 다시 말하지만, 일부 예제는 우스꽝스러워 보일 수 있지만 독일 탱크 문제와 같은 일부 예제는 때로는 삶과 죽음의 상황에서 실제 적용이 가능하다.

The Train Problem

"철도는 기관차에 1...N 순서로 번호를 매깁니다. 어느 날 번호가 60인 기관차를 보게 됩니다. 철도에 몇 대의 기관차가 있는지 추정하세요. (goal: N)"

prior 을 선택할 근거가 많지 않으므로 간단한 것부터 시작한 다음 대안을 고려해본다. N 이 1에서 1000 사이의 모든 값일 가능성이 똑같다고 가정해보자.

사전 분포는 다음과 같다.

import numpy as np
from empiricaldist import Pmf

hypos = np.arange(1, 1001)
prior = Pmf(1, hypos)

이제 likelihood 을 알아보자. 𝑁 기관차로 구성된 차량에서 60번 기관차를 볼 확률은 얼마인가? 모든 기관차를 볼 확률이 똑같다고 가정하면 특정 기관차를 볼 확률은 1/𝑁 이다.

다음은 업데이트를 수행하는 함수이다.

def update_train(pmf, data):
    """Update pmf based on new data."""
    hypos = pmf.qs
    likelihood = 1 / hypos
    impossible = (data > hypos)
    likelihood[impossible] = 0
    pmf *= likelihood
    pmf.normalize()

이 함수는 이전 장의 주사위 문제의 업데이트 함수와 동일하다. likelihood 관점에서 주사위 문제와 비슷하다.

업데이트 해보자

data = 60
posterior = prior.copy()
update_train(posterior, data)


당연히 60 미만의 𝑁 값은 모두 제거된다. 가장 높은 pmf 값은 60 이다.

>>> posterior.max_prob()
60

가장 높은 숫자를 가진 열차를 우연히 봤을 확률이 얼마나 될까? 그럼에도 확률을 최대화하려면 60 을 맞혀야 한다.

다른 대안으로 사후 분포의 평균을 계산하는 방법이 있다. 가능한 수량 집합 𝑞𝑖 와 그 확률 𝑝𝑖 이 주어지면 분포의 평균은 다음과 같습니다.

mean=ipiqi
>>> np.sum(posterior.ps * posterior.qs)
333.41989326370776
>>> posterior.mean()
333.41989326370776

즉, 333대 열차가 있을것으로 기대할 수 있다.
사후 평균을 추정치로 사용하면 장기적으로 평균 제곱 오차(MSE, mean squared error)를 최소화할 수 있다.

Sensitivity to the Prior

이전 섹션에서 사용한 사전은 1에서 1000까지 균일하지만, 균일 분포 또는 특정 상한을 선택하는 것에 대한 정당성을 제시하지 않았다. 사후분포가 선행 분포에 민감한지 궁금할 수 있다. 데이터가 너무 적고 관측값이 하나뿐인 경우라면 그렇다.

import pandas as pd

df = pd.DataFrame(columns=['Posterior mean'])
df.index.name = 'Upper bound'

for high in [500, 1000, 2000]:
    hypos = np.arange(1, high+1)
    pmf = Pmf(1, hypos)
    update_train(pmf, data=60)
    df.loc[high] = pmf.mean()
    
df

상한(upper bound)을 변경하면 사후 평균이 크게 달라지는데 이는 좋지 않다. 사후가 사전에 민감한 경우 두 가지 방법으로 진행할 수 있다.

데이터가 많을수록 prior 에 기반한 posterior 분포가 수렴하는 경향이 있다. 예를 들어 열차 60 외 30과 90번 열차가 있다고 가정해보자. 사후확률은 다음과 같이 계산할 수 있다.

p(D|H60)p(D|H30)p(D|H90)
df = pd.DataFrame(columns=['Posterior mean'])
df.index.name = 'Upper bound'

dataset = [30, 60, 90]

for high in [500, 1000, 2000]:
    hypos = np.arange(1, high+1)
    pmf = Pmf(1, hypos)
    for data in dataset:
        update_train(pmf, data)
    df.loc[high] = pmf.mean()
    
df

상한에 따라 차이는 더 줄었다. 분명히 세 개의 열차로는 posterior 에 수렴하기 충분하지 않다.

Power Law Prior

더 많은 데이터를 사용할 수 없는 경우 다른 옵션은 더 많은 배경 정보를 수집하여 prior 을 개선하는 것이다. 기관차가 1000대인 기차 운영회사와 1대만 있는 회사가 같은 확률이라고 가정하는 것은 합리적이지 않다.

이 법칙에 따르면 기관차가 10개 미만인 회사가 1000개라면 기관차가 100개인 회사는 100개, 1000개인 회사는 10개, 1만 개의 기관차를 보유한 회사는 1개가 있을 수 있다.

수학적으로 power law 는 주어진 규모인 𝑁를 가진 회사의 수가 (1/N)α에 비례한다는 것을 의미하며, 여기서 𝛼 는 1에 가까운 수다.

PMF(x)(1x)α

이와 같은 식으로 앞서 power law prior 를 구성해보자.

alpha = 1.0
ps = hypos**(-alpha)
power = Pmf(ps, hypos, name='power law')
power.normalize()

비교를 위해 사전분포(uniform)은 다음과 같다.

hypos = np.arange(1, 1001)
uniform = Pmf(1, hypos, name='uniform')
uniform.normalize()


power law 는 높은 값에 대한 사전 확률을 낮추기 때문에 사후 평균과 상한의 민감도가 낮아졌다.

power law prior 을 사용하여 세 개의 열차를 관찰할 때 사후 평균이 상한(upper bound)에 따라 어떻게 달라지는지 살펴보자.

df = pd.DataFrame(columns=['Posterior mean'])
df.index.name = 'Upper bound'

alpha = 1.0
dataset = [30, 60, 90]

for high in [500, 1000, 2000]:
    hypos = np.arange(1, high+1)
    ps = hypos**(-alpha)
    power = Pmf(ps, hypos)
    for data in dataset:
        update_train(power, data)
    df.loc[high] = power.mean()
    
df

이제 그 차이가 훨씬 작아졌다. 실제로 상한을 위 숫자보다 크게 설정해도 평균은 134에 수렴한다.

Credible Intervals

지금까지 사후 분포를 요약하는 두 가지 방법, 즉 사후 확률이 가장 높은 값(MAP)과 사후 평균(posterior mean)을 살펴봤다. 이 두 가지 모두 점 추정(point estimates), 즉 우리가 관심 있는 수량을 추정하는 단일 값이다.

사후 분포를 요약하는 또 다른 방법은 백분위수를 사용하는 것이다. 표준화 시험(like 수능)을 치른 적이 있다면 백분위수에 익숙할 것이다. 예를 들어, 백분위수가 90이라면 시험을 본 사람의 90%와 비슷하거나 그보다 더 잘했다는 의미다.

x라는 값이 주어지면 x보다 작거나 같은 모든 값을 찾아서 확률을 더하면 백분위수 순위를 계산할 수 있다.

Pmf는 이 계산을 수행하는 메서드를 제공한다. 예를 들어, 회사의 열차 수가 100대 미만일 확률을 계산할 수 있습니다.

>>> power.prob_le(100)
0.2937469222495771

앞서 power law 와 3개 열차 데이터 집합(30, 60, 90)을 사용하면 약 29% 이다. 따라서 100개의 열차는 29번째 백분위수다.

반대로 특정 백분위수를 계산하고 싶다고 하자. 예를 들어 분포의 중앙값이 50번째 백분위수라고 가정한다. 총합이 0.5를 초과할 때까지 확률을 더하여 계산할 수 있다.

def quantile(pmf, prob):
    """Compute a quantile with the given prob."""
    total = 0
    for q, p in pmf.items():
        total += p
        if total >= prob:
            return q
    return np.nan

50 백분위수를 구하는 방법은 다음과 같다.

>>> quantile(power, 0.5)
113

113개 열차가 posterior 분포의 중앙값이다. Pmf는 동일한 작업을 수행하는 사분위수라는 메서드를 제공한다. 다음과 같이 호출하여 5 & 95번째 백분위수를 계산하면 다음과 같다.

>>> power.quantile([0.05, 0.95])
array([ 91., 243.])

또한 Pmf 는 주어진 확률을 포함하는 간격(interval)을 계산하는 credible_interval을 제공한다.

>>> power.credible_interval(0.9)
array([ 91., 243.])

The German Tank Problem

제2차 세계대전 중 런던 주재 미국 대사관 경제전과는 통계 분석을 통해 독일의 탱크 및 기타 장비 생산량을 추정했다.

서방 연합군은 개별 탱크의 섀시 및 엔진 일련 번호가 포함된 일지, 재고, 수리 기록을 확보했다.

이 기록을 분석한 결과 일련번호는 제조업체와 전차 유형별로 100개씩 블록으로 할당되었고, 각 블록의 번호는 순차적으로 사용되었으며, 각 블록의 모든 번호가 사용된 것은 아니라는 사실을 발견했다. 따라서 독일 전차 생산량을 추정하는 문제는 100개의 번호 블록 내에서 위에 풀어본 기차 문제의 형태로 바라볼 수 있었다.

이를 바탕으로 미국과 영국의 분석가들은 다른 형태의 정보에 의한 추정치보다 훨씬 낮은 추정치를 산출했다. 그리고 전쟁이 끝난 후, 이 추정치가 훨씬 더 정확했다는 기록이 나왔습니다.

이들은 타이어, 트럭, 로켓 및 기타 장비에 대해서도 유사한 분석을 수행하여 정확하고 실행 가능한 경제 정보를 산출해냈다.

독일 탱크 문제는 역사적으로도 흥미롭지만, 통계적 추정을 실제로 적용한 좋은 예이기도 합니다.

이 문제에 대한 자세한 내용은 위키백과 페이지와 러글스와 브로디, "제2차 세계대전의 경제 정보에 대한 경험적 접근"를 참조하길 바란다.

Informative Priors

베이지안들 사이에서는 사전 분포를 선택하는 데 두 가지 접근 방식이 있다.

정보가 없는 prior 정보는 더 객관적으로 보이기 때문에 매력적이다. 하지만 저자는 일반적으로 infomrative prior 를 선호한다. 왜? 첫째, 베이지안 분석은 항상 모델링을 기반으로 한다. prior 을 선택하는 것은 이러한 결정 중 하나이지만 유일한 결정은 아니며 가장 주관적일 수도 있다. 따라서 정보가 없는 prior 이 더 객관적이라 하더라도 전체 분석은 여전히 주관적일 수 있다.

또한 대부분의 실제 문제에서는 데이터가 많거나 많지 않은 두 가지 상황 중 하나에 처할 가능성이 높다. 데이터가 많은 경우, informative 나 uninformative 나 동일한 결과를 내므로 prior 선택은 중요하지 않다. 데이터가 많지 않은 경우 관련 배경 정보(예: power law distribution)를 이용하면 차이를 분명히 알 수 있다.

그리고 독일 탱크 문제에서처럼 결과에 따라 생사를 결정해야 하는 상황이라면, 적게 아는 척하면서 객관성이라는 환상을 유지하기보다는 모든 정보를 최대한 활용해야 한다.

Summary

이 장에서는 주사위 문제와 같은 확률 함수를 가지고 있으며 독일 탱크 문제에 적용할 수 있는 기차 문제를 소개했다. 예제의 목표는 개체 수(estimate a count) 또는 모집단의 크기를 추정한다.