확률공간과 확률변수

측정을 반복하면 매번 값이 조금씩 다르다. 센서 잡음, 시료의 불균일, 환경의 요동이 섞이기 때문이다. 이 흩어짐을 "평균 3.2, 표준편차 0.4"처럼 숫자 두 개로 요약하는 것이 보통이지만, 숫자 두 개가 말해 주지 않는 것이 많다. 값이 0 근처에 몰려 있는지, 드물게 아주 큰 값이 나오는지, 봉우리가 두 개인지는 분포 전체를 보아야 알 수 있다. 머신러닝 모델도 마찬가지다. 분류기의 softmax 출력, 생성모델의 샘플, 회귀 모델의 예측 구간은 모두 분포에 대한 진술이다.

이 장은 그 분포를 다루기 위한 최소한의 언어를 세운다. 무작위 실험을 수학적으로 적는 확률공간, 실험 결과를 숫자로 바꾸는 확률변수, 그리고 분포를 적는 네 가지 방법(PMF·PDF·CDF·quantile function)이다. 마지막으로 확률변수를 함수에 통과시켰을 때 분포가 어떻게 바뀌는지(변수변환)를 다룬다. 이 장의 기호는 부록 A. 표기법을 따른다.

학습 목표

  • 확률공간과 확률변수를 정의한다
  • PMF·PDF·CDF를 구분한다
  • 변수변환으로 확률변수 함수의 분포를 구한다

확률공간의 직관

"이 센서가 다음 측정에서 3.5보다 큰 값을 낼 확률"을 말하려면 세 가지를 정해야 한다. 일어날 수 있는 결과가 무엇인지, 확률을 매길 대상이 무엇인지, 그리고 그 대상에 어떤 숫자를 줄지다. 이 셋을 묶은 것이 확률공간(probability space) (Ω,F,P)(\Omega, \mathcal{F}, P)다.

  • 표본공간(sample space) Ω\Omega: 실험의 가능한 결과 ω\omega 전체의 집합. 주사위 하나면 {1,…,6}\{1, \dots, 6\}, 부품 수명이면 [0,∞)[0, \infty)다.
  • 사건(event): 확률을 매길 수 있는 Ω\Omega의 부분집합. "짝수가 나온다" ={2,4,6}= \{2, 4, 6\}. 사건들의 모음을 F\mathcal{F}라 쓴다.
  • 확률 측도(probability measure) PP: 사건마다 [0,1][0, 1]의 숫자를 주는 함수.

PP는 세 가지 공리(Kolmogorov 공리)만 만족하면 된다.

P(A)≥0,P(Ω)=1,P(⋃i=1∞Ai)=∑i=1∞P(Ai)  (Ai가 서로소일 때).P(A) \ge 0, \qquad P(\Omega) = 1, \qquad P\Big(\bigcup_{i=1}^\infty A_i\Big) = \sum_{i=1}^\infty P(A_i) \ \ (A_i \text{가 서로소일 때}).

첫째는 확률이 음수가 아니라는 것, 둘째는 "무언가는 반드시 일어난다"는 것, 셋째는 겹치지 않는 사건들의 확률은 더해진다는 것이다. 여사건의 확률 P(Ac)=1−P(A)P(A^c) = 1 - P(A), 합사건의 확률 P(A∪B)=P(A)+P(B)−P(A∩B)P(A \cup B) = P(A) + P(B) - P(A \cap B) 같은 익숙한 규칙은 모두 이 공리에서 나온다.

확률변수

확률공간은 결과 ω\omega를 그대로 다루지만, 연구에서 관심 있는 것은 결과에서 계산한 숫자다. 주사위 두 개를 던진 결과 ω=(3,5)\omega = (3, 5)에서 관심 있는 것은 합 8이고, 대기 관측 하루에서 관심 있는 것은 강수량 mm다. 결과를 숫자로 바꾸는 규칙이 확률변수다.

정의. 확률변수(random variable) XX는 표본공간에서 실수로 가는 함수 X:Ω→RX: \Omega \to \mathbb{R}이다. 무작위인 것은 함수가 아니라 어떤 ω\omega가 실현되는가다. ω\omega가 정해지면 X(ω)X(\omega)는 하나로 정해진다. 그래서 같은 실험 위에 주사위 합, 최댓값, 첫 주사위 값처럼 여러 확률변수를 함께 정의할 수 있고, 이들 사이의 관계(11.3장의 결합분포)를 말할 수 있다.

