콘텐츠로 이동
Data Prep
상세

베이지안 통계 (Bayesian Statistics)

데이터가 주어졌을 때 모수의 불확실성을 확률로 표현하는 통계적 접근법. ML/DL에서 불확실성 정량화, 정규화, 하이퍼파라미터 튜닝 등에 활용됨.

왜 베이지안인가

빈도주의의 한계: - 점 추정만 제공, 불확실성 표현 제한적 - 사전 지식 반영 어려움 - "모수는 고정" 가정이 때로 부자연스러움

베이지안의 장점: - 불확실성 정량화: 예측의 신뢰도를 확률로 표현 - 사전 지식 활용: 기존 연구, 도메인 지식 반영 - 소표본에서 강점: 데이터가 적어도 합리적 추론 - 자연스러운 업데이트: 새 데이터로 믿음 점진적 갱신


베이지안 vs 빈도주의

관점 빈도주의 (Frequentist) 베이지안 (Bayesian)
확률의 의미 장기적 빈도 믿음의 정도
모수 θ 고정된 미지의 값 확률 변수
추론 대상 P(Data | θ) P(θ | Data)
사전 정보 사용 안 함 사전 분포로 반영
결과 점 추정, 신뢰구간 사후 분포 전체
해석 "반복 시 95%가 참값 포함" "95% 확률로 이 구간에 있음"

직관적 차이:

질문: "이 동전의 앞면 확률은?"

빈도주의: "동전을 무한히 던지면 앞면 비율이 θ에 수렴"
         θ는 고정된 값, 우리가 모를 뿐

베이지안: "내 믿음으로는 θ가 0.4~0.6 사이일 확률이 90%"
         θ 자체가 불확실하고, 데이터로 업데이트함


베이즈 정리 복습

\[P(\theta | D) = \frac{P(D | \theta) P(\theta)}{P(D)}\]
이름 의미 역할
\(P(\theta)\) 사전 분포 데이터 전 모수에 대한 믿음 기존 지식 반영
\(P(D\|\theta)\) 우도 모수가 주어졌을 때 데이터 확률 데이터의 증거력
\(P(\theta\|D)\) 사후 분포 데이터 후 모수에 대한 믿음 최종 추론 결과
\(P(D)\) 증거 정규화 상수 분포가 합이 1이 되게

핵심 공식 (비례 형태): $\(\text{Posterior} \propto \text{Likelihood} \times \text{Prior}\)$


베이즈 업데이트 예시

동전 던지기

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

def coin_flip_posterior(n_heads, n_tails, prior_alpha=1, prior_beta=1):
    """
    Prior: Beta(alpha, beta)
    Data: n_heads 성공, n_tails 실패
    Posterior: Beta(alpha + n_heads, beta + n_tails)
    """
    return stats.beta(prior_alpha + n_heads, prior_beta + n_tails)

# 시뮬레이션
np.random.seed(42)
true_p = 0.7
x = np.linspace(0, 1, 200)

fig, axes = plt.subplots(2, 3, figsize=(15, 8))
prior = stats.beta(1, 1)  # 무정보적 사전 (균등분포)

n_heads, n_tails = 0, 0
for idx, n_flips in enumerate([0, 1, 5, 10, 50, 200]):
    ax = axes.flatten()[idx]

    # 새로운 관측
    new_flips = n_flips - (n_heads + n_tails)
    if new_flips > 0:
        new_results = np.random.binomial(1, true_p, new_flips)
        n_heads += new_results.sum()
        n_tails += new_flips - new_results.sum()

    posterior = coin_flip_posterior(n_heads, n_tails)

    ax.plot(x, prior.pdf(x), 'b--', label='Prior', alpha=0.5)
    ax.plot(x, posterior.pdf(x), 'r-', label='Posterior', linewidth=2)
    ax.axvline(x=true_p, color='g', linestyle=':', label=f'True p={true_p}')
    ax.fill_between(x, posterior.pdf(x), alpha=0.3, color='red')
    ax.set_title(f'n={n_flips} (heads={n_heads})')
    ax.legend()
    ax.set_xlim(0, 1)

plt.tight_layout()

관찰 포인트: 1. 데이터 0개: 사후 = 사전 (업데이트 없음) 2. 데이터 적을 때: 사전이 강하게 영향 3. 데이터 많아지면: 사전 영향 감소, 데이터가 지배


