Propensity Score Matching (PSM)
정의
성향점수 매칭(propensity score matching, PSM)은 성향점수(propensity score)가 비슷한 처치군과 대조군 개인을 짝지어 처치효과(treatment effect)를 추정하는 매칭(matching) 방법이다.
여기서 는 성향점수다.
직관적 이해
성향점수로 매칭하는 근거
Rosenbaum & Rubin (1983):
- 성향점수가 같으면 처치 확률이 같다.
- 따라서 고차원(high-dimensional) 대신 스칼라 만으로 매칭할 수 있다.
- 차원 축소: 차원의 저주(curse of dimensionality)를 완화한다.
예시
| 환자 | 나이 | 성별 | 병력 | PS |
|---|---|---|---|---|
| A (처치) | 45 | M | 고혈압 | 0.72 |
| B (대조) | 52 | F | 당뇨 | 0.70 |
는 다르지만 가 비슷하므로 매칭할 수 있다.
절차
1단계: 성향점수 추정
추정에 흔히 쓰는 방법은 다음과 같다.
- Logistic regression (가장 일반적)
- Random forest
- Gradient boosting
- Neural network
2단계: 매칭
각 처치군 개인마다 성향점수가 가장 비슷한 대조군을 찾는다.
For each treated unit i:
Find control j* with |e(Xi) - e(Xj)| minimized
Match (i, j*)
3단계: 효과 추정
매칭 옵션
1. Caliper
매칭 허용 거리에 상한을 둔다.
일반적으로 로 둔다.
2. 1:k Matching
처치 1명당 대조 k명을 매칭한다.
- k=1: 표준 설정이다.
- k>1: 분산(variance)은 줄지만 편향(bias)이 커질 수 있다.
3. With/Without Replacement
| 옵션 | 장점 | 단점 |
|---|---|---|
| With | 좋은 매칭, 편향↓ | 분산↑, 일부 대조군 과다 사용 |
| Without | 분산↓, 공정 | 매칭 품질↓ |
장점과 한계
장점
| 장점 | 설명 |
|---|---|
| 차원 축소 | 고차원 X를 스칼라 성향점수로 요약한다 |
| 직관성 | ”처치 확률이 비슷한 개인끼리 비교”라는 해석이 명확하다 |
| 투명성 | 매칭된 쌍을 직접 검토할 수 있다 |
| 유연성 | 다양한 매칭 옵션을 적용할 수 있다 |
한계
| 한계 | 설명 |
|---|---|
| 성향점수 모델 의존 | 성향점수를 잘못 설정하면 편향이 생긴다 |
| 정보 손실 | 매칭되지 않은 표본을 제외한다 |
| 분산 | IPW보다 효율이 낮을 수 있다 |
| 매칭 품질 | 나쁜 매칭이 만들어질 수 있다 |
품질 평가
균형 확인
매칭 후 두 군의 공변량(covariate) 분포가 얼마나 비슷한지 비교한다.
기준: 이면 균형이 잡힌 것으로 본다.
시각화
import matplotlib.pyplot as plt
# 매칭 전후 PS 분포
plt.subplot(1, 2, 1)
plt.hist(ps[W==1], alpha=0.5, label='Treated')
plt.hist(ps[W==0], alpha=0.5, label='Control')
plt.title('Before Matching')
plt.subplot(1, 2, 2)
plt.hist(ps_matched[W_matched==1], alpha=0.5, label='Treated')
plt.hist(ps_matched[W_matched==0], alpha=0.5, label='Control')
plt.title('After Matching')
구현
R (MatchIt)
library(MatchIt)
# PSM with 1:1 nearest neighbor
m.out <- matchit(treat ~ x1 + x2 + x3,
data = df,
method = "nearest",
distance = "logit",
caliper = 0.2)
# 균형 확인
summary(m.out)
# 매칭 데이터
matched_data <- match.data(m.out)
# ATT 추정
lm(y ~ treat, data = matched_data, weights = weights)
Python
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import NearestNeighbors
# PS 추정
lr = LogisticRegression()
lr.fit(X, W)
ps = lr.predict_proba(X)[:, 1]
# 매칭
treated_idx = np.where(W == 1)[0]
control_idx = np.where(W == 0)[0]
nn = NearestNeighbors(n_neighbors=1)
nn.fit(ps[control_idx].reshape(-1, 1))
distances, matches = nn.kneighbors(ps[treated_idx].reshape(-1, 1))
# ATT 추정
att = np.mean(Y[treated_idx] - Y[control_idx[matches.flatten()]])
관련 개념
- Matching Methods Overview - 매칭 방법 통합
- Propensity Score - 핵심 도구
- Nearest Neighbor Matching - 일반 NNM
- ATT - PSM의 주요 추정 대상
- Selection Bias - 해결 대상
참고 논문
- Rosenbaum, P. R., & Rubin, D. B. (1983). The central role of the propensity score
- yaoSurveyCausalInference2021 - Section 3.3
- Caliendo, M., & Kopeinig, S. (2008). Some practical guidance for PSM