XX에 대한 질문은 Ω\Omega의 사건으로 바뀐다. {X≤x}\{X \le x\}는 {ω:X(ω)≤x}\{\omega : X(\omega) \le x\}의 줄임말이고, 그 확률을 P(X≤x)P(X \le x)라 쓴다. 대문자 XX는 확률변수, 소문자 xx는 그것이 취한 값이다.

확률변수는 값의 모양에 따라 셋으로 나뉜다.

  • 이산(discrete): 셀 수 있는 값만 갖는다. 검출기에 들어온 광자 수, 불량품 수.
  • 연속(continuous): 구간의 값을 갖고, 한 점의 확률은 모두 0이다. 부품 수명, 기온.
  • 혼합(mixed): 둘이 섞인 것. 하루 강수량은 비가 오지 않은 날 정확히 0이고(이산 부분), 비가 온 날 연속적인 양수다(연속 부분).

혼합형은 예외처럼 보이지만 과학 데이터에서 흔하다. 비가 오는 날이 전체의 40%이고, 비가 온 날의 강수량은 평균 5 mm인 지수분포를 따른다고 두고 시뮬레이션한다.

import numpy as np

rng = np.random.default_rng(0)
n_days = 100_000
wet = rng.random(n_days) < 0.4                                          # (N,) 비가 온 날
rain_mm = np.where(wet, rng.exponential(scale=5.0, size=n_days), 0.0)   # (N,) 강수량

print(f"P(R = 0)    ≈ {np.mean(rain_mm == 0):.3f}   (이론 0.600)")
print(f"P(R = 3 mm) ≈ {np.mean(rain_mm == 3.0):.3f}   (연속 부분의 한 점)")
for r in (0.0, 1.0, 5.0, 20.0):
    F_theory = 0.6 + 0.4 * (1 - np.exp(-r / 5.0))
    print(f"F({r:4.1f} mm) ≈ {np.mean(rain_mm <= r):.3f}   이론 {F_theory:.3f}")
P(R = 0)    ≈ 0.601   (이론 0.600)
P(R = 3 mm) ≈ 0.000   (연속 부분의 한 점)
F( 0.0 mm) ≈ 0.601   이론 0.600
F( 1.0 mm) ≈ 0.673   이론 0.673
F( 5.0 mm) ≈ 0.854   이론 0.853
F(20.0 mm) ≈ 0.993   이론 0.993

값 0에는 확률 0.6이 실려 있지만, 3 mm 같은 연속 부분의 한 점에는 확률이 없다. 이런 변수는 다음 절의 PMF나 PDF 하나로는 표현되지 않는다. 그러나 누적확률 P(R≤r)P(R \le r)은 이론값(0.6+0.4(1−e−r/5)0.6 + 0.4(1 - e^{-r/5}))과 잘 맞는다. 다음 절에서 볼 CDF가 모든 확률변수에 공통인 표현인 이유다.

분포의 표현

확률변수 XX의 분포(distribution)는 "XX가 어느 구간에 있을 확률"을 모두 모은 것이다. 이를 적는 방법이 네 가지 있고, 각각 쓰임이 다르다.

PMF. 이산확률변수의 확률질량함수(probability mass function)는 각 값의 확률이다.

p(x)=P(X=x),∑xp(x)=1.p(x) = P(X = x), \qquad \sum_x p(x) = 1.

PDF. 연속확률변수의 확률밀도함수(probability density function) p(x)p(x)는 구간의 확률을 적분으로 준다.

P(a<X≤b)=∫abp(x) dx,∫−∞∞p(x) dx=1.P(a < X \le b) = \int_a^b p(x)\,dx, \qquad \int_{-\infty}^{\infty} p(x)\,dx = 1.

PDF 값 p(x)p(x)는 확률이 아니라 단위 길이당 확률이다. 짧은 구간 [x,x+h][x, x + h]의 확률이 약 p(x) hp(x)\,h다. 그러므로 PDF 값은 1보다 클 수 있다. 폭 0.5인 구간에 확률 1을 고르게 펴면 밀도는 2가 된다.

