from scipy.stats import binom
from empiricaldist import Pmf
import numpy as np
def make_binominal(n, p):
= np.arange(n + 1)
ks = binom.pmf(ks, n, p)
ps return Pmf(ps, ks)
비율 추정
확률 통계
유로 동전 문제
import matplotlib.pyplot as plt
'font.family'] = 'Noto Sans KR'
plt.rcParams[
= make_binominal(n=250, p=0.5)
pmf_k ='coin', color='C5')
pmf_k.plot(label'coin toss 이항분포')
plt.title('앞면이 나온 횟수(k)')
plt.xlabel('PMF') plt.ylabel(
Text(0, 0.5, 'PMF')
- 동전을 250번 던져서 앞면의 횟수가 140과 같은 극단적인 값이 나올 확률
140) + pmf_k.prob_le(110) pmf_k.prob_ge(
0.06642115124004333
베이지안 추정
- 동전 앞면의 비율을 균등분포로 가정하고 시작
= np.linspace(0, 1, 101)
hypos = Pmf(1, hypos)
prior = hypos
likelihood_heads = 1 - hypos
likelihood_tails = {
likelihood 'H': likelihood_heads,
'T': likelihood_tails
} prior
probs | |
---|---|
0.00 | 1 |
0.01 | 1 |
0.02 | 1 |
0.03 | 1 |
0.04 | 1 |
... | ... |
0.96 | 1 |
0.97 | 1 |
0.98 | 1 |
0.99 | 1 |
1.00 | 1 |
101 rows × 1 columns
def update_euro(pmf, dataset):
for data in dataset:
*= likelihood[data]
pmf pmf.normalize()
= prior.copy()
posterior = 'H' * 140 + 'T' * 110
dataset
update_euro(posterior, dataset)
='coin', color='C5')
posterior.plot(label'동전 앞면 비율의 사후확률 분포')
plt.title('동전 앞면의 비율')
plt.xlabel('PMF') plt.ylabel(
Text(0, 0.5, 'PMF')
print(f'동전의 앞면이 250번 중 140번 등장했다면 앞면의 비율은 {posterior.max_prob()}일 확률이 가장 높다.')
동전의 앞면이 250번 중 140번 등장했다면 앞면의 비율은 0.56일 확률이 가장 높다.
삼각사전분포
- 사전확률을 균등분포로 설정했지만, 실제로는 정규분포에 가까울 것이다.
- 근데 책에서는 일단 삼각분포를 사용한다.
= np.arange(50)
ramp_up = np.arange(50, -1, -1)
ramp_down = np.append(ramp_up, ramp_down)
a = Pmf(a, hypos, name='triangle')
triangle
triangle.normalize()
= Pmf(1, hypos, name='uniform')
uniform
uniform.normalize()
='균등사전', color='C4')
uniform.plot(label='삼각사전', color='C5')
triangle.plot(label
plt.legend()'삼각사전분포 및 균등사전분포')
plt.title('동전 앞면의 비율')
plt.xlabel('PMF') plt.ylabel(
Text(0, 0.5, 'PMF')
update_euro(uniform, dataset)
update_euro(triangle, dataset)
='균등사전', color='C4')
uniform.plot(label='삼각사전', color='C5')
triangle.plot(label
plt.legend()'삼각 및 균등 사후분포')
plt.title('동전 앞면의 비율')
plt.xlabel('PMF') plt.ylabel(
Text(0, 0.5, 'PMF')
- 두 확률분포의 사후 분포간 차이는 미미함.
- 데이터가 충분하다면 서로 다른 사전확률로 시작한다고 해도 동일한 사후확률로 수렴하는 경향이 있다.
이항가능도함수
- 갱신을 굳이 250번 하지 않아도, 이항분포를 통해 가능도를 한번에 계산할 수 있다.
def update_binomial(pmf, data):
= data
k, n = pmf.qs
xs = binom.pmf(k, n, xs)
likelihood *= likelihood
pmf pmf.normalize()
= Pmf(1, hypos, name='uniform2')
uniform2 = 140, 250
data
update_binomial(uniform2, data) np.allclose(uniform, uniform2)
True
연습문제
4-1
= np.linspace(0.2, 0.33, 101)
hypos = Pmf(1, hypos)
uniform = uniform.copy()
prior
prior.normalize()
= 3, 3
data
update_binomial(uniform, data)='사전', color='C4')
prior.plot(label='사후', color='C5')
uniform.plot(label
plt.legend()'사전 vs 사후 분포')
plt.title('안타 비율')
plt.xlabel('PMF') plt.ylabel(
Text(0, 0.5, 'PMF')
4-2
def update_randomized_response(pmf, data):
= data
yes_count, total = pmf.qs
ps = 0.5 + 0.5 * ps
prob_yes = binom.pmf(yes_count, total, prob_yes)
likelihood *= likelihood
pmf
pmf.normalize()
= np.linspace(0, 1, 101)
hypos = Pmf(1, hypos)
uniform = uniform.copy()
prior
prior.normalize()
= 80, 100
data
update_randomized_response(uniform, data)
='사전', color='C4')
prior.plot(label='사후', color='C5')
uniform.plot(label
plt.legend()'Randomized Response - 사전 vs 사후 분포')
plt.title('탈세자 비율 (p)')
plt.xlabel('PMF')
plt.ylabel(True, alpha=0.3) plt.grid(
= uniform.max_prob()
most_likely_rate print(f'가장 가능성이 높은 탈세자 비율: {most_likely_rate:.3f}')
= uniform.credible_interval(0.95)
credible_interval print(f'95% 신뢰구간: [{credible_interval[0]:.3f}, {credible_interval[1]:.3f}]')
가장 가능성이 높은 탈세자 비율: 0.600
95% 신뢰구간: [0.420, 0.730]
4-3
def update_machine_response(pmf, data, y):
= data
k, n = pmf.qs * (1 - y) + (1 - pmf.qs) * y
xs = binom.pmf(k, n, xs)
likelihood *= likelihood
pmf
pmf.normalize()
= np.linspace(0, 1, 101)
hypos = Pmf(1, hypos)
uniform
= 140, 250
data for y in np.linspace(0, 0.5, 6):
= uniform.copy()
dist
update_machine_response(dist, data, y)=f'y={y:.1f}')
dist.plot(label
plt.legend()'y에 따른 앞면의 비율')
plt.title('동전 앞면의 비율')
plt.xlabel('PMF') plt.ylabel(
Text(0, 0.5, 'PMF')
4-4
= np.linspace(0.1, 0.4, 101)
hypos = Pmf(1, hypos)
uniform = Pmf(1, hypos)
prior
prior.normalize()
= (1 - hypos) ** 4
prob_both_0 = (2 * hypos * (1 - hypos)) ** 2
prob_both_1 = hypos ** 4
prob_both_2
= prob_both_0 + prob_both_1 + prob_both_2
likelihood = uniform * likelihood
posterior
posterior.normalize()
='사전분포', color='C1')
prior.plot(label='사후분포', color='C2')
posterior.plot(label
plt.legend()'사전 분포와 사후분포')
plt.title('우주선을 맞출 확률 (x)')
plt.xlabel('PMF')
plt.ylabel(
= prior.mean()
prior_mean = posterior.mean()
posterior_mean
print("\n=== 연습문제 4-4 답변 ===")
if posterior_mean > prior_mean:
print("✅ 데이터는 좋은 소식입니다 (GOOD)")
print(f"✅ x의 추정값이 {prior_mean:.3f}에서 {posterior_mean:.3f}로 증가했습니다 (INCREASE)")
else:
print("❌ 데이터는 나쁜 소식입니다 (BAD)")
print(f"❌ x의 추정값이 {prior_mean:.3f}에서 {posterior_mean:.3f}로 감소했습니다 (DECREASE)")
=== 연습문제 4-4 답변 ===
❌ 데이터는 나쁜 소식입니다 (BAD)
❌ x의 추정값이 0.250에서 0.235로 감소했습니다 (DECREASE)