PSM·DiD·도구 변수로 관찰 데이터의 인과효과 추정하기

관찰 데이터에서 정책과 제품 변경의 효과를 추정할 때 PSM, DiD, 도구 변수의 가정·진단·활용 방식을 정리한다.

2026-08-14 · 최초 발행 2025-10-14

실험이 어려운 환경에서는 정책이나 프로덕트 변경 전후의 차이를 그대로 효과로 읽기 어렵다. 처치 여부가 무작위로 정해지지 않았다면, 관찰된 결과에는 선택 편향과 내생성이 섞여 있을 수 있다. PSM, DiD, 도구 변수는 이런 관찰 데이터에서 반사실을 근사하기 위한 대표적인 식별 전략이다.

인과 효과는 처치가 결과에 만든 평균 차이인 ATE 또는 ATT를 추정하는 문제로 볼 수 있다. 잠재 결과 프레임에서는 각 개체가 처치를 받았을 때와 받지 않았을 때의 결과를 함께 상정하지만, 현실에서는 둘 중 하나만 관찰된다. 세 기법은 보이지 않는 반사실을 서로 다른 방식으로 가까이 간다.

관찰 데이터를 설계로 바꾸는 방법

PSM은 관측된 공변량을 이용해 처치 배정을 무작위 배정에 가깝게 재구성하려는 매칭 설계다. DiD는 처치와 통제 집단의 시간상 변화를 비교해 공통 추세를 제거한다. IV는 처치와 결과 사이의 내생성을 피하기 위해 외생적 변동을 제공하는 도구를 활용하며, 2단계 추정으로 효과를 구한다.

성향 점수로 비교 가능한 집단 만들기

PSM은 조건부 무작위성과 공통 지지를 전제로 한다. 관측 공변량을 조건으로 했을 때 처치 배정이 독립적이어야 하며, 처치·통제 집단이 겹치는 공통 지지 영역도 확보되어야 한다.

일반적인 흐름은 성향 점수 추정, 근접 이웃·칼리퍼·커널 방식의 매칭, 균형성 확인, ATT 또는 ATE 추정으로 이어진다. 균형성은 SMD<0.1을 권고 기준으로 볼 수 있다. 매칭을 더 엄격하게 적용하면 편향은 줄어들 수 있지만 분산은 커지고 표본 손실도 발생한다. 대규모 데이터에서는 매칭 비용도 고려 대상이다.

시간 차이를 활용하는 DiD

DiD는 처치 집단과 통제 집단이 처치 이전에 같은 방향으로 움직였다는 병행 추세 가정에 기대고 있다. 여기에 충격의 외생성과 집단 간 간섭 부재도 필요하다.

사전·사후 차이를 구한 뒤 집단 간 차이를 한 번 더 비교하며, 고정효과와 클러스터-강건 표준오차를 적용하고 사전 추세를 점검한다. 처치 시점이 집단마다 다른 계단식 도입에서는 이벤트 스터디와 현대적 가중 DiD 추정량이 필요하다. Sun & Abraham, Callaway & Sant’Anna 등이 이 맥락에서 언급된다.

내생성을 분리하는 도구 변수

IV 설계는 도구 변수의 관련성, 외생성, 배제 제한, 단조성을 요구한다. 단조성은 추정 결과가 국지적 평균 처리효과인 LATE로 해석된다는 조건과 연결된다.

먼저 도구가 처치에 충분한 영향을 주는지 1단계에서 확인하고, 예측된 처치값으로 결과를 추정하는 2단계를 수행한다. 1단계 F-통계량은 ≈10 이상을 권고하며, 과식별 상황에서는 Sargan/Hansen 검정을 사용할 수 있다. 약한 도구는 표준오차를 키우고 추정을 불안정하게 만들며, IV 결과는 LATE 범위에서 해석해야 한다.

추정값보다 먼저 확인할 진단 항목

PSM에서는 매칭 뒤 공변량 균형성(SMD, Love plot), 공통 지지 영역, 매칭 뒤 모델 의존성을 점검한다. 관측되지 않은 요인은 매칭으로 해결할 수 없으므로, 대리변수의 품질도 설계의 일부가 된다.

DiD에서는 처치 이전의 추세를 시각화하고 검정해야 한다. 처리 시점이 이질적인 경우에는 이를 반영한 추정량을 사용하며, 시간·개체 고정효과와 집락 표준오차를 함께 검토한다.

IV는 1단계 강도(F)를 확인하는 것으로 끝나지 않는다. 도구가 결과에 직접 영향을 주지 않는다는 배제 제한은 도메인 지식으로 정당화해야 하며, 과식별 검정과 방향성 민감도 분석도 함께 본다.