from scipy import stats

X = stats.uniform(loc=0.0, scale=0.5)          # 0~0.5 균등분포
print("pdf(0.2) =", X.pdf(0.2))
print("P(0.1 < X <= 0.3) = F(0.3) - F(0.1) =", round(X.cdf(0.3) - X.cdf(0.1), 3))

x = X.rvs(size=200_000, random_state=np.random.default_rng(1))   # (N,)
print("표본에서 센 비율                    =", round(np.mean((x > 0.1) & (x <= 0.3)), 3))
for h in (0.1, 0.01, 0.001):
    frac = np.mean(np.abs(x - 0.2) < h / 2)                       # 폭 h 구간에 든 비율
    print(f"h = {h:<5}  P(|X - 0.2| < h/2) ≈ {frac:.4f}   비율 / h = {frac / h:.2f}")
pdf(0.2) = 2.0
P(0.1 < X <= 0.3) = F(0.3) - F(0.1) = 0.4
표본에서 센 비율                    = 0.402
h = 0.1    P(|X - 0.2| < h/2) ≈ 0.2005   비율 / h = 2.01
h = 0.01   P(|X - 0.2| < h/2) ≈ 0.0200   비율 / h = 2.00
h = 0.001  P(|X - 0.2| < h/2) ≈ 0.0021   비율 / h = 2.05

구간이 좁아질수록 그 구간에 든 확률은 0으로 가지만, 확률을 구간 폭으로 나눈 값은 PDF 값 2 근처에 머문다. 이것이 밀도의 뜻이다. h=0.001h = 0.001에서 2.05로 조금 벗어난 것은 구간에 든 표본이 400개 정도로 적어 생긴 표본 잡음이다. 코드에서 scipy.stats의 분포 객체는 pdf(또는 이산 분포의 pmf), cdf, ppf(quantile function), rvs(표본 추출)를 같은 이름으로 제공한다. 이 책은 이 인터페이스를 계속 쓴다.

CDF. 누적분포함수(cumulative distribution function)는

F(x)=P(X≤x)F(x) = P(X \le x)

다. 이산·연속·혼합 어느 경우에도 정의된다는 것이 CDF의 장점이다. 성질은 세 가지다. 감소하지 않고, x→−∞x \to -\infty에서 0, x→∞x \to \infty에서 1로 가며, 오른쪽 연속이다. 구간 확률은 P(a<X≤b)=F(b)−F(a)P(a < X \le b) = F(b) - F(a)이고, 한 점의 확률 P(X=x)P(X = x)는 그 점에서 CDF가 뛰는 높이다. 연속이면 p(x)=F′(x)p(x) = F'(x), 이산이면 CDF가 PMF의 값만큼 계단처럼 뛴다.

Quantile function. CDF의 역함수 F−1(p)F^{-1}(p)는 "누적확률이 pp가 되는 값"이다. F−1(0.5)F^{-1}(0.5)가 중앙값, F−1(0.9)F^{-1}(0.9)가 90% 분위수다. CDF가 계단이거나 평평한 구간이 있으면 보통의 역함수가 없으므로 일반화 역함수를 쓴다.

F−1(p)=min⁡{x:F(x)≥p},0<p<1.F^{-1}(p) = \min\{x : F(x) \ge p\}, \qquad 0 < p < 1.

"누적확률이 처음으로 pp에 닿는 xx"다. 이 정의로 F(F−1(p))≥pF(F^{-1}(p)) \ge p가 항상 성립하고, 연속이며 순증가하는 CDF에서는 등호가 된다.

T = stats.expon(scale=2000.0)                  # 부품 수명(시간), 평균 2000 h
for p in (0.1, 0.5, 0.9):
    t_h = T.ppf(p)                             # quantile function F^{-1}(p)
    print(f"F^-1({p}) = {t_h:7.1f} h   F(F^-1(p)) = {T.cdf(t_h):.3f}")

K = stats.poisson(mu=3.0)                      # 이산 분포: CDF가 계단
print("Poisson(3)  F(2) =", round(K.cdf(2), 3), "  F(3) =", round(K.cdf(3), 3))
print("F^-1(0.5) =", K.ppf(0.5), "  (F(k) >= 0.5인 가장 작은 k)")