사전 분포 (Prior Distribution)

사전 분포의 종류

유형 설명 예시
무정보적 (Non-informative) 모수에 대해 아는 것 없음 Uniform, Jeffreys
약 정보적 (Weakly informative) 합리적 범위만 제한 넓은 Normal, Half-Cauchy
정보적 (Informative) 강한 사전 믿음 이전 연구 결과 기반
켤레 사전 (Conjugate) 계산 편의성 우도에 맞는 특정 분포

켤레 사전 분포 (Conjugate Prior)

사후 분포가 사전 분포와 같은 분포 family를 따르는 경우.

우도 켤레 사전 사후 예시
Binomial Beta Beta 성공률 추정
Poisson Gamma Gamma 발생률 추정
Normal (μ 알려짐, σ² 추정) Inverse-Gamma Inverse-Gamma 분산 추정
Normal (σ² 알려짐, μ 추정) Normal Normal 평균 추정
Exponential Gamma Gamma 대기 시간
Multinomial Dirichlet Dirichlet 범주 확률

왜 중요한가? 해석적 계산 가능 → MCMC 없이 빠른 추론.

# Beta-Binomial 예시: 클릭률 추정
def beta_binomial_update(alpha_prior, beta_prior, n_clicks, n_impressions):
    """
    Prior: Beta(alpha_prior, beta_prior)
    Data: n_clicks clicks in n_impressions
    Posterior: Beta(alpha + clicks, beta + non-clicks)
    """
    alpha_post = alpha_prior + n_clicks
    beta_post = beta_prior + n_impressions - n_clicks
    return alpha_post, beta_post

# 사전: Beta(2, 8) -> 평균 0.2에 대한 약한 믿음 (과거 경험)
# 데이터: 50 클릭 / 200 노출
alpha_post, beta_post = beta_binomial_update(2, 8, 50, 200)
posterior = stats.beta(alpha_post, beta_post)

print(f"사후 평균: {posterior.mean():.4f}")
print(f"사후 표준편차: {posterior.std():.4f}")
print(f"95% 신용 구간: {posterior.ppf([0.025, 0.975]).round(4)}")

# MLE (최대우도) 비교
mle = 50 / 200
print(f"MLE: {mle:.4f}")
# 사전이 MLE를 약간 수축(shrinkage)시킴

사전 분포 선택 가이드

실무 접근법:

  1. 도메인 지식 있으면 → 정보적 사전
  2. 과거 연구, 전문가 의견 반영

  3. 범위만 알면 → 약 정보적 사전

  4. 확률은 [0,1], 표준편차는 양수 등

  5. 전혀 모르면 → 무정보적/약 정보적 사전

  6. 결과에 크게 영향 안 주면서 정규화
# 약 정보적 사전 예시들

# 확률 (0~1): Beta(1, 1) = Uniform, 또는 Beta(2, 2)
# 양수 척도 (std 등): Half-Normal(0, 10) 또는 Half-Cauchy(0, 5)
# 무제한 위치 (mean): Normal(0, 100)
# 상관계수: LKJ prior (상관 행렬용)

# 권장: Stan, PyMC 문서의 "prior choice recommendations" 참고

사전 민감도 분석

# 다양한 사전으로 분석해서 결과가 얼마나 달라지는지 확인
priors = [(1, 1), (2, 8), (5, 5), (10, 2)]  # 다양한 Beta 사전
n_clicks, n_total = 50, 200

plt.figure(figsize=(10, 4))
x = np.linspace(0, 0.5, 200)

for alpha, beta in priors:
    alpha_post, beta_post = beta_binomial_update(alpha, beta, n_clicks, n_total)
    posterior = stats.beta(alpha_post, beta_post)
    label = f'Prior Beta({alpha},{beta}), Post mean={posterior.mean():.3f}'
    plt.plot(x, posterior.pdf(x), label=label)

plt.axvline(x=n_clicks/n_total, color='k', linestyle='--', label='MLE')
plt.legend()
plt.title('Prior Sensitivity Analysis')

# 데이터가 충분하면 사전 선택에 덜 민감함

사후 분포 추론

점 추정

