확률분포(Probability Distribution)는 확률변수가 가질 수 있는 값과 그 확률을 나타내는 함수입니다. 데이터가 어떤 분포를 따르는지 이해하면, 이상치 판단, 가설검정, 모델 선택의 이론적 근거를 확보할 수 있습니다.
학습 목표
- 이산형과 연속형 확률분포의 차이를 이해한다
- 정규분포의 성질과 68-95-99.7 규칙을 설명할 수 있다
- 이항분포와 포아송분포를 적절한 상황에 적용할 수 있다
- 중심극한정리의 의미와 실무적 중요성을 설명할 수 있다
- QQ-plot으로 데이터의 정규성을 시각적으로 판단할 수 있다
왜 중요한가
많은 통계 기법과 머신러닝 알고리즘은 데이터가 특정 분포를 따른다고 가정합니다. 예를 들어, 선형회귀는 잔차가 정규분포를 따른다고 가정하고, 로지스틱회귀는 이항분포를 기반으로 합니다. 분포를 이해하면 이런 가정의 타당성을 검증할 수 있습니다.
정규분포
정규분포(Normal Distribution)는 평균을 중심으로 좌우 대칭인 종 모양(bell curve)의 분포입니다.
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
# 정규분포 생성
mu, sigma = 170, 10 # 평균 170cm, 표준편차 10cm
x = np.linspace(mu - 4*sigma, mu + 4*sigma, 1000)
pdf = stats.norm.pdf(x, mu, sigma)
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x, pdf, 'b-', linewidth=2, label='PDF')
# 68-95-99.7 규칙 시각화
for n_sigma, alpha, label in [(1, 0.3, '68.3%'), (2, 0.2, '95.4%'), (3, 0.1, '99.7%')]:
ax.fill_between(x, pdf, where=(x >= mu - n_sigma*sigma) & (x <= mu + n_sigma*sigma),
alpha=alpha, color='#4a9eca', label=f'{label} (+-{n_sigma}σ)')
ax.set_title('정규분포와 68-95-99.7 규칙')
ax.set_xlabel('키 (cm)')
ax.set_ylabel('확률 밀도')
ax.legend()
plt.tight_layout()
plt.show()
정규분포의 주요 성질
# 표준정규분포 (Z-분포): 평균=0, 표준편차=1
z = stats.norm(0, 1)
# 확률 계산
print(f"P(Z < 1.96) = {z.cdf(1.96):.4f}") # 누적분포함수
print(f"P(-1.96 < Z < 1.96) = {z.cdf(1.96) - z.cdf(-1.96):.4f}") # 95% 구간
# Z-score 변환: 원래 데이터 → 표준정규분포
heights = np.array([165, 170, 175, 180, 190])
z_scores = (heights - mu) / sigma
print(f"키 190cm의 Z-score: {z_scores[-1]:.1f}")
print(f"상위 {(1 - z.cdf(z_scores[-1]))*100:.1f}%에 해당")
# 역함수: 확률 → 값 (분위수)
print(f"상위 5% 기준: {stats.norm.ppf(0.95, mu, sigma):.1f}cm")
| 함수 | 설명 | 사용 예 |
|---|
pdf(x) | 확률밀도함수 | 특정 값의 상대적 가능성 |
cdf(x) | 누적분포함수 P(X ≤ x) | 특정 값 이하의 확률 |
ppf(q) | CDF의 역함수 | 주어진 확률에 해당하는 값 |
rvs(size) | 난수 생성 | 시뮬레이션 데이터 생성 |
이항분포
이항분포(Binomial Distribution)는 n번의 독립 시행에서 성공 횟수의 분포입니다.
# 불량률 5%인 제품 100개 중 불량품 수
n, p = 100, 0.05
binom = stats.binom(n, p)
x = np.arange(0, 20)
pmf = binom.pmf(x)
fig, ax = plt.subplots(figsize=(8, 5))
ax.bar(x, pmf, color='#4a9eca', alpha=0.7)
ax.set_title(f'이항분포 (n={n}, p={p})')
ax.set_xlabel('불량품 수')
ax.set_ylabel('확률')
plt.tight_layout()
plt.show()
# 확률 계산
print(f"평균 불량품 수: {binom.mean():.1f}개")
print(f"불량품이 정확히 5개일 확률: {binom.pmf(5):.4f}")
print(f"불량품이 10개 이상일 확률: {1 - binom.cdf(9):.4f}")
포아송분포
포아송분포(Poisson Distribution)는 단위 시간/공간에서 사건이 발생하는 횟수의 분포입니다.
# 하루 평균 3건의 고객 불만 접수
lam = 3
poisson = stats.poisson(lam)
x = np.arange(0, 15)
pmf = poisson.pmf(x)
fig, ax = plt.subplots(figsize=(8, 5))
ax.bar(x, pmf, color='#4a9e4a', alpha=0.7)
ax.set_title(f'포아송분포 (λ={lam})')
ax.set_xlabel('불만 건수')
ax.set_ylabel('확률')
plt.tight_layout()
plt.show()
print(f"하루 불만이 0건일 확률: {poisson.pmf(0):.4f}")
print(f"하루 불만이 7건 이상일 확률: {1 - poisson.cdf(6):.4f}")
| 분포 | 유형 | 적용 상황 | 파라미터 |
|---|
| 정규분포 | 연속형 | 키, 시험 점수, 오차 | 평균(mu), 표준편차(sigma) |
| 이항분포 | 이산형 | 합격/불합격, 클릭/미클릭 | 시행 수(n), 성공 확률(p) |
| 포아송분포 | 이산형 | 시간당 사건 수 | 평균 발생률(lambda) |
중심극한정리
중심극한정리(Central Limit Theorem, CLT)는 모집단의 분포에 관계없이, 표본 평균의 분포는 표본 크기가 충분히 크면 정규분포에 근사한다는 정리입니다.
np.random.seed(42)
# 원래 분포: 균등분포 (정규분포가 아님)
population = np.random.uniform(0, 100, 100000)
fig, axes = plt.subplots(2, 3, figsize=(15, 8))
# 원래 분포
axes[0, 0].hist(population, bins=50, color='#e6a23c', alpha=0.7)
axes[0, 0].set_title('모집단 (균등분포)')
# 표본 크기별 표본 평균의 분포
sample_sizes = [2, 5, 10, 30, 100]
for i, n in enumerate(sample_sizes):
row, col = (i + 1) // 3, (i + 1) % 3
sample_means = [np.mean(np.random.choice(population, n)) for _ in range(5000)]
axes[row, col].hist(sample_means, bins=50, color='#4a9eca', alpha=0.7)
axes[row, col].set_title(f'표본 평균 분포 (n={n})')
axes[row, col].axvline(np.mean(sample_means), color='red', linestyle='--')
plt.suptitle('중심극한정리: 표본 크기가 커질수록 정규분포에 근사')
plt.tight_layout()
plt.show()
표본 크기가 30 이상이면 중심극한정리가 일반적으로 적용됩니다. 원래 분포가 극단적으로 비대칭인 경우 더 큰 표본이 필요합니다.
QQ-plot — 정규성 검정
from scipy.stats import probplot
np.random.seed(42)
# 정규분포 데이터
normal_data = np.random.normal(100, 15, 200)
# 오른쪽 치우침 데이터
skewed_data = np.random.exponential(10, 200)
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 정규분포 QQ-plot
probplot(normal_data, dist="norm", plot=axes[0])
axes[0].set_title('정규분포 데이터 QQ-Plot')
# 편향된 데이터 QQ-plot
probplot(skewed_data, dist="norm", plot=axes[1])
axes[1].set_title('편향된 데이터 QQ-Plot')
plt.tight_layout()
plt.show()
# 정규성 검정 (Shapiro-Wilk test)
stat, p_value = stats.shapiro(normal_data)
print(f"정규분포 데이터 — Shapiro-Wilk p-value: {p_value:.4f}")
stat, p_value = stats.shapiro(skewed_data)
print(f"편향된 데이터 — Shapiro-Wilk p-value: {p_value:.4f}")
# p < 0.05이면 정규분포가 아니라고 판단
QQ-plot에서 점들이 대각선에 가까울수록 정규분포에 가깝습니다. 꼬리 부분이 벗어나면 두꺼운 꼬리(heavy tail)를, S자 형태면 편향을 의미합니다.
AI/ML에서의 활용
- 피처 정규화: 정규분포 가정이 필요한 모델(선형회귀, LDA)에서 피처의 정규성을 확인합니다
- 이상치 판단: 정규분포에서 3시그마(sigma) 밖의 값을 이상치로 판단합니다
- A/B 테스트: 중심극한정리를 이용하여 두 그룹의 평균 차이를 검정합니다
- 확률 모델링: 이항분포로 분류 문제의 확률을, 포아송분포로 이벤트 발생을 모델링합니다
- 히스토그램으로 시각적 확인, 2) QQ-plot으로 정규성 검정, 3) Shapiro-Wilk 또는 Kolmogorov-Smirnov 검정으로 통계적 확인. 실무에서는 시각적 확인과 통계 검정을 함께 사용합니다.
표본 크기가 너무 작거나(n < 30), 분포의 분산이 무한한 경우(코시 분포 등)에는 CLT가 잘 적용되지 않습니다. 극단적으로 편향된 분포에서는 더 큰 표본이 필요합니다.
체크리스트
다음 문서
가설검정
t-test, chi-square, ANOVA로 통계적 유의성을 검정합니다