u = np.random.default_rng(2).random(100_000)   # (N,) Unif(0, 1)
t_sim = T.ppf(u)                               # 역변환 샘플링
print(f"F^-1(U)의 표본 중앙값 {np.median(t_sim):.1f} h   이론 중앙값 {T.median():.1f} h")
F^-1(0.1) =   210.7 h   F(F^-1(p)) = 0.100
F^-1(0.5) =  1386.3 h   F(F^-1(p)) = 0.500
F^-1(0.9) =  4605.2 h   F(F^-1(p)) = 0.900
Poisson(3)  F(2) = 0.423   F(3) = 0.647
F^-1(0.5) = 3.0   (F(k) >= 0.5인 가장 작은 k)
F^-1(U)의 표본 중앙값 1390.7 h   이론 중앙값 1386.3 h

세 가지를 읽는다. 첫째, 평균 수명이 2000 h인 지수분포에서 중앙값은 1386 h로 평균보다 짧다. 오른쪽 꼬리가 길어 평균을 끌어올리기 때문이다. "부품 절반이 1386 h 안에 고장 난다"와 "평균 수명 2000 h"는 같은 분포에 대한 다른 진술이다. 둘째, Poisson(3)은 F(2)=0.423<0.5≤F(3)=0.647F(2) = 0.423 < 0.5 \le F(3) = 0.647이므로 중앙값이 3이다. 계단 CDF에서는 일반화 역함수가 정확히 이렇게 동작한다. 셋째, 균등난수 UU를 quantile function에 넣으면 그 분포의 표본이 나온다. P(F−1(U)≤x)=P(U≤F(x))=F(x)P(F^{-1}(U) \le x) = P(U \le F(x)) = F(x)이기 때문이다. 이 역변환 샘플링(inverse transform sampling)은 11.6장에서 다른 샘플링 방법과 함께 다룬다.

아래 위젯에서 분포와 모수를 바꾸며 위쪽의 PDF(이산 분포는 PMF)와 아래쪽의 CDF를 함께 본다. xx를 움직이면 xx 왼쪽의 넓이(이산 분포는 막대의 합)가 아래 그림의 F(x)F(x) 높이와 같다는 것을 확인할 수 있다.

네 표현의 쓰임. PMF·PDF는 우도(12.2장)와 모델의 손실을 쓸 때, CDF는 구간 확률·초과확률·혼합형 변수를 다룰 때, quantile function은 예측 구간·위험 한계(예: "99% 확률로 이 하중을 넘지 않는다")·샘플링에 쓴다. 같은 분포를 어느 표현으로 보느냐에 따라 눈에 띄는 성질이 다르다. 밀도의 봉우리는 PDF에서, 꼬리의 무게는 CDF의 1−F(x)1 - F(x)나 quantile에서 잘 보인다.

변수변환

확률변수를 함수에 통과시키는 일은 흔하다. 측정한 전압을 온도로 환산하고, 양수 파라미터를 log⁡\log 공간에서 다루고, 신경망 출력에 softplus를 씌운다. XX의 분포를 알 때 Y=g(X)Y = g(X)의 분포는 무엇일까.

CDF로 구하기. 가장 일반적인 방법은 CDF의 정의로 돌아가는 것이다. gg가 증가함수이면

FY(y)=P(g(X)≤y)=P(X≤g−1(y))=FX(g−1(y))F_Y(y) = P(g(X) \le y) = P(X \le g^{-1}(y)) = F_X(g^{-1}(y))

이다. 감소함수이면 부등호가 뒤집혀 FY(y)=1−FX(g−1(y))F_Y(y) = 1 - F_X(g^{-1}(y))가 된다(연속일 때).

밀도 공식. 연속이고 gg가 순단조이며 미분 가능하면, 위 식을 yy로 미분해

pY(y)=pX(g−1(y)) ∣dg−1(y)dy∣p_Y(y) = p_X\big(g^{-1}(y)\big)\,\left|\frac{d g^{-1}(y)}{dy}\right|