사양을 바꿔도 결과가 유지되는지 확인하는 과정도 필요하다. 공변량 세트, 매칭 알고리즘, 칼리퍼, 가중 방식을 바꿔볼 수 있고, 가짜 처치 시점이나 가짜 결과를 쓰는 위약·허위 테스트로 위양성을 확인할 수 있다. 결측과 이상치 처리에서는 전처리 기준을 사전 등록하고, 승산(trim)·윈저라이징·중앙값 회귀 등을 보조 분석으로 둘 수 있다.

제품과 정책 데이터에서의 선택

추천 배너 노출이 구매에 미친 영향을 알고 싶다면 PSM을 적용할 수 있다. 사용자 속성과 활동 로그로 성향 점수를 구하고, 1:1 최근접+칼리퍼 매칭 뒤 균형성을 확인해 ATT를 산출한다. 리치나 활동성처럼 관측되지 않은 요인에 대한 대리변수를 확보하고, 공통 지지 영역 밖 표본을 제외하는 일이 중요하다.

수수료 인하 정책이 거래량에 미친 영향은 DiD 설계에 맞는다. 도입 전후 패널 데이터를 사용해 처리·통제 지역의 병행 추세를 검정하고, 이중차분 고정효과 모형을 적용한다. 계단식 도입에서는 현대적 DiD 추정량을 사용하며, 집락 표준오차는 정책 단위로 집락화한다.

가격과 수요가 프로모션이나 수요 충격 때문에 동시에 움직이는 상황에서는 IV가 후보가 된다. 비용 쇼크나 환율 같은 외생적 도구 변수를 활용해 2SLS로 탄력성을 추정한다. 도구의 배제 제한을 정당화하고 약한 도구를 피하며, 장기·단기 효과를 분해해야 한다.

신규 랭킹 알고리즘을 일부 트래픽에 순차 배포하는 경우에는 사전 매칭과 DiD를 결합할 수 있다. 먼저 매칭으로 집단을 정렬하고, 도입 전후 DiD로 추정 편향을 추가로 줄인다. 이때 공변량 드리프트를 모니터링하고 스플라인이나 시간 상호작용으로 시간적 이질성을 흡수한다.

기대할 수 있는 개선 범위

매칭 뒤 공변량 불균형(SMD)을 0.2→0.05 수준으로 개선하는 것을 목표로 둘 수 있다. DiD에서는 사전 추세 비유의 p>0.1, IV에서는 1단계 F≥10 확보가 식별 신뢰도를 높이는 기준이 된다.

추정 편차를 줄여 ROI 추정 오차를 ±30%→±10%로 개선하는 효과를 기대할 수 있다. 제한된 A/B 테스트를 대체하거나 보완하고, 실험이 불가능한 영역에서도 정책을 빠르게 평가할 수 있다는 운영상 이점도 있다.

방법별 제약과 해석 범위

지표 PSM DiD IV
식별 가정 일관성 관측 혼란변수 통제 가정 중요, 공통 지지 필요 병행 추세 핵심, 외생적 쇼크 필요 배제 제한·외생성·관련성 충족 필요
안정성(민감도) 매칭 사양에 민감, 균형성에 좌우 사전 추세 위반에 취약 약한 도구에 취약, 표준오차 증가
확장성/표본 표본 손실 가능, 대규모 매칭 비용 존재 패널/반복 단면 필요, 확장 용이 유효 도구 확보가 병목
해석 용이성 ATT/ATE 직관적 차분 기반, 시각화 용이 LATE 중심, 해석 주의
운영 편의 전처리·튜닝 요구 로그/모니터링 체계와 궁합 좋음 도구 탐색·정당화 비용 큼

데이터 제약에 따라 식별 전략 고르기

가능불가아니오가능불가아니오입력 데이터- 처치 D, 결과 Y- 공변량 X- 시간 T(선택)무작위 실험 가능성RCT 설계 권장실험 실행관측 공변량으로 배정 설명 가능PSM 설계- 성향 점수 추정- 매칭/가중- 균형성 진단패널/반복 단면 병행 추세가정 가능DiD 설계- 전/후·집단 차분- 사전 추세 검정- FE+클러스터 SE외생적 도구 변수 확보IV(2SLS) 설계- 1단계 강도(F) 확인- 2단계 추정- 과식별 검정부분 식별/경계 분석- Bounds·감도 분석강건성·감도 분석출력- 효과 추정치/신뢰구간- 진단 리포트

Python으로 확인하는 PSM·DiD·IV

전제조건: Python 3.10+, pandas 2.x, numpy 1.26+, scikit-learn 1.3+, statsmodels 0.14+, linearmodels 5.x
설치: pip install pandas numpy scikit-learn statsmodels linearmodels

성향 점수 추정과 매칭 뒤 균형성 확인

import numpy as np, pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import NearestNeighbors