추정량 정의 손실 함수 사용
MAP \(\arg\max_\theta P(\theta\|D)\) 0-1 손실 뾰족한 분포
사후 평균 \(E[\theta\|D]\) 제곱 손실 대칭 분포
사후 중앙값 Median of \(P(\theta\|D)\) 절대 손실 왜곡된 분포
# MAP vs 사후 평균
posterior = stats.beta(52, 158)  # 클릭률 예시

# MAP (최빈값): Beta의 mode = (α-1)/(α+β-2)
map_estimate = (52 - 1) / (52 + 158 - 2)
posterior_mean = posterior.mean()
posterior_median = posterior.median()

print(f"MAP: {map_estimate:.4f}")
print(f"사후 평균: {posterior_mean:.4f}")
print(f"사후 중앙값: {posterior_median:.4f}")

# 대칭 분포에서는 세 값이 비슷
# 왜곡된 분포에서는 다를 수 있음

신용 구간 (Credible Interval)

베이지안 신용 구간: "모수가 이 구간에 있을 확률이 95%"

# Equal-tailed interval (ETI)
# 양쪽 2.5%씩 자름
ci_eti = posterior.ppf([0.025, 0.975])
print(f"95% ETI: {ci_eti.round(4)}")

# Highest Posterior Density (HPD) interval
# 가장 좁은 구간 (비대칭 분포에서 더 유용)
from scipy.optimize import minimize_scalar

def hpd_interval(dist, prob=0.95):
    """HPD 구간: 확률 밀도가 가장 높은 구간"""
    alpha = 1 - prob

    def interval_width(lower_prob):
        lower = dist.ppf(lower_prob)
        upper = dist.ppf(lower_prob + prob)
        return upper - lower

    result = minimize_scalar(interval_width, bounds=(0, alpha), method='bounded')
    lower = dist.ppf(result.x)
    upper = dist.ppf(result.x + prob)
    return lower, upper

hpd = hpd_interval(posterior)
print(f"95% HPD: {np.round(hpd, 4)}")

신용 구간 vs 신뢰 구간

신용 구간 (Credible Interval) 신뢰 구간 (Confidence Interval)
"θ가 이 구간에 있을 확률 95%" "이런 구간들 중 95%가 θ 포함"
직관적 해석 해석 어려움
사후 분포 기반 표본 분포 기반
사전 분포 필요 사전 분포 불필요

MCMC (Markov Chain Monte Carlo)

복잡한 사후 분포에서 샘플을 추출하는 방법. 해석적 계산 불가능할 때 필수.

왜 MCMC가 필요한가

\[P(\theta|D) = \frac{P(D|\theta)P(\theta)}{P(D)}\]

문제: \(P(D) = \int P(D|\theta)P(\theta) d\theta\) 계산이 어려움 (고차원 적분)

해결: 사후 분포에서 직접 샘플 추출 → 적분 대신 샘플 평균

Metropolis-Hastings 알고리즘

def metropolis_hastings(log_posterior, initial, n_samples, proposal_std=0.5):
    """
    Metropolis-Hastings 알고리즘

    log_posterior: 사후의 log (정규화 상수 몰라도 됨)
    """
    samples = [initial]
    current = initial
    accepted = 0

    for _ in range(n_samples - 1):
        # 1. 제안 분포에서 후보 제안
        proposal = current + np.random.normal(0, proposal_std)

        # 2. 수락 확률 계산 (log 스케일)
        log_accept_ratio = log_posterior(proposal) - log_posterior(current)

        # 3. 수락 또는 거절
        if np.log(np.random.random()) < log_accept_ratio:
            current = proposal
            accepted += 1

        samples.append(current)

    acceptance_rate = accepted / (n_samples - 1)
    return np.array(samples), acceptance_rate

# 예시: Beta(52, 158)에서 샘플링
def log_beta_posterior(theta, alpha=52, beta=158):
    if theta <= 0 or theta >= 1:
        return -np.inf
    return (alpha - 1) * np.log(theta) + (beta - 1) * np.log(1 - theta)

samples, acc_rate = metropolis_hastings(log_beta_posterior, 0.3, 20000, proposal_std=0.02)
print(f"수락률: {acc_rate:.2%}")  # 이상적: 20-50%

# 번인(burn-in) 제거
samples = samples[5000:]

print(f"MCMC 평균: {samples.mean():.4f}")
print(f"실제 평균: {stats.beta(52, 158).mean():.4f}")