를 얻는다. 첫 인자는 "yy로 가는 xx의 밀도", 둘째 인자는 gg가 구간 길이를 얼마나 늘리거나 줄이는지를 보정하는 Jacobian이다. gg가 구간을 두 배로 늘리면 같은 확률이 두 배 길이에 펴지므로 밀도는 절반이 된다. 다변수에서는 이 인자가 Jacobian 행렬식 ∣det⁡Jg−1∣|\det \mathbf{J}_{g^{-1}}|이 되고, normalizing flow(19.4장)가 바로 이 공식으로 밀도를 계산한다. gg가 단조가 아니면(예: Y=X2Y = X^2) yy로 가는 xx가 여러 개이므로 각 가지의 기여를 더한다.

X∼N(0,0.52)X \sim \mathcal{N}(0, 0.5^2), Y=eXY = e^X로 확인한다. g−1(y)=log⁡yg^{-1}(y) = \log y, ∣dg−1/dy∣=1/y|dg^{-1}/dy| = 1/y이므로 pY(y)=pX(log⁡y)/yp_Y(y) = p_X(\log y)/y이고, 이것이 로그정규(log-normal) 분포다.

X = stats.norm(0.0, 0.5)
Y = stats.lognorm(s=0.5)                       # exp(X)의 분포 (scipy의 로그정규)
y_grid = np.array([0.5, 1.0, 1.5, 2.0])
p_formula = X.pdf(np.log(y_grid)) / y_grid     # p_X(g^{-1}(y)) |d g^{-1}/dy|
print("공식   p_Y(y):", np.round(p_formula, 4))
print("scipy  p_Y(y):", np.round(Y.pdf(y_grid), 4))

y = np.exp(X.rvs(size=200_000, random_state=np.random.default_rng(3)))   # (N,)
print(f"중앙값  exp(X의 중앙값) = {np.exp(X.median()):.3f}   Y 표본 {np.median(y):.3f}")
print(f"평균    exp(X의 평균)   = {np.exp(X.mean()):.3f}   Y 표본 {y.mean():.3f}")
print(f"최빈값  exp(X의 최빈값) = {np.exp(0.0):.3f}   Y 이론 {np.exp(-0.5**2):.3f}")
공식   p_Y(y): [0.6105 0.7979 0.3829 0.1526]
scipy  p_Y(y): [0.6105 0.7979 0.3829 0.1526]
중앙값  exp(X의 중앙값) = 1.000   Y 표본 1.000
평균    exp(X의 평균)   = 1.000   Y 표본 1.133
최빈값  exp(X의 최빈값) = 1.000   Y 이론 0.779

공식이 scipy의 로그정규 밀도와 일치한다. 아래 세 줄이 이 절의 핵심이다. 단조 증가 변환은 분위수를 보존한다. P(Y≤em)=P(X≤m)P(Y \le e^m) = P(X \le m)이므로 중앙값은 그대로 e0=1e^0 = 1로 간다. 그러나 평균은 보존되지 않는다. exe^x가 볼록하므로 E[eX]>eE[X]\mathbb{E}[e^X] > e^{\mathbb{E}[X]}이고(Jensen 부등식, 11.5장), 이론값은 e0.52/2≈1.133e^{0.5^2/2} \approx 1.133이다. 최빈값도 보존되지 않는다. 밀도에 Jacobian 1/y1/y가 곱해져 봉우리가 e−0.25≈0.779e^{-0.25} \approx 0.779로 옮겨 간다. 밀도의 봉우리는 좌표를 바꾸면 움직이는 양이다.

연구에서의 의미. 로그 공간에서 학습한 모델의 예측을 exp⁡\exp로 되돌리면 그것은 원래 공간의 평균이 아니라 (로그 공간 예측이 중앙값이었다면) 중앙값이다. 반응 속도, 농도, 입자 크기처럼 양수이고 오른쪽으로 긴 양을 로그 변환해 회귀하는 일이 흔한데, 이때 되돌린 예측값이 평균보다 체계적으로 작게 나온다. 또 MAP 추정(13.1장)은 사후밀도의 봉우리이므로 파라미터를 어떤 좌표로 적느냐에 따라 바뀐다. 분위수와 CDF는 좌표에 따라 바뀌지 않는다.

실습