# 가상 데이터
np.random.seed(42)
n = 5000
X1 = np.random.normal(size=n)
X2 = np.random.binomial(1, 0.4, size=n)
prop = 1/(1+np.exp(-(0.8*X1 - 0.5*X2)))
D = np.random.binomial(1, prop)  # 처치
# 결과: 진짜 효과 2.0, 공변량 효과 포함
Y = 2.0*D + 1.5*X1 - 1.0*X2 + np.random.normal(scale=1.0, size=n)
df = pd.DataFrame({"Y":Y, "D":D, "X1":X1, "X2":X2})

# 성향 점수 추정
lr = LogisticRegression(max_iter=1000)
lr.fit(df[["X1","X2"]], df["D"])
ps = lr.predict_proba(df[["X1","X2"]])[:,1]
df["ps"] = ps

# 최근접 1:1 매칭(칼리퍼 적용)
treated = df[df.D==1].copy()
control = df[df.D==0].copy()
nn = NearestNeighbors(n_neighbors=1)
nn.fit(control[["ps"]])
dist, idx = nn.kneighbors(treated[["ps"]])
caliper = 0.05
matched_pairs = []
for i, (d, j) in enumerate(zip(dist[:,0], idx[:,0])):
    if d <= caliper:
        matched_pairs.append((treated.index[i], control.index[j]))
midx_t = [i for i,_ in matched_pairs]
midx_c = [j for _,j in matched_pairs]
m_t = df.loc[midx_t]
m_c = df.loc[midx_c]

# ATT 추정
att = (m_t["Y"].values - m_c["Y"].values).mean()
print(f"ATT (PSM): {att:.3f}, 매칭쌍: {len(midx_t)}")

# 균형성 점검: 표준화 평균 차(SMD)
def smd(x_t, x_c):
    mt, mc = x_t.mean(), x_c.mean()
    st = x_t.std(ddof=1); sc = x_c.std(ddof=1)
    return (mt - mc)/np.sqrt((st**2 + sc**2)/2)
for col in ["X1","X2","ps"]:
    print(col, round(smd(m_t[col], m_c[col]), 3))

공변량 SMD 절대값은 0.1 이하를 목표로 두고, 칼리퍼 변화에 따른 민감도도 확인한다.

고정효과 회귀로 DiD 추정하기

import pandas as pd, numpy as np
import statsmodels.api as sm
from linearmodels.panel import PanelOLS

# 가상 패널: 개체 i, 시간 t
np.random.seed(0)
N, T = 500, 6
ids = np.arange(N)
times = np.arange(T)
panel = [(i,t) for i in ids for t in times]
df = pd.DataFrame(panel, columns=["id","t"])
# 처리 집단과 도입 시점
treated_ids = np.random.choice(ids, size=N//2, replace=False)
df["treated"] = np.isin(df["id"], treated_ids).astype(int)
df["post"] = (df["t"] >= 3).astype(int)
df["D"] = df["treated"] * df["post"]  # DiD 상호작용
# 결과 생성: 개체/시간 고정효과 + 처리효과 1.5
alpha_i = np.random.normal(scale=1.0, size=N)
gamma_t = np.linspace(-0.5, 0.5, T)
eps = np.random.normal(scale=1.0, size=len(df))
df["Y"] = alpha_i[df["id"].values] + gamma_t[df["t"].values] + 1.5*df["D"] + eps

# PanelOLS: 개체·시간 고정효과
df = df.set_index(["id","t"])
exog = sm.add_constant(df[["D"]])  # 상수는 FE 모델에서 자동 제거
mod = PanelOLS(df["Y"], df[["D"]], entity_effects=True, time_effects=True)
res = mod.fit(cov_type="clustered", cluster_entity=True)
print(res.summary)

계단식 도입이나 이질적 효과가 있다면 Sun & Abraham, Callaway & Sant’Anna 등의 현대적 DiD 추정량 사용을 권장한다.

2SLS로 도구 변수 효과 추정하기

import numpy as np, pandas as pd
from linearmodels.iv import IV2SLS

np.random.seed(7)
n = 3000
Z = np.random.normal(size=n)            # 도구
X = np.random.normal(size=n)            # 공변량
# 처치: Z 관련성, U(미관측)로 내생성
U = np.random.normal(size=n)
D = 0.8*Z + 0.7*X + 0.8*U + np.random.normal(size=n)
# 결과: 진짜 처리효과 2.0, U 포함
Y = 2.0*D + 1.0*X + 1.0*U + np.random.normal(size=n)
df = pd.DataFrame({"Y":Y,"D":D,"Z":Z,"X":X})

# 2SLS
iv = IV2SLS.from_formula("Y ~ 1 + X + [D ~ Z + X]", data=df).fit(cov_type="robust")
print(iv.summary)
print("1단계 F-stat(약한 도구 점검):", round(iv.first_stage.stats['F']['stat'],2))

1단계 F≈10 이상을 확인하고, 배제 제한은 도메인 지식으로 정당화해야 한다.

인과 추론성향 점수 매칭이중차분도구 변수데이터 분석