MCMC 수렴 진단 (중요!)

문제: MCMC가 수렴했는지 어떻게 알 수 있나?

def diagnose_mcmc(samples, n_chains=4):
    """MCMC 진단"""

    # 1. Trace plot: 시계열 확인
    plt.figure(figsize=(12, 3))
    plt.plot(samples, alpha=0.7)
    plt.xlabel('Iteration')
    plt.ylabel('θ')
    plt.title('Trace Plot')

    # 이상적: 특정 값 주위를 랜덤하게 왔다갔다 (fuzzy caterpillar)
    # 나쁜 징후: 추세, 긴 자기상관, 제자리 멈춤

# R-hat (Gelman-Rubin) 통계량
# 여러 체인을 독립적으로 돌려서 비교
# R-hat < 1.01이면 수렴으로 간주

# ESS (Effective Sample Size)
# 자기상관 고려한 "실질적" 샘플 수
# ESS > 400 권장

def effective_sample_size(samples):
    """간단한 ESS 계산"""
    n = len(samples)
    acf = np.correlate(samples - samples.mean(), samples - samples.mean(), mode='full')
    acf = acf[n-1:] / acf[n-1]

    # 처음으로 음수가 되는 지점까지의 자기상관 합
    for i in range(1, len(acf)):
        if acf[i] < 0:
            break

    tau = 1 + 2 * acf[1:i].sum()  # integrated autocorrelation time
    return n / tau

ess = effective_sample_size(samples)
print(f"ESS: {ess:.0f} / {len(samples)} samples")

PyMC를 이용한 베이지안 추론

import pymc as pm
import arviz as az

# 클릭률 추정 예시
n_clicks = 50
n_impressions = 200

with pm.Model() as click_model:
    # 사전 분포
    p = pm.Beta('p', alpha=2, beta=8)

    # 우도
    clicks = pm.Binomial('clicks', n=n_impressions, p=p, observed=n_clicks)

    # MCMC 샘플링
    trace = pm.sample(2000, tune=1000, return_inferencedata=True, 
                      random_seed=42)

# 결과 요약
print(az.summary(trace))

# 시각화
az.plot_posterior(trace)
az.plot_trace(trace)

# 수렴 진단
print(f"R-hat: {az.rhat(trace)}")
print(f"ESS: {az.ess(trace)}")

선형 회귀 (베이지안)

import pymc as pm

# 데이터 생성
np.random.seed(42)
n = 100
X = np.random.randn(n, 2)
true_weights = np.array([2.0, -1.5])
true_sigma = 0.5
y = X @ true_weights + np.random.randn(n) * true_sigma

with pm.Model() as linear_model:
    # 사전 분포 (약 정보적)
    weights = pm.Normal('weights', mu=0, sigma=10, shape=2)
    sigma = pm.HalfNormal('sigma', sigma=1)

    # 평균
    mu = pm.math.dot(X, weights)

    # 우도
    y_obs = pm.Normal('y', mu=mu, sigma=sigma, observed=y)

    # 추론
    trace = pm.sample(2000, tune=1000, return_inferencedata=True)

# 결과
print(az.summary(trace, var_names=['weights', 'sigma']))

# 예측 불확실성
with linear_model:
    pm.sample_posterior_predictive(trace, extend_inferencedata=True)

# 새 데이터에 대한 예측 분포 시각화 가능

베이지안 딥러닝

MC Dropout (Monte Carlo Dropout)

추론 시에도 Dropout 적용 → 예측 불확실성 추정.

이론적 배경: Dropout은 가우시안 프로세스의 근사 (Gal & Ghahramani, 2016)

import torch
import torch.nn as nn

class MCDropoutModel(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim, dropout_rate=0.5):
        super().__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)
        self.fc3 = nn.Linear(hidden_dim, output_dim)
        self.dropout = nn.Dropout(dropout_rate)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = self.dropout(x)  # 추론 시에도 적용!
        x = torch.relu(self.fc2(x))
        x = self.dropout(x)
        return self.fc3(x)

