1 개요
가설 검정에서 표본 크기를 결정하는 일반론은 표본 크기 결정에서 다루었다. 그 포스트는 단일/이표본 정규 검정, ANOVA, 비율 검정처럼 닫힌 형태의 공식이 존재하는 경우를 중심으로 한다.
회귀 분석에서는 상황이 달라진다. 파라미터 수 \(p\) , 효과 크기, 다중공선성, 클래스 불균형 등 여러 요인이 곱셈으로 결합되기 때문에 단순한 공식 하나로 끝나지 않는다. 이 포스트는 다음 질문에 답한다:
- “파라미터 1개당 10개”라는 규칙은 어디서 나오는가?
- 효과 크기가 작으면 왜 더 많은 샘플이 필요한가?
- 다중공선성이 있으면 필요 샘플 수는 어떻게 변하는가?
- 로지스틱 회귀에서는 왜 선형 회귀보다 더 많은 샘플이 필요한가?
- 경험칙과 검정력 분석 중 어느 것을 따라야 하는가?
2 파라미터당 10개 규칙의 유도
2.1 OLS 추정량의 분산 구조
회귀 모델 \(y = X\beta + \epsilon\) 에서 OLS 추정량의 공분산 행렬은 다음과 같다:
\[\text{Var}(\hat{\beta}) = \sigma^2 (X^\top X)^{-1}\]
파라미터가 \(p\) 개이고 샘플이 \(n\) 개이면, \(X\) 는 \(n \times p\) 행렬이다. \((X^\top X)^{-1}\) 의 대각 원소 — 각 추정량의 분산 — 이 안정적으로 추정되려면 \(n \gg p\) 이어야 한다.
직관적으로 이해하면: \(n = p\) 이면 \((X^\top X)\) 가 정방 행렬이 되어 데이터의 모든 자유도를 파라미터 추정에 소모한다. 잔차를 추정할 여유가 없으므로 과적합이 발생한다. \(n < p\) 이면 아예 역행렬이 존재하지 않는다.
2.2 F-검정 관점: 왜 “10”인가
회귀 전체 유의성의 F-통계량은 다음과 같다:
\[F = \frac{R^2 / p}{(1 - R^2) / (n - p - 1)}\]
분자 자유도는 \(p\) , 분모 자유도는 \(n - p - 1\) 이다. 분모 자유도가 충분히 커야 F-분포의 꼬리가 안정되고 검정이 검정력을 갖는다.
경험적으로 분모 자유도 \(\geq 10p\) 가 되려면:
\[n - p - 1 \geq 10p \implies n \geq 11p + 1 \approx 10p\]
여기서 “파라미터당 10개” 기준이 등장한다. 이 수치는 엄밀한 수학적 상수가 아니라, 자유도 기반 안정성 조건이 수렴하는 실용적 근사값이다.
2.3 잔차 분산의 안정성
각 계수 \(\hat{\beta}_j\) 의 표준오차는 다음과 같다:
\[\text{SE}(\hat{\beta}_j) = \sigma \sqrt{[(X^\top X)^{-1}]_{jj}}\]
실제 추정에 쓰이는 잔차 분산 \(\hat{\sigma}^2 = \frac{RSS}{n - p - 1}\) 은 자유도 \(n - p - 1\) 의 카이제곱 분포를 따른다. 이 자유도가 작을수록 \(\hat{\sigma}^2\) 추정이 불안정해지고, 그 불확실성이 \(\text{SE}(\hat{\beta}_j)\) 로 직접 전파된다.
\(n = 10p\) 이면 \(n - p - 1 \approx 9p\) 자유도다. \(p = 10\) 이면 자유도 90 — 카이제곱 분포의 분산 \(\text{Var}(\chi^2_\nu) = 2\nu\) 에 의해 상대적 변동이 \(\sqrt{2/90} \approx 15\%\) 수준으로, 실무적으로 안정적이다.
2.4 검정력 관점의 교차 확인
t-검정으로 \(H_0: \beta_j = 0\) 을 검정할 때, 통계량은 자유도 \(n - p - 1\) 의 t-분포를 따른다. \(\alpha = 0.05\) , 검정력 \(1 - \beta = 0.80\) 을 원하면 최소 자유도가 요구되며, 이를 역산하면 대략 \(n \approx 10p\) 에 해당하는 조건이 나온다.
| 관점 | 근거 | 결론 |
|---|---|---|
| F-검정 분모 자유도 | \(n - p - 1 \geq 10p\) | \(n \approx 10p\) |
| \(\hat{\sigma}^2\) 안정성 | 잔차 자유도가 충분해야 함 | \(n \gg p\) 경험칙 |
| 검정력 | \(\alpha = 0.05\) , power \(= 0.8\) 달성 | \(n \approx 10p\) 수준 |
세 관점이 독립적으로 같은 영역에 수렴한다는 사실이 이 경험칙의 근거다.
3 효과 크기와 비중심 분포
“파라미터당 10개”는 추정의 안정성만 보장한다. 추정이 안정적이라는 것은 “계수 값이 제대로 나온다”는 뜻이지, “효과가 있다는 결론을 내릴 수 있다”는 뜻이 아니다. 실제로 존재하는 효과를 탐지할 수 있는가는 별개의 질문이며, 이는 효과 크기에 의존한다.
3.1 비중심 t-분포와 검정력
\(H_1\) 하에서 t-통계량은 비중심 t-분포를 따른다:
\[T = \frac{\hat{\beta}_j}{\text{SE}(\hat{\beta}_j)} \sim t_{n-p-1,\;\lambda}\]
비중심 모수:
\[\lambda = \frac{\beta_j}{\text{SE}(\hat{\beta}_j)} = \frac{\beta_j \sqrt{n \cdot \text{Var}(x_j)}}{\sigma}\]
\(n\) 이 클수록 \(\text{SE}\) 가 작아지고 \(\lambda\) 가 커지며, 비중심 분포가 귀무 분포에서 멀어져 검정력이 올라간다. 이 관계가 “샘플이 많을수록 작은 효과도 탐지 가능”의 수학적 실체다.
검정력은 비중심 분포의 임계값 바깥 면적이다:
\[1 - \beta = P(|T| > t_{\alpha/2,\;\nu} \mid \lambda)\]
3.2 Cohen의 \(f^2\) 와 필요 샘플 수
다중 회귀에서 효과 크기를 표준화한 지표가 Cohen의 \(f^2\) 다:
\[f^2 = \frac{R^2}{1 - R^2}\]
직관적으로 \(f^2\) 는 “설명된 분산 대 설명되지 않은 분산의 비율”이다. \(R^2 = 0.13\) 이면 \(f^2 = 0.15\) 로, 잔차 분산 1 단위당 모델이 0.15 단위의 분산을 설명한다는 뜻이다. 이 비율이 작을수록 신호가 잡음에 묻혀 있어 탐지가 어렵다.
F-검정의 비중심 모수가 \(\lambda_F = f^2 \cdot n\) 이므로, 목표 검정력을 달성하는 데 필요한 비중심 모수 \(\lambda_F^*\) 가 상수이면:
\[n^* = \frac{\lambda_F^*}{f^2}\]
\(f^2\) 가 분모에 있으므로 효과 크기가 절반으로 줄면 필요 \(n\) 이 두 배가 된다. 이것이 효과 크기와 샘플 수의 역비례 관계다.
\(p = 10\) , \(\alpha = 0.05\) , 검정력 0.80 기준으로 구체적 수치를 보면:
| Cohen의 \(f^2\) | \(R^2\) 해석 | 필요 \(n\) |
|---|---|---|
| 0.02 | 작은 효과 ( \(R^2 \approx 0.02\) ) | 547 |
| 0.15 | 중간 효과 ( \(R^2 \approx 0.13\) ) | 89 |
| 0.35 | 큰 효과 ( \(R^2 \approx 0.26\) ) | 45 |
\(f^2 = 0.02\) 이면 \(n = 100\) 에서 실제 검정력은 약 0.30이다. 70%의 확률로 실제 존재하는 효과를 놓친다. “파라미터당 10개 = 100”으로 안심하면 작은 효과는 탐지하지 못한다.
from statsmodels.stats.power import FTestPower
def required_n(f2, alpha=0.05, power=0.80, num_params=10):
"""Cohen의 f²로부터 필요 샘플 수를 계산한다."""
analysis = FTestPower()
n = analysis.solve_power(
effect_size=f2**0.5,
alpha=alpha,
power=power,
df_num=num_params,
)
return int(n) + 1
print(required_n(f2=0.02)) # 547
print(required_n(f2=0.15)) # 89
print(required_n(f2=0.35)) # 454 다중공선성과 VIF 보정
4.1 VIF가 분산에 미치는 영향
다중공선성이 있으면 \((X^\top X)^{-1}\) 의 대각 원소가 팽창한다. 이것이 분산 팽창 인수(Variance Inflation Factor, VIF)로 정확히 표현된다:
\[\text{Var}(\hat{\beta}_j) = \frac{\sigma^2}{n \cdot \text{Var}(x_j)} \cdot \text{VIF}_j\]
\[\text{VIF}_j = \frac{1}{1 - R_j^2}\]
여기서 \(R_j^2\) 는 \(x_j\) 를 나머지 예측변수들로 회귀했을 때의 결정계수다.
직관적으로: VIF는 유효 샘플 수를 줄이는 효과를 낸다. VIF = 5 이면 1000개의 샘플 중 실질적으로 200개만 해당 변수의 독립적 추정에 기여하는 셈이다.
\[n_{\text{effective}} = \frac{n}{\text{VIF}_j}\]
4.2 VIF가 검정력에 미치는 영향
비중심 t-모수를 VIF로 다시 쓰면:
\[\lambda_j = \frac{\beta_j \sqrt{n \cdot \text{Var}(x_j)}}{\sigma \cdot \sqrt{\text{VIF}_j}}\]
\(\text{VIF}_j\) 가 분모 루트 안에 있으므로, 같은 검정력을 유지하려면:
\[n_{\text{required}} = n_{\text{no-collinearity}} \times \text{VIF}_j\]
\(f^2 = 0.15\) , \(p = 10\) , 검정력 0.80 기준:
| VIF | 해석 | 필요 \(n\) |
|---|---|---|
| 1 | 다중공선성 없음 | 89 |
| 2 | 약한 상관 ( \(R_j^2 = 0.50\) ) | 178 |
| 5 | 중간 상관 ( \(R_j^2 = 0.80\) ) | 445 |
| 10 | 강한 상관 ( \(R_j^2 = 0.90\) ) | 890 |
| 25 | 심각한 상관 ( \(R_j^2 = 0.96\) ) | 2,225 |
VIF = 10이면 \(n\) 의 90%가 공선성을 보완하는 데 소모되고, 10%만 실제 추정에 기여한다. 이것이 “같은 신호를 탐지하는 데 더 많은 관측이 필요해진다”의 정확한 의미다.
4.3 VIF 보정 공식
\[\boxed{n_{\text{required}} = n_{\text{base}} \times \text{VIF}_{\max}}\]
def required_n_with_vif(f2, vif_max, alpha=0.05, power=0.80, num_params=10):
"""VIF 보정을 포함한 필요 샘플 수를 계산한다."""
from statsmodels.stats.power import FTestPower
analysis = FTestPower()
n_base = analysis.solve_power(
effect_size=f2**0.5,
alpha=alpha,
power=power,
df_num=num_params,
)
n_adjusted = n_base * vif_max
return int(n_adjusted) + 1
print(required_n_with_vif(f2=0.15, vif_max=1)) # 89
print(required_n_with_vif(f2=0.15, vif_max=5)) # 445
print(required_n_with_vif(f2=0.15, vif_max=10)) # 890이 공식은 최악의 경우(가장 큰 VIF를 가진 변수)를 기준으로 하는 보수적 추정이다. 변수마다 VIF가 다를 때는 시뮬레이션이 더 정확하다.
4.4 시뮬레이션 기반 검정력 확인
import numpy as np
from scipy import stats
def simulate_power(n, p, beta, sigma, corr_matrix, alpha=0.05, n_sim=1000):
"""상관 구조가 있는 예측변수에서 F-검정의 시뮬레이션 검정력을 계산한다."""
reject_count = 0
for _ in range(n_sim):
X = np.random.multivariate_normal(
mean=np.zeros(p),
cov=corr_matrix,
size=n
)
y = X @ beta + np.random.normal(0, sigma, n)
XtX_inv = np.linalg.inv(X.T @ X)
beta_hat = XtX_inv @ X.T @ y
residuals = y - X @ beta_hat
RSS_full = residuals @ residuals
y_mean = y.mean()
SST = ((y - y_mean)**2).sum()
F = ((SST - RSS_full) / p) / (RSS_full / (n - p - 1))
f_crit = stats.f.ppf(1 - alpha, p, n - p - 1)
if F > f_crit:
reject_count += 1
return reject_count / n_sim
# VIF ~= 5 구조 (r = 0.8 상관관계)
p = 10
r = 0.8
corr = np.full((p, p), r)
np.fill_diagonal(corr, 1.0)
beta = np.array([0.3] * p)
sigma = 1.0
power_89 = simulate_power(n=89, p=p, beta=beta, sigma=sigma, corr_matrix=corr)
power_445 = simulate_power(n=445, p=p, beta=beta, sigma=sigma, corr_matrix=corr)
print(f"n=89 검정력: {power_89:.2f}") # ~0.30
print(f"n=445 검정력: {power_445:.2f}") # ~0.804.5 다중공선성 심각도별 전략
VIF 보정으로 샘플을 늘리는 것이 항상 최선은 아니다. VIF가 일정 수준을 넘으면 모델 변경이 샘플 증가보다 효율적이다.
| VIF 범위 | 해석 | 권장 전략 |
|---|---|---|
| 1 – 2 | 무시 가능 | 기본 \(n\) 사용 |
| 2 – 5 | 주의 | VIF 보정 \(n\) 계산 후 수집 가능성 확인 |
| 5 – 10 | 심각 | Ridge 회귀 전환 검토 |
| 10 이상 | 매우 심각 | PCA 변환 후 주성분 회귀, 또는 변수 제거 |
왜 VIF가 커지면 전략이 바뀌는가? VIF = 2 – 5 범위에서는 샘플을 2 – 5배 늘리는 것이 현실적으로 가능하다. 그러나 VIF = 10이면 샘플을 10배 늘려야 하므로, 데이터 수집 비용이 급격히 증가한다. 이 시점에서는 Ridge의 \(\ell_2\) 패널티로 \((X^\top X + \lambda I)^{-1}\) 을 안정화하는 편이 현실적이다. Ridge는 대각에 \(\lambda\) 를 더해 조건수를 낮추므로, 공선성에 의한 분산 팽창을 직접 억제한다. VIF가 10을 넘으면 변수 자체에 중복 정보가 과다하다는 신호이므로, PCA로 독립 성분을 추출하거나 변수를 제거하는 것이 근본적 해결이다.
5 로지스틱 회귀: EPV 규칙과 두 패널티의 결합
5.1 Events Per Variable (EPV)
로지스틱 회귀에서는 소수 클래스의 사건 수가 추정 안정성을 결정한다. 선형 회귀와 달리 로지스틱 회귀는 이산적 결과(0/1)를 다루기 때문에, 각 파라미터가 안정적으로 추정되려면 소수 클래스에 속하는 관측치(event)가 충분해야 한다. “Events Per Variable”이라는 이름은 바로 이것을 가리킨다 — 파라미터 하나당 소수 클래스의 사건이 몇 개 있는가.
Peduzzi et al. (1996)의 시뮬레이션에 따르면, EPV < 10이면 MLE가 수렴하지 않거나, 계수 추정값의 편향이 커지거나, complete separation(완전 분리 — 예측변수의 특정 조합이 결과를 완벽하게 구분하여 MLE가 무한대로 발산하는 현상)이 발생한다.
기본 EPV 규칙:
\[n_{\text{EPV}} = \frac{10 \cdot p}{\text{소수 클래스 비율}}\]
\(p = 10\) , 1:1 비율이면 \(n_{\text{EPV}} = 200\) 이다.
5.2 두 패널티의 곱셈 결합
로지스틱 회귀에서 다중공선성이 존재하면 두 개의 독립적 패널티가 동시에 작용한다:
\[n_{\text{required}} = \underbrace{\frac{10 \cdot p}{\text{소수 클래스 비율}}}_{\text{EPV 패널티}} \times \underbrace{\text{VIF}_{\max}}_{\text{다중공선성 패널티}}\]
왜 더하기가 아니라 곱하기인가? 비유로 설명하면: EPV 패널티는 “신호의 총 에너지를 줄이는” 효과이고, VIF 패널티는 “특정 채널의 잡음을 키우는” 효과다. 총 에너지가 반으로 줄고(\(\times 0.5\)), 동시에 특정 채널의 잡음이 5배 커지면(\(\times 5\)), 그 채널의 신호 대 잡음비는 \(0.5 \times \frac{1}{5} = 0.1\) 로 떨어진다. 두 효과가 서로 다른 경로로 작용하므로 곱셈으로 결합된다. 이것을 Fisher 정보행렬의 구조에서 확인할 수 있다:
\[\text{Var}(\hat{\beta}) \approx (X^\top W X)^{-1}\]
| 문제 | 영향 경로 | 결과 |
|---|---|---|
| 클래스 불균형 / 로지스틱 구조 | \(W = \text{diag}(\pi_i(1 - \pi_i))\) 값이 작아짐 | 정보행렬 전체가 스케일다운 |
| 다중공선성 | \(X^\top X\) 가 ill-conditioned | 특정 계수의 분산만 선택적으로 팽창 |
\(W\) 는 모든 계수에 균등하게 작용하고, VIF는 공선성에 연루된 계수에 선택적으로 작용한다. 서로 다른 메커니즘이므로 곱셈으로 결합된다.
5.3 \(p = 10\) , 1:1 비율, VIF별 수치
| VIF | 해석 | 필요 \(n\) | 파라미터당 |
|---|---|---|---|
| 1 | 다중공선성 없음 | 200 | 20 |
| 2 | 약한 상관 | 400 | 40 |
| 5 | 중간 상관 | 1,000 | 100 |
| 10 | 강한 상관 | 2,000 | 200 |
| 25 | 심각한 상관 | 5,000 | 500 |
VIF = 10이면 파라미터당 200개다. 선형 회귀에서 다중공선성 없는 경우(파라미터당 10개) 대비 20배이며, 이 수준이면 샘플 증가보다 Ridge 로지스틱 회귀나 변수 제거를 먼저 검토하는 것이 현실적이다.
5.4 로지스틱 시뮬레이션
import numpy as np
from scipy import stats
def logistic_simulate_power(n, p, beta, corr_matrix, alpha=0.05, n_sim=1000):
"""로지스틱 회귀에서 Wald 카이제곱 검정의 시뮬레이션 검정력을 계산한다."""
from sklearn.linear_model import LogisticRegression
reject_count = 0
for _ in range(n_sim):
X = np.random.multivariate_normal(np.zeros(p), corr_matrix, size=n)
log_odds = X @ beta
prob = 1 / (1 + np.exp(-log_odds))
y = np.random.binomial(1, prob)
model = LogisticRegression(fit_intercept=False, max_iter=1000, C=1e6)
model.fit(X, y)
beta_hat = model.coef_[0]
pi_hat = model.predict_proba(X)[:, 1]
W = np.diag(pi_hat * (1 - pi_hat))
info_matrix = X.T @ W @ X
try:
chi2_stat = beta_hat @ info_matrix @ beta_hat
chi2_crit = stats.chi2.ppf(1 - alpha, df=p)
if chi2_stat > chi2_crit:
reject_count += 1
except np.linalg.LinAlgError:
pass
return reject_count / n_sim
p = 10
beta = np.array([0.3] * p)
# 다중공선성 없음
corr_none = np.eye(p)
# VIF ~= 5 (r = 0.8)
r = 0.8
corr_high = np.full((p, p), r)
np.fill_diagonal(corr_high, 1.0)
power_200_none = logistic_simulate_power(n=200, p=p, beta=beta, corr_matrix=corr_none)
power_200_high = logistic_simulate_power(n=200, p=p, beta=beta, corr_matrix=corr_high)
power_1000_high = logistic_simulate_power(n=1000, p=p, beta=beta, corr_matrix=corr_high)
print(f"n=200, VIF=1: {power_200_none:.2f}") # ~0.80
print(f"n=200, VIF=5: {power_200_high:.2f}") # ~0.30
print(f"n=1000, VIF=5: {power_1000_high:.2f}") # ~0.805.5 세 요인의 통합 공식
\[\boxed{n_{\text{required}} = \frac{10 \cdot p}{\text{소수 클래스 비율}} \times \text{VIF}_{\max}}\]
| 요인 | 역할 | \(p = 10\) 기준 예시 |
|---|---|---|
| \(p\) | 추정 파라미터 수 | \(\times 10\) |
| 소수 클래스 비율 | 분모 — 비율이 낮을수록 \(n\) 증가 | 1:1이면 \(\div 0.5 = \times 2\) |
| \(\text{VIF}_{\max}\) | 다중공선성 패널티 | VIF = 5이면 \(\times 5\) |
세 요인이 모두 곱셈으로 작용하므로, VIF = 5 + 1:9 클래스 불균형이면:
\[n = \frac{10 \times 10}{0.1} \times 5 = 5{,}000\]
파라미터당 500개다.
6 경험칙 vs 검정력 분석: 두 기준의 관계
지금까지 경험칙(파라미터당 10개, EPV, VIF 보정)과 검정력 분석(비중심 분포 기반)을 각각 다루었다. 실무에서는 이 두 기준이 서로 다른 \(n\) 을 제시하는 경우가 흔하다. 어느 쪽을 따라야 하는가? 이를 이해하려면 두 기준이 애초에 다른 질문에 답한다는 점을 인식해야 한다.
6.1 목적 자체가 다르다
| 경험칙 (EPV, \(p \times 10\) , VIF 보정) | 검정력 기반 샘플 수 계산 | |
|---|---|---|
| 목적 | 추정의 안정성 보장 | 특정 효과 탐지 확률 보장 |
| 질문 | “계수를 신뢰할 수 있게 추정할 수 있는가?” | “존재하는 효과를 탐지할 확률이 충분한가?” |
| 효과 크기 | 고려 안 함 | 명시적으로 지정 |
| 근거 | 점근 이론 + 시뮬레이션 경험칙 | 비중심 분포 이론 |
| 출력 | 최소 안정성 조건 | 목표 검정력을 보장하는 \(n\) |
6.2 경험칙이 보장하는 것
EPV \(\geq 10\) , \(n \geq 10p\) 류의 규칙은 추정 가능성(estimability)을 보장한다. 이 조건 미만에서 발생하는 문제:
- MLE가 수렴하지 않거나 complete separation 발생
- 계수 추정값의 편향이 커짐 (Peduzzi et al., 1996)
- 신뢰구간이 너무 넓어 실용적으로 무의미
- Wald 검정의 점근 정규 근사가 성립하지 않음
경험칙은 “이 \(n\) 이하면 통계 결과 자체를 믿을 수 없다”는 최소 조건이다. 비유하면 자동차의 최소 연료량과 같다 — 연료가 부족하면 출발 자체가 불가능하지만, 연료가 충분하다고 해서 목적지에 도착할 수 있는 것은 아니다.
6.3 검정력 분석이 보장하는 것
\[1 - \beta = P(\text{reject } H_0 \mid \beta = \delta)\]
추정이 완벽하게 안정적이더라도 효과가 작으면 검정력이 낮아 탐지에 실패한다. 이것은 경험칙과 독립적인 질문이다.
6.4 같은 \(n\) 에서 두 기준이 엇갈리는 경우
Case 1: 경험칙 통과, 검정력 부족
\(p = 10\) , 1:1 비율, 다중공선성 없음이면 EPV 기준 \(n = 200\) 으로 충분하다. 그러나 효과 크기가 작으면 ( \(f^2 = 0.02\) ):
\[n_{\text{power}} = \frac{\lambda^*}{f^2} \approx \frac{12.4}{0.02} \approx 620\]
\(n = 200\) 에서 실제 검정력 \(\approx 0.30\) 이다. 추정은 안정적이지만 효과를 탐지하지 못한다.
Case 2: 검정력 충족, 경험칙 미달
효과가 매우 크면 ( \(f^2 = 1.0\) ):
\[n_{\text{power}} \approx 25\]
검정력 분석은 \(n = 25\) 로 충분하다고 하지만, EPV 기준은 \(n \geq 200\) 을 요구한다. \(n = 25\) 에서 MLE 편향과 수렴 문제가 발생할 수 있다.
6.5 두 조건의 관계
\[n_{\text{final}} = \max(n_{\text{경험칙}},\ n_{\text{power}})\]
경험칙은 필요조건 (이 이하면 결과를 믿을 수 없음), 검정력 분석은 충분조건 (이 이상이면 목표 검정력 달성)이다. 최종 샘플 수는 두 조건 중 더 큰 값을 취한다.
| 상황 | 구속 기준 | 이유 |
|---|---|---|
| 효과 크기 크다 ( \(f^2 \geq 0.35\) ) | 경험칙 | 검정력은 소수 샘플로도 충족, 추정 안정성이 병목 |
| 효과 크기 작다 ( \(f^2 \leq 0.05\) ) | 검정력 | 추정은 안정적이어도 신호가 약해 탐지 실패 |
| 다중공선성 심각 (VIF \(\geq 5\) ) | 경험칙 | VIF 보정이 검정력 요건보다 빠르게 증가 |
| 클래스 불균형 심각 (1:19 이상) | 경험칙 | EPV 패널티가 지배적 |
def final_n(p, f2=None, minority_ratio=0.5, vif_max=1.0,
model='logistic', alpha=0.05, power=0.80):
"""경험칙과 검정력 분석 중 더 큰 값을 반환한다."""
if model == 'logistic':
n_heuristic = (10 * p / minority_ratio) * vif_max
else:
n_heuristic = 10 * p * vif_max
if f2 is not None:
from statsmodels.stats.power import FTestPower
n_power = FTestPower().solve_power(
effect_size=f2**0.5, alpha=alpha,
power=power, df_num=p
) * vif_max
else:
n_power = 0
n_final = max(n_heuristic, n_power)
binding = '경험칙' if n_heuristic >= n_power else '검정력'
return int(n_final) + 1, binding
# 효과 크기 큰 경우 -- 경험칙이 구속
print(final_n(p=10, f2=0.35, model='logistic'))
# (200, '경험칙')
# 효과 크기 작은 경우 -- 검정력이 구속
print(final_n(p=10, f2=0.02, model='logistic'))
# (621, '검정력')7 실무 4단계 파이프라인
7.1 Step 1: 효과 크기 추정
가장 어렵고 가장 중요한 단계다. 효과 크기의 추정 방법을 신뢰도 순으로 나열하면:
| 방법 | 신뢰도 | 설명 |
|---|---|---|
| 자체 Pilot Study | 높음 | 동일 모집단, 동일 측정 |
| Meta-analysis | 높음 | 여러 연구의 효과 크기 풀링 |
| 유사 선행 연구 | 중간 | 모집단/측정 차이로 편향 가능 |
| MDES (Minimum Detectable Effect Size) | 중간 | 의미 있는 최소 효과를 역산 |
| Cohen 관행값 | 낮음 | 최후 수단 |
MDES 접근은 “이 효과가 실무적으로 의미 있으려면 최소 얼마여야 하는가?”를 먼저 정의하고, 그 값을 효과 크기로 사용한다. Cohen 관행값(small/medium/large)은 분야와 무관한 일반적 기준이라 특정 연구의 맥락을 반영하지 못한다. 반면 MDES는 “이 크기 이하의 효과는 발견해도 실무적 의미가 없다”는 도메인 지식에 기반하므로, 연구 설계에 더 적합한 근거를 제공한다. 예: 로지스틱 회귀에서 OR \(= 1.5\) 이상이면 임상적으로 유의미하다고 판단하면, \(\beta_{\min} = \log(1.5)\) 를 효과 크기로 설정한다.
7.2 Step 2: 공식 검정력 분석
선형 회귀:
from statsmodels.stats.power import FTestPower
n = FTestPower().solve_power(
effect_size=f2**0.5,
alpha=0.05,
power=0.80,
df_num=p,
)로지스틱 회귀 — 닫힌 형태 공식이 없으므로 시뮬레이션을 권장한다:
import numpy as np
from sklearn.linear_model import LogisticRegression
from scipy import stats
def logistic_power_by_simulation(n, p, beta_true, prev=0.5,
alpha=0.05, n_sim=2000):
"""로지스틱 회귀 검정력을 시뮬레이션으로 추정한다."""
reject = 0
intercept = np.log(prev / (1 - prev))
for _ in range(n_sim):
X = np.random.randn(n, p)
log_odds = intercept + X @ np.array([beta_true] * p)
prob = 1 / (1 + np.exp(-log_odds))
y = np.random.binomial(1, prob)
if y.sum() < 5 or (1 - y).sum() < 5:
continue
model = LogisticRegression(max_iter=1000, C=1e6)
model.fit(X, y)
beta_hat = model.coef_[0]
pi_hat = model.predict_proba(X)[:, 1]
W = np.diag(pi_hat * (1 - pi_hat))
info = X.T @ W @ X
try:
chi2 = beta_hat @ info @ beta_hat
if chi2 > stats.chi2.ppf(1 - alpha, df=p):
reject += 1
except np.linalg.LinAlgError:
pass
return reject / n_sim
# n을 바꿔가며 검정력 0.80 달성 지점 탐색
for n in [100, 200, 300, 400, 500]:
pw = logistic_power_by_simulation(n=n, p=10, beta_true=0.3)
print(f"n={n:4d} -> power={pw:.2f}")7.3 Step 3: 경험칙 교차 확인
Step 2의 결과와 경험칙을 비교하여 \(\max\) 를 취한다.
7.4 Step 4: 민감도 분석 + 여유분
효과 크기 추정이 틀렸을 때를 대비해 비관적 시나리오로 재계산한다:
f2_estimated = 0.15
for ratio in [0.50, 0.75, 1.00]:
f2_scenario = f2_estimated * ratio
n, binding = final_n(p=10, f2=f2_scenario, model='logistic')
print(f"효과 크기 {ratio*100:.0f}%: f2={f2_scenario:.3f} -> n={n} ({binding})")여유분 가이드라인:
| 상황 | 여유분 |
|---|---|
| 탈락/결측 예상 | +10 – 20% |
| 측정 오류 가능성 높음 | +15 – 25% |
| 규제 제출용 (FDA/EMA) | 검정력 0.90 이상 사용 |
| 탐색적 연구 | 검정력 0.80으로 충분 |
8 도메인별 실무 관행
| 분야 | 주된 방법 | 특이사항 |
|---|---|---|
| 임상시험 | 공식 검정력 분석 필수 | FDA/EMA 규정상 프로토콜에 명시 |
| 역학 연구 | EPV 기준 + 검정력 교차 확인 | 로지스틱 회귀가 주류 |
| 사회과학 | G*Power | Cohen 관행값 남용 주의 |
| 산업 ML | 시뮬레이션 | 대용량 데이터로 커버하는 경우가 많다 |
| A/B 테스트 | MDE 역산 + 검정력 | 비즈니스 임팩트 기반 MDES 정의 |
9 요약
효과 크기는 MDES 또는 Pilot Study로 추정하고, 검정력 분석과 경험칙의 최댓값을 취한 뒤, 비관적 시나리오로 민감도 분석을 거쳐 10 – 20% 여유분을 더한다.
\[n_{\text{final}} = \max\!\left(\underbrace{\frac{10p}{\text{minority ratio}} \times \text{VIF}}_{\text{경험칙}},\quad \underbrace{\frac{\lambda^*}{f^2} \times \text{VIF}}_{\text{검정력}}\right) \times (1 + \text{여유분})\]
10 관련 주제
선행 지식
관련 개념
- 다중 검정 보정 — 다중 비교 시 유의수준 조정
- 제곱합 분해 — F-검정의 분모/분자 구성
- \(X^\top X\) 가 왜 분산인가 — OLS 분산 구조의 선형대수적 배경