1 양적 변수의 3 가지 입력 방법
Option 1 — Linear: \(X\) 자체를 입력. Logit 단위 선형 가정. \[\text{logit}(r) = \beta_0 + \beta_1 X\]
Option 2 — Categorical: \(X\) 를 카테고리로 분할 (예: tertiles, quintiles). \[\text{logit}(r) = \beta_0 + \sum_{j=2}^k \beta_j D_j\]
Option 3 — Spline: 비선형 매끄러운 함수. \[\text{logit}(r) = \beta_0 + s(X)\]
(Woodward, 2014, Ch.10.10).
1.1 직관 — 3 옵션의 trade-off
| 옵션 | 정보 활용 | 가정 강도 | 자유도 |
|---|---|---|---|
| Linear | 모든 정보 | 가장 강함 (logit 선형) | 1 |
| Categorical | 카테고리 정보만 | 가장 약함 | \(k-1\) |
| Spline | 모든 정보 | 매끄러움 | 4~10 |
- 추상: Linear 는 기울기 1 개로 모든 효과 표현 — 가정 강함 + 검정력 ↑.
- 일상어 비유: 시험 점수와 합격률 — 직선 가정 (모든 점수 차이가 동일 효과) vs 카테고리 분할 (구간별 차이 자유) vs spline (매끄러운 곡선).
- 반사실: 진성 패턴이 비선형이면 linear 가 misspecified. 진성이 선형이면 categorical 이 정보 손실. Spline 이 균형.
2 Option 1 — Linear (Logit 선형 가정)
\(\text{logit}(r) = \beta_0 + \beta_1 X\) 의 가정 — \(X\) 1 단위 증가가 logit 일정 단위 변화.
실패 시나리오: - 연령 30~50 사이 효과 ↑ (가속). - 50~70 사이 효과 ↓ (saturation).
→ 단일 \(\beta_1\) 가 평균 효과만 잡고 패턴 가림.
3 단계 직관:
- 추상: \(f(\text{age}) = \beta_1 \cdot \text{age}\) 가정. \(f\) 가 비선형이면 misspecified.
- 일상어 비유: 학년-점수 비선형 (1~6 학년 가속, 7~12 plateau) → 단일 기울기 부적합.
- 반사실: 비선형 변환 (\(\log X\), \(X^2\), spline) 적용. 진성 패턴 우선 시각화.
2.1 Logit 선형성 점검 도구
| 도구 | 메커니즘 |
|---|---|
| Quartile/decile plot | \(X\) 를 quartile 분할 후 각 quartile 의 log odds plot |
| Spline residual plot | Spline 모형의 잔차에서 비선형 패턴 식별 |
| Box-Tidwell test | \(X \cdot \log X\) 항 추가 후 유의성 검정 |
| GAM (Generalized Additive Model) | 자유 형태 적합 |
- 추상: 각 quartile 의 평균 \(X\) vs 그 quartile 의 log odds plot. 직선이면 linearity OK.
- 일상어 비유: 학년별 평균 점수 plot — 점이 직선에 가까우면 선형 관계.
- 반사실: U-shape, 곡선이면 spline 또는 quadratic 필요.
3 Option 2 — Categorical (Binning)
\(X\) 를 quantile (tertile, quartile, quintile) 또는 임상 임계값 (정상/경계/이상) 으로 분할.
각 카테고리 dummy 입력 → categorical logistic.
3.1 강점
- 가정 약함: 비선형 패턴 자유 표현.
- 임상 활용: 카테고리별 OR 가 임상 의사 결정에 직접 활용.
- 시각화: 효과 곡선 시각화 쉬움.
3.2 약점
같은 카테고리 안의 \(X\) 값들이 동일 처리 → dose-response 정보 폐기.
3 단계 직관:
- 추상: \(X = 30\) 과 \(X = 40\) 이 같은 카테고리에 들어가면 \(\beta\) 추정에 같은 영향. 진성 dose 차이 무시.
- 일상어 비유: 시험 점수 90 점과 99 점이 같은 “A 등급” 으로 묶임 — 점수 차이 정보 손실.
- 반사실: Categorical → linear → spline 순서로 정보 활용 ↑. 단 가정도 ↑.
3.3 Cut-point 선정의 함정
Cut-point 를 자료 본 후 결정 (예: 최대 OR 의 위치) → over-fitting + p-value 부정확.
해법: - 사전 임계값: 임상 표준 (예: BMI 25, 30) 또는 정책 기준. - 표본 분할: Train 에서 cut-point 결정, test 에서 검증. - Bootstrap: Cut-point 의 분포 추정.
4 Option 3 — Spline
연속 변수의 매끄러운 비선형 적합. 흔한 옵션:
Linear spline (knots): 임계점에서 기울기 변화 — piecewise linear.
Cubic spline: 각 구간 cubic 다항식 + 매끄러운 연결.
Restricted cubic spline (Harrell): 양 끝 linear → 외삽 안전.
Natural cubic spline: 양 끝 미분 0 가정.
4.1 Knot 의 위치
- 고정 위치: \(X\) 의 quintile (Harrell 권장 — 4 knots at p10, p25, p50, p75, p90).
- 자료 기반: Cross-validation 으로 최적 knot 수.
- 임상 임계값: 실무 의의 있는 위치.
3 단계 직관:
- 추상: Knot 수가 자유도 결정. 너무 적으면 underfit, 많으면 overfit.
- 일상어 비유: 곡선을 그릴 때 점의 수 — 적으면 직선화, 많으면 굴곡 과다.
- 반사실: 4 knots 가 표준 — Harrell 의 경험 권장. CV 가 자료 기반 대안.
4.2 Restricted Cubic Spline 의 우월성
- 추상: 양 끝의 linear 제약 → 자료 범위 외삽이 안정적.
- 일상어 비유: 곡선 양 끝을 직선으로 마무리 → 화면 밖 추세가 합리적.
- 반사실: 일반 cubic spline 은 양 끝에서 폭주 가능 → 외삽 위험.
5 시각화 — Effect Curve
import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
from patsy import dmatrix
np.random.seed(42)
n = 2000
# 가상: 진성 비선형 효과 (U-shape)
age = np.random.uniform(20, 80, n)
log_odds = -3 + 0.05 * (age - 50)**2 / 100 # U-shape around 50
prob = 1 / (1 + np.exp(-log_odds))
y = np.random.binomial(1, prob, n)
df = pd.DataFrame({"age": age, "y": y})
# 1. Linear
m_linear = sm.Logit(df["y"], sm.add_constant(df[["age"]])).fit(disp=0)
# 2. Categorical (quintile)
df["age_q"] = pd.qcut(df["age"], 5, labels=False)
m_cat = sm.Logit(df["y"], sm.add_constant(pd.get_dummies(df["age_q"], drop_first=True).astype(int))).fit(disp=0)
# 3. Restricted cubic spline (4 knots)
spline_X = dmatrix("cr(age, df=4) - 1", data=df, return_type="dataframe")
m_spline = sm.Logit(df["y"], sm.add_constant(spline_X)).fit(disp=0)
# AIC 비교
print("Model comparison (AIC):")
print(f" Linear: {m_linear.aic:.1f}")
print(f" Categorical (5 cat): {m_cat.aic:.1f}")
print(f" Spline (df=4): {m_spline.aic:.1f}")
# Effect curve 시각화
age_grid = np.linspace(20, 80, 100)
# Linear prediction
linear_pred = m_linear.predict(sm.add_constant(pd.DataFrame({"age": age_grid})))
# Spline prediction
spline_X_grid = dmatrix("cr(age, df=4) - 1", data=pd.DataFrame({"age": age_grid}), return_type="dataframe")
spline_pred = m_spline.predict(sm.add_constant(spline_X_grid))
plt.figure(figsize=(10, 6))
plt.plot(age_grid, linear_pred, label="Linear", linestyle="--")
plt.plot(age_grid, spline_pred, label="Spline (RCS df=4)", linewidth=2)
plt.scatter(df["age"], df["y"] * 0.05 + 0.45, alpha=0.05, s=2, label="Data")
plt.xlabel("Age")
plt.ylabel("Predicted P(Y=1)")
plt.legend()
plt.title("Linear vs Spline 적합")해석: U-shape 진성 패턴을 spline 이 잡고 linear 는 평균 기울기로 잘못 잡음. AIC 도 spline 이 우월.
6 A/B 테스트의 양적 변수 처리
A/B 테스트 사후 분석에서 사전 변수 (가입 후 일수, 사용량, 결제액) 의 입력.
- 추상: 사전 결제액 같은 right-skewed 변수는 종종 log 변환 + spline 이 유리.
- 일상어 비유: 부의 효과 — \(0\) vs \(\$100\) 가 큰 차이, \(\$10000\) vs \(\$10100\) 는 미미. log 단위가 자연.
- 반사실: Linear 입력 시 outlier 가 모형 좌우. Spline 이 robust.
6.1 Best Practice — Treatment 와 Continuous 의 Interaction
# Treatment × spline(pre_engagement)
df["treatment"] = np.random.binomial(1, 0.5, n)
df["pre_eng"] = np.random.normal(0, 1, n)
# Spline of pre_eng
spline_pre = dmatrix("cr(pre_eng, df=4) - 1", data=df, return_type="dataframe")
spline_pre.columns = [f"pre_s{i}" for i in range(spline_pre.shape[1])]
# Treatment × spline
for col in spline_pre.columns:
df[f"T_x_{col}"] = df["treatment"] * spline_pre[col]
X = sm.add_constant(pd.concat([df[["treatment"]], spline_pre,
df[[f"T_x_{c}" for c in spline_pre.columns]]], axis=1))
# 진성 데이터
log_odds = -2 + 0.3 * df["treatment"] + 0.5 * df["pre_eng"]
df["conversion"] = np.random.binomial(1, 1/(1+np.exp(-log_odds)), n)
m_hte = sm.Logit(df["conversion"], X).fit(disp=0)
# m_hte 의 lift = treatment 효과의 pre_eng 의 함수이 모형이 사전 활동량의 함수로서 lift 를 추정 — 비선형 HTE 의 본격 분석.
7 Restricted Cubic Spline (RCS) 의 자세
Cubic spline + 양 끝 linear 제약.
Knot 선정 (Harrell 권장): - 4 knots: percentiles 5, 35, 65, 95. - 5 knots: 5, 27.5, 50, 72.5, 95.
자유도: knots - 1.
- 추상 정의: Knot ↑ → 곡선 자유도 ↑ → 비선형 패턴 표현 ↑.
- 일상어 비유: 곡선 그릴 때 점의 수 — 4 점 충분, 10 점 과다.
- 반사실 시나리오: 4 knots 가 표준. 더 많이 = over-fit, 적게 = under-fit.
7.1 Spline vs Polynomial
Polynomial (\(X^2, X^3\)) 의 함정: - 양 끝의 폭주. - Knot 외 지역의 부정확. - Multicollinearity (X 와 X² 의 상관).
3 단계 직관:
- 추상 정의: Polynomial 이 global fit, spline 이 local fit. Local 이 robust.
- 일상어 비유: 큰 곡선 (polynomial) vs 작은 곡선 결합 (spline).
- 반사실 시나리오: Spline 이 RCS 의 안전. 단 임상 의의 임계값 명확 시 categorical 도 OK.
8 Box-Tidwell Test 의 활용
Logit linearity 점검:
추가 항 \(X \cdot \log X\) 입력 후 유의성 검정.
\[\text{logit}(\hat r) = \beta_0 + \beta_1 X + \beta_2 X \log X + \cdots\]
\(\beta_2\) 가 유의 → linearity 위반 → 변환 또는 spline.
- 추상 정의: \(X \log X\) 항이 비선형의 1 차 근사 검출.
- 일상어 비유: 곡선 패턴의 1 차 근사 — 직선 + 곡률 시그널.
- 반사실 시나리오: 검정 부족 시 spline + LR test 비교가 더 robust.
9 A/B 테스트의 양적 변수 처리
A/B 테스트의 사전 결제액 (skewed 분포):
import numpy as np
from patsy import dmatrix
# Log 변환 + spline
df["log_pre_purchase"] = np.log1p(df["pre_purchase"])
spline_X = dmatrix("cr(log_pre_purchase, df=4) - 1", data=df, return_type="dataframe")3 단계 직관:
- 추상 정의: 비선형 패턴 + skewed 분포 → log 변환 + spline.
- 일상어 비유: 부의 효과 — log 단위가 자연.
- 반사실 시나리오: Linear 입력 시 outlier 가 모형 좌우. Log + spline 이 robust.
10 결론
양적 변수의 3 옵션 (Linear / Categorical / Spline) 의 선택이 logistic 모형의 정확성을 결정. 진성 비선형성 의심 시 spline 우선. Logit 선형성 점검 도구 (quartile plot, Box-Tidwell) 가 1 차 진단. RCS (4 knots) 가 Harrell 권장 표준. Polynomial 의 양 끝 폭주 회피.
이로써 Ch.10 시리즈 (8 편) 가 마무리. 다음 묶음 (Ch.11 Cox/Survival, B-WOO11-0~9) 부터 시간-사건 분석의 모델링을 본다.
11 관련 주제
Phase H WOO Ch.10 시리즈 (완성)
다음 묶음 (WOO Ch.11)
- 1111-11-11, WOO Ch.11 overview — 추적 데이터 모델링
Statistics 크로스링크