def predict_with_uncertainty(model, x, n_samples=100):
    """MC Dropout으로 예측 불확실성 추정"""
    model.train()  # Dropout 활성화

    predictions = []
    with torch.no_grad():
        for _ in range(n_samples):
            pred = model(x)
            predictions.append(pred)

    predictions = torch.stack(predictions)
    mean = predictions.mean(dim=0)
    std = predictions.std(dim=0)  # 불확실성

    return mean, std

# 사용 예시
model = MCDropoutModel(10, 64, 1)
x = torch.randn(5, 10)  # 5개 샘플
mean, uncertainty = predict_with_uncertainty(model, x)

# 불확실성이 높은 샘플 = 모델이 확신 못함
print(f"예측: {mean.squeeze()}")
print(f"불확실성: {uncertainty.squeeze()}")

언제 불확실성이 높은가?

  1. Epistemic uncertainty (모델 불확실성): 학습 데이터 부족
  2. 학습 데이터와 다른 영역의 입력
  3. 더 많은 데이터로 줄일 수 있음

  4. Aleatoric uncertainty (데이터 불확실성): 데이터 자체의 노이즈

  5. 입력이 출력을 완전히 결정하지 못함
  6. 더 많은 데이터로 줄일 수 없음
# Heteroscedastic regression: aleatoric 불확실성 모델링
class UncertaintyModel(nn.Module):
    def __init__(self, input_dim, hidden_dim):
        super().__init__()
        self.shared = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU()
        )
        self.mean_head = nn.Linear(hidden_dim, 1)
        self.var_head = nn.Linear(hidden_dim, 1)  # log variance

    def forward(self, x):
        h = self.shared(x)
        mean = self.mean_head(h)
        log_var = self.var_head(h)  # log 스케일로 양수 보장
        return mean, log_var

# Negative log-likelihood loss
def nll_loss(mean, log_var, target):
    var = torch.exp(log_var)
    return 0.5 * (log_var + (target - mean)**2 / var).mean()

ML에서의 베이지안 응용

베이지안 최적화 (Bayesian Optimization)

하이퍼파라미터 튜닝에 활용. Grid/Random search보다 효율적.

from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel

def bayesian_optimization(objective, bounds, n_iterations=30, n_initial=5):
    """
    베이지안 최적화

    objective: 최대화할 함수 (black-box)
    bounds: (min, max) 튜플
    """
    X_observed = []
    y_observed = []

    # 1. 초기 랜덤 탐색
    for _ in range(n_initial):
        x = np.random.uniform(bounds[0], bounds[1])
        y = objective(x)
        X_observed.append([x])
        y_observed.append(y)

    X_observed = np.array(X_observed)
    y_observed = np.array(y_observed)

    # GP 모델 (surrogate function)
    kernel = ConstantKernel() * RBF()
    gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=10,
                                   alpha=1e-6)

    for i in range(n_iterations):
        gp.fit(X_observed, y_observed)

        # 2. Acquisition function 최대화
        # Expected Improvement (EI)
        x_candidates = np.linspace(bounds[0], bounds[1], 1000).reshape(-1, 1)
        mu, sigma = gp.predict(x_candidates, return_std=True)

        best_y = y_observed.max()
        with np.errstate(divide='warn'):
            improvement = mu - best_y
            Z = improvement / (sigma + 1e-9)
            ei = improvement * stats.norm.cdf(Z) + sigma * stats.norm.pdf(Z)
            ei[sigma < 1e-9] = 0

        # 3. 다음 탐색 지점
        x_next = x_candidates[np.argmax(ei)]
        y_next = objective(x_next[0])

        X_observed = np.vstack([X_observed, x_next])
        y_observed = np.append(y_observed, y_next)

        if (i + 1) % 10 == 0:
            print(f"Iter {i+1}: best y = {y_observed.max():.4f}")

    best_idx = np.argmax(y_observed)
    return X_observed[best_idx], y_observed[best_idx]

# 예시: 학습률 최적화
def objective(lr):
    # 실제로는 모델 학습 후 validation loss 반환
    return -((lr - 0.01)**2 * 1000 + 0.1 * np.random.randn())

best_lr, best_score = bayesian_optimization(objective, bounds=[0.0001, 0.1])
print(f"최적 학습률: {best_lr[0]:.6f}")

L2 정규화의 베이지안 해석

핵심 통찰: L2 정규화 = 가중치에 대한 가우시안 사전