평균 0, 분산 1로 맞춘 다섯 분포(정규, 균등, Laplace, 평균을 뺀 지수분포, 두 정규분포의 쌍봉 혼합)를 만들어 점 요약이 놓치는 차이를 수치로 본다. 코드는 labs/probability/random-variables/same_moments.py이고, 다섯 분포의 히스토그램과 CDF를 한 그림에 겹쳐 outputs/same_moments.png로 저장한다. 집필 시점의 실행 결과는 다음과 같다(시드 0, 각 100만 표본).

samples 1,000,000, seed 0
dist         mean    var  median  P(|X|<0.25)   P(X>2)  P(|X|>3)
normal      0.001  1.001   0.001        0.197   0.0230    0.0027
uniform    -0.000  1.000   0.001        0.145   0.0000    0.0000
Laplace    -0.000  0.996   0.001        0.298   0.0293    0.0141
exp - 1    -0.000  1.001  -0.308        0.186   0.0499    0.0184
bimodal    -0.001  1.000  -0.003        0.063   0.0029    0.0000

평균과 분산은 모두 같지만 다른 질문에 대한 답은 크게 다르다.

  • 꼬리. 3 표준편차 밖으로 벗어날 확률이 정규분포는 0.27%, Laplace는 1.41%, 지수분포는 1.84%로 5–7배 차이가 난다. 균등분포는 아예 0이다. "3σ 밖은 이상치"라는 규칙은 정규분포를 가정한 것이다.
  • 중앙값. 지수분포는 평균이 0이어도 중앙값이 −0.308-0.308이다. 비대칭 분포에서 평균은 "전형적인 값"이 아니다.
  • 중심부. 쌍봉 혼합은 평균 0 근처(∣X∣<0.25|X| < 0.25)에 확률이 6.3%밖에 없다. 평균이 가장 드문 값 근처에 놓일 수 있다.

그림에서 다섯 CDF는 모두 0 근처를 지나지만 기울기(밀도)와 양 끝의 접근 속도(꼬리)가 다르다. 스크립트를 고쳐 정규분포와 Laplace 분포의 표의 값을 scipy.stats의 cdf로 계산한 이론값과 비교한다. 예를 들어 정규분포의 P(∣X∣>3)P(|X| > 3)은 2 * stats.norm.sf(3)이다. 이어서 연습문제를 푼다. 테스트가 바로 채점한다.

실패 사례

  • PDF 값을 확률로 읽는 것. "이 값에서 밀도가 3.2이므로 확률이 높다"는 말은 성립하지 않는다. 밀도는 단위에 따라 바뀐다. 같은 분포를 m 대신 mm로 적으면 밀도 값은 1000분의 1이 된다. 확률이 필요하면 구간을 정하고 CDF의 차를 계산한다. 생성모델이 내놓는 로그우도(log-likelihood)도 연속 데이터에서는 로그 밀도이므로, 데이터의 단위나 전처리(스케일링)가 다른 모델끼리는 값을 그대로 비교할 수 없다.
  • 연속확률변수에서 확률 0을 "불가능"으로 읽는 것. P(X=0.3)=0P(X = 0.3) = 0이어도 관측값은 늘 어떤 한 점이다. 반대로 측정 장비가 값을 반올림해 기록하면 데이터는 사실상 이산이 되어 같은 값이 반복된다. 이런 데이터에 연속 밀도 모델을 맞추면 우도가 한없이 커지는 퇴화가 생길 수 있다.
  • 혼합형 변수에 연속 분포 하나를 맞추는 것. 0이 많은 강수량·농도·판매량 데이터에 정규분포나 로그정규분포를 바로 맞추면 0의 질량을 표현할 수 없다. 이산 부분과 연속 부분을 나누어 모델링한다.
  • 변환한 뒤의 평균을 변환 전 평균의 함수로 계산하는 것. E[g(X)]≠g(E[X])\mathbb{E}[g(X)] \neq g(\mathbb{E}[X])다. 분위수는 단조 변환을 통과하지만 평균과 최빈값은 통과하지 않는다.

통과 기준

  • 임의의 분포에 대해 PDF(또는 PMF)·CDF·quantile function의 관계를 식과 그림으로 설명하고, 구간 확률을 CDF로 계산한다.
  • 단조 변환 Y=g(X)Y = g(X)의 밀도를 변수변환 공식으로 유도하고, 표본 히스토그램과 비교해 확인한다.
  • 연습문제 empirical-cdf-quantile의 테스트를 통과한다.