for textmining

베이지안 추론(2)

|

이 글에서는 베이지안 추론에 대해 살펴보도록 하겠습니다. 이 글은 ‘Think Bayes(앨런 B. 다우니 지음, 권정민 옮김, 한빛미디어 펴냄)’를 정리했음을 먼저 밝힙니다. 그럼 시작하겠습니다.

기관차 문제

모든 기차의 기관차엔 1부터 $N$까지 일련번호가 붙어 있습니다. 어느 날 60호 기관차를 봤다고 칩시다. 이 때 이 회사가 운영하고 있는 기관차는 총 몇 개일까요? 즉 $N$이 몇인지 추정하는 것이 문제가 되겠습니다. 베이지안 추론법에 따르면 이런 문제는 두 단계로 해결합니다.

(1) 사전확률 : 데이터를 보기 전에 $N$에 대해 알고 있는 것이 무엇인가?

(2) 우도 : $N$이 특정한 값을 가질 때 관측한 데이터(60호 객차)가 발생할 확률은?

동일 사전확률 가정

사전확률과 관련해 근거는 부족하지만 간단한 가정을 해보겠습니다. 철도를 운영하는 회사는 단 하나이고, 이 회사가 운영 중인 기관차는 일단 1000개라고 칩시다. 또 $N$은 1~1000 사이의 어떤 값이든 동일한 확률로 선택될 수 있다고 보는 겁니다.

이 가정 하에서 우도를 구해봅시다. 이 회사가 운영하고 있는 기관차가 59개 이하라면 60호 기관차를 절대 관측할 수 없습니다. 따라서 $N$이 1~59일 때 우도는 0입니다.

운영 중인 기관차 수가 60개라면 60호 기관차를 관측할 확률은 1/60이 됩니다. 마찬가지로 총 기관차 수가 61개라면 우도는 1/61, 62개라면 1/62… 이런 식으로 우도를 구할 수 있게 됩니다.

베이즈 규칙에 따르면 사후확률(60호 기관차를 관측했을 때 운영 중인 기관차 수 $N$이 나타날 확률)은 사전확률에 우도를 곱해 풀 수 있습니다. 사전확률은 동일하다고 가정했기 때문에 제일 큰 값을 갖는 우도가 전제하는 $N$이 우리의 추정 결과가 될 것입니다.

이 경우 우리는 $N$을 60으로 추정할 수밖에 없게 됩니다. 운영 중인 기관차가 60개일 때 우도가 가장 큰 값을 갖게 되거든요. 그런데 이런 추정은 상식에는 반하는 결과입니다.

다시 말해 60호 기관차를 관측했다고 해서 이 회사가 운영 중인 기관차 수가 60개라고 추정하는 건 너무 단순한 추론이라는 것이지요. 만약 35호 기관차를 관측했다면 같은 방식으로 베이지안 추론을 해보면 총 기관차 수가 35개라는 예측이 나오게 될 겁니다.

이 가정에 따른 결과 표는 다음과 같습니다. 아래 표에서 사후확률은 사전확률에 우도를 곱한 뒤 사후확률 전체 합이 1이 되도록 나누어준 값입니다.

$N$ 사전확률 우도 사후확률
1 1/1000 0 0
 
59 1/1000 0 0
60 1/1000 1/60 0.0059
 
1000 1/1000 1/1000 0.00035

사후확률의 평균은 $N$에 사후확률을 곱한 뒤 모두 더해주면 됩니다. 그 값은 333.065557입니다.

가정 보완하기

동일 사전확률 가정이 불완전함을 확인했습니다. 이를 보완할 수 있는 방법은 두 가지가 있습니다. (1)이 사전확률, (2)가 우도 쪽을 보완하는 접근기법이 되겠습니다.

(1) 배경지식을 더 확보

(2) 데이터를 더 확보

사전확률의 대안