# L2 정규화 손실: L(w) + λ||w||²
# 
# 베이지안 해석:
# - 우도: P(D|w) ∝ exp(-L(w))
# - 가우시안 사전: P(w) ∝ exp(-λ||w||²) = N(0, 1/(2λ)I)
# - MAP 추정 = L2 정규화 최소화
#
# 따라서:
lambda_reg = 0.01
prior_variance = 1 / (2 * lambda_reg)
print(f"L2 λ={lambda_reg} ↔ 사전 분산 σ²={prior_variance}")

# λ가 크면 → 사전 분산 작음 → 가중치를 0에 가깝게 제한
# λ가 작으면 → 사전 분산 큼 → 가중치 자유도 높음

L1 정규화의 베이지안 해석

# L1 정규화 = 라플라스 사전
# P(w) ∝ exp(-λ|w|) = Laplace(0, 1/λ)
#
# 라플라스 분포는 0에서 뾰족함 → 많은 가중치가 정확히 0
# → Sparse solution (희소성)

모델 비교 (베이즈 팩터)

두 모델의 상대적 증거 비교.

\[BF_{12} = \frac{P(D|M_1)}{P(D|M_2)} = \frac{\text{Model 1의 증거}}{\text{Model 2의 증거}}\]
# BIC를 이용한 베이즈 팩터 근사
def approx_log_bayes_factor(bic1, bic2):
    """
    log(BF) ≈ (BIC2 - BIC1) / 2
    """
    return (bic2 - bic1) / 2

# 해석 (Kass & Raftery, 1995)
# log(BF) > 5 (BF > 150): 매우 강한 증거 (M1 선호)
# log(BF) > 3 (BF > 20): 강한 증거
# log(BF) > 1 (BF > 3): 양의 증거
# log(BF) ≈ 0 (BF ≈ 1): 증거 없음 (동등)
# log(BF) < -1: M2 선호

# 예시
bic_simple = 100  # 간단한 모델
bic_complex = 95  # 복잡한 모델

log_bf = approx_log_bayes_factor(bic_simple, bic_complex)
print(f"log(BF) = {log_bf:.2f}")
print(f"BF = {np.exp(log_bf):.2f}")

if log_bf > 1:
    print("복잡한 모델 선호")
else:
    print("간단한 모델 선호 (Occam's razor)")

흔한 실수와 오해

1. 사전 분포를 데이터에서 결정

# 나쁜 예: 데이터 보고 사전 설정 (double dipping)
# data = ...
# prior_mean = data.mean()  # 틀림!

# 사전은 데이터 보기 전의 믿음이어야 함
# 데이터로 사전을 정하면 사후가 과적합됨

2. "무정보적" 사전이 항상 좋다고 생각

# 무정보적 사전의 문제:
# 1. 변환에 불변하지 않음
#    θ에 Uniform → log(θ)에는 Uniform 아님
# 2. 부적절한 사전 (improper prior)은 사후도 부적절할 수 있음
# 3. 실제로 "정보 없음"이 아닌 경우가 많음

# 권장: 약 정보적 사전
# - 물리적으로 말이 되는 범위 제한
# - 계산적으로 안정

3. 사후 분포의 모드만 보고

# MAP만 보고하면 불확실성 정보 손실
# 사후 분포 전체를 보고하거나, 최소한 신용 구간 함께

# 나쁜 예: "θ = 0.25"
# 좋은 예: "θ = 0.25 (95% CI: [0.20, 0.30])"
# 더 좋은 예: 사후 분포 시각화

4. MCMC 수렴 확인 안 함

# 반드시 확인:
# 1. Trace plot: 랜덤하게 왔다갔다 하는지
# 2. R-hat < 1.01
# 3. ESS > 400
# 4. 여러 체인이 같은 분포 탐색하는지

# 수렴 안 되면:
# - 샘플 수 늘리기
# - 튜닝(warm-up) 늘리기
# - 더 효율적인 샘플러 (NUTS, HMC)
# - 모델/파라미터화 재검토

5. 빈도주의 개념과 혼동

# 신뢰구간 vs 신용구간 해석 혼동
# 빈도주의: "장기적으로 95%가 참값 포함"
# 베이지안: "θ가 이 구간에 있을 확률 95%"

# p-value는 베이지안 개념이 아님!
# 베이지안에서는 사후 확률로 직접 판단

참고 자료