(1)과 관련해 기관차를 1000대나 운영하고 있는 회사가 있고, $N$이 1~1000 사이에 선택될 확률이 동일하다고 전제하는 건 비현실적입니다. 회사의 규모는 현실적으로는 이보다 규모가 훨씬 작을 겁니다. 바꿔 말해 $N$이 1000이 될 확률은 $N$이 1이 될 가능성보다 훨씬 작을 것이라 가정하는 것이 합리적입니다.

이와 관련해 로버트 액스텔이라는 학자는 회사 규모의 분포는 멱법칙을 따른다는 사실을 밝혀냈습니다. 이 법칙에 따르면 기관차가 10대 미만인 회사가 1000개일 때, 100대의 기관차를 소유한 회사는 100개, 1000대의 기관차를 운영 중인 회사는 10개, 1만대 기관차를 소유한 회사는 1개입니다.

다시 말해 운영 중인 기관차의 총 개수 $N$이 커질수록 $N$이 선택될 확률, 즉 사전확률이 점차 작아진다는 이야기입니다. 그럼 사전확률을 다시 구해보겠습니다.

우선 $N$의 역수를 취합니다.

$N$ 역수
1 1
2 0.5
3 0.33
4 0.25
5 0.2
총합 7.48547

이렇게 구한 역수를 역수의 총합(7.48547)으로 나눠준 것이 각 $N$의 사전확률이 되겠습니다. 다음과 같습니다.

$N$ 사전확률
1 0.13359213049244018
2 0.06679606524622009
3 0.044530710164146725
4 0.033398032623110044
5 0.026718426098488037
996 0.0001341286450727311
997 0.00013399411283093298
998 0.00013385985019282582
999 0.00013372585634878898
1000 0.00013359213049244018

관측치 늘리기

동일 사전확률 가정 하에서 60호 기관차 하나만 관측한 뒤에 사후확률의 평균을 구하면 다음과 같습니다.

상한선 사후확률 평균
500 207
1000 333
2000 552

우리는 60호 기관차만 보고 결론을 내린 셈인데요. 데이터를 하나만 보고 결론을 내리는건 너무 성급한 일입니다. 60호 기관차에 이어 30번과 90번 기관차도 봤다고 가정해 보겠습니다. 이 데이터를 사용했을 때 사후확률 평균은 다음과 같습니다.

상한선 사후확률 평균
500 152
1000 164
2000 171

그 차이가 확실히 줄어들어 수렴하는 경향을 보임을 알 수 있습니다.

마지막으로 보완한 사전확률을 토대로 30번, 60번, 90번 기관차를 관측한 뒤의 사후확률 평균을 보겠습니다.

상한선 사후확률 평균
500 131
1000 133
2000 134

상한선이 어떻든 간에 상관없이 사후확률 평균은 134에 수렴한다고 합니다.

파이썬 코드

마지막 사후확률 표를 생성하는 데 쓴 파이썬 코드는 다음과 같습니다. thinkbayes.py는 이곳에서 내려받을 수 있습니다.

import thinkbayes as tb

class Train(tb.Suite):
    """Represents hypotheses about 
    how many trains the company has."""

    def __init__(self, hypos, alpha=1.0):
        """Initializes the hypotheses 
        with a power law distribution.

        hypos: sequence of hypotheses
        alpha: parameter of the power law prior
        """
        tb.Pmf.__init__(self)
        for hypo in hypos:
            self.Set(hypo, hypo ** (-alpha))
        self.Normalize()

    def Likelihood(self, data, hypo):
        """Computes the likelihood of the data 
        under the hypothesis.
        """
        if hypo < data:
            return 0
        else:
            return 1.0 / hypo

def Mean(suite):
    total = 0
    for hypo, prob in suite.Items():
        total += hypo * prob
    return total

def MakePosterior(high, dataset):
    hypos = xrange(1, high+1)
    suite = Train(hypos)
    suite.name = str(high)

    for data in dataset:
        suite.Update(data)

    return suite

dataset = [30, 60, 90]
for high in [500, 1000, 2000]:
    suite = MakePosterior(high, dataset)
    print high, suite.Mean()

Comments