LITTLE BY LITTLE

[5-1] 실무로 통하는 인과추론 with 파이썬 - 5장. 성향점수 본문

데이터 분석/인과추론

[5-1] 실무로 통하는 인과추론 with 파이썬 - 5장. 성향점수

위나 2024. 5. 14. 23:19

목차

<5장 성향점수>

5.1 관리자 교육의 효과
5.2 회귀분석과 보정
5.3 성향점수
5.3.1 성향점수 추정
5.3.2 성향점수의 직교화
5.3.3 성향점수 매칭
5.3.4 역확률 가중치
5.3.5 역확률 가중치의 분산
5.3.6 안정된 성향점수 가중치
5.3.7 유사 모집단
5.3.8 선택편향
5.3.9 편향-분산 트레이드오프
5.3.10 성향점수의 양수성 가정
5.4 디자인 vs 모델 기반 식별
5.5 이중 강건 추정
5.5.1 처치 모델링이 쉬운 경우
5.5.2 결과 모델링이 쉬운 경우
5.6 연속형 처치에서의 일반화 성향 점수
5.7 요약


5장. 성향점수

 
4장에서는 선형회귀분석을 사용하여 교란 요인을 보정하는 방법과, 직교화를 활용한 편향 제거라는 개념을 소개했다.
5장에서는 또다른 편향 제거 방법 중 하나인 성향점수 가중치를 배운다.

→ "잔차 생성" 대신에, "처치 배정 메커니즘을 모델링하고 모델 예측을 사용하여 데이터를 재조정"한다.
→ '이진'이나 '이산형' 처치가 있을 때 적합한 방법을 주로 소개한다.


5.1 관리자 교육의 효과

 
✅ EX. 관리자 교육(T)이 직원 참여도(Y)에 영향을 미칠까?
 

intervention(T) -&amp;amp;gt; engagement_score(Y)
  • 공변량(교란요인) - 관리자에 관한 데이터
    • tenure(근속 기간)
    • n_of_reports(관리자가 담당한 보고서 수)
    • gender, role(직군), 
    • department_size(직원 수), department_score(부서의 평균 참여점수)
    • last_engagement_score(이전 참여도조사에서 해당 관리자의 평균 참여점수)

5.2 회귀분석과 보정

  • 먼저 회귀분석으로 교란 요인을 보정하고 그 결과인 회귀 추정값을 성향점수 가중치 추정값과 같은지 확인해보자.
model = smf.ols("""engagement_score ~ intervention 
+ tenure + last_engagement_score + department_score
+ n_of_reports + C(gender) + C(role)""", data=df).fit()

print("ATE:", model.params["intervention"])
print("95% CI:", model.conf_int().loc["intervention", :].values.T)

> ATE: 0.2677908576676856 # 교란 요인을 보정하지 않은 단수누 추정값 = 0.43
> 95% CI: [0.23357751 0.30200421]
  • 보정 후 효과 추정값이 0.26으로, 두 배정도 작아졌기에 긍정 편향이 있음을 알 수 있다.
  • 즉, 이미 직원 참여도가 높은(Y) 관리자가 교육 프로그램에 더 많이 참여(T)했을 가능성이 높다는 의미

5.3 성향 점수
성향 점수 (=균형 점수=조건부 확률 P(T|X))

: 처치를 받을 조건부 확률로, 공변량 X를 T로 변환하는 일종의 함수 (=공변량 X로 추정되는 처치 받을 확률)

X대신 성향점수 e(x)를 통제할 수 있다
  • 교란 요인 X를 통제하는 대신, E[T|X]를 추정하는 균형점수(성향점수)를 통제하는 방법에 쓰임
  • 교란 요인 X를 직접 통제할 필요 없이 조건부 독립성 (Y1,Y0) ⊥ T | X을 만족할 수 있다는 깨달음에서 비롯됨
  • 차원 축소 기법으로 볼 수도 있다.
    • 고차원일 수도 있는 X를 조건부로 설정하는 대신, 성향점수를 조건부로 두고 X로 유입되는 뒷문 경로를 차단할 수 있다.
    • (Y1,Y0) ⊥ T | P(x)
  • 앞의 관리자 교육 프로그램의 관점에서 생각해보면, (관리자 교육(T)→직원 참여도(Y))
    • 직속 상사의 참여가 높은 관리자일수록 교육에 참여할 가능성이 더 높다. (실험-대조군 비교 불가)
    • 성향 점수가 동일하다면,(=관리자가 교육(처치)을 받을 확률이 똑같다면), 처치는 사실상 무작위 배정된 것과 같다.

공변량 x대신 성향점수 e(x)를 사용하는 이유는,
 

  1. 공변량이 고차원일 경우(여러 개), 성향점수 e(x) 하나로 축소함으로써 모델의 복잡성을 줄이는 데 도움이 된다.
  2. 이중 로버스트(=극단값에 민감하지 않음) 특성 활용
    • 성향 점수 모델과 결과 모델 두 가지 모델을 결합했기에,
    • 둘 중 한가지인 성향 점수 모델이 약간 잘못되었더라도, Y에 대한 모델이 올바르면 여전히 편향을 줄일 수 있다. (vice versa)
    • 모델의 견고성 향상

5.3.1 성향점수 측정

  • 실제 성향점수 e(x)는 알 수 없는 이상적인 값으로, 현실에서는 처치 배정 메커니즘을 알 수 없기에 추정값으로 대체해야 함
  • 종속 변수(처치)가 이진 변수이기 때문에 로지스틱 회귀모델을 활용하여 공변량(X)이 처치(T)를 받을 확률성향 점수를 추정할 수 있다.

앞의 예제(이진 처치) 에서 로지스틱 회귀(logit)로 e(x)를 추정해보자

ps_model = smf.logit("""intervention ~ 
tenure + last_engagement_score + department_score
+ C(n_of_reports) + C(gender) + C(role)""", data=df).fit(disp=0)

 
원본 데이터프레임에 추가

data_ps = df.assign(
    propensity_score = ps_model.predict(df),
)

data_ps[["intervention", "engagement_score", "propensity_score"]].head()
추정된 성향점수(propensity_score)

 
* 머신러닝 모델로 성향점수를 추정할 수도 있다. 단, 1) sklearn의 보정 모듈을 사용하여  보정된 확률 예측값이 나오는지 확인해야하며, 2) OOF(Out of fold) 방식의 예측(cross_val_predict)을 사용하여 과적합에서 오는 편향을 피해야 한다.


5.3.2 성향 점수와 직교화

  • 이전 장에서 배운 FWL 정리 ① 편향 제거 단계에서 선형회귀로 E[T|X]를 추정하는 것처럼,
  • 성향 점수 추정도 유사한 방식으로 처치 배정 메커니즘을 모델링한다.
  • 즉, 선형회귀에서 교란 요인 X를 보정하기 위해, 성향점수 e'(X)를 사용할 수 있다.
model = smf.ols("engagement_score ~ intervention + propensity_score", # X 대신 성향 점수 e(x) 더하기
                data=data_ps).fit()
model.params["intervention"]
  • 이 결과로 얻은 ATE 추정값은 교란 요인 X를 사용하여 선형회귀분석을 적합시킨 결과와 유사함
  • 두 접근법 모두 단순히 처치를 직교화하는 방법
  • 유일한 차이점은 OLS는 선형회귀분석을 사용하여 T를 모델링하고, 성향점수 추정값은 로지스틱 회귀분석으로 얻어진다는 것

5.3.3 성향점수 매칭

: 성향점수 직교화에 이어 성향점수를 통제하는 또 다른 접근 방식으로 매칭 추정량이 있다.

  • 이 방법은 관측 가능한 특징이 비슷한 실험 대상의 짝을 찾아 실험군-대조군을 비교한다.
  • 매칭 종류 중 k=1인 K 최근접 이웃(KNN, K-nearest neighbors) 알고리즘 형태의 매칭을 다뤄보자.

sklearn.neighbors.KNeighborsRegressor K-최근접 이웃(K-Nearest Neighbors, KNN)
: 회귀 모델을 생성하는 클래스로,  각 데이터 포인트의 가장 가까운 K개의 이웃을 기반으로 값을 예측
 
KNN 알고리즘 형태의 성향점수 매칭 방법
 
1. 성향점수를 유일한 특성으로 사용하여 실험군에 KNN 모델 적합시키기

mt1 = KNeighborsRegressor(n_neighbors=1).fit(treated[[X]], treated[Y]])

 
2. 실험군의 예측모델 결과값를 대조군의 Y1 (잠재적 결과)으로 대체하기 (mt1=실험군 예측모델)

match = mt1.predict(untreated[[X]])

 
3. 대조군에 KNN모델을 적합시키기

mt0 = KNeighborsRegressor(n_neighbors=1).fit(untreated[[X]], untreated[Y]])

 
4. 대조군의 예측모델 결과값을 실험군의 Y0 (잠재적 결과)으로 대체하기

match = mt0.predict(treated[[X]])

 
전체 코드

from sklearn.neighbors import KNeighborsRegressor

T = "intervention"
X = "propensity_score" # 성향 점수 e(x)
Y = "engagement_score"

treated = data_ps.query(f"{T}==1") # 실험군 필터링
untreated = data_ps.query(f"{T}==0") # 대조군 필터링

mt0 = KNeighborsRegressor(n_neighbors=1).fit(untreated[[X]], # 실험군의 잠재적 결과 예측
                                             untreated[Y])

mt1 = KNeighborsRegressor(n_neighbors=1).fit(treated[[X]], treated[Y]) # 대조군의 잠재적 결과 예측

# 예측 및 매칭
predicted = pd.concat([
    # 대조군 데이터를 학습한 모델로 실험군 데이터의 짝을 찾기
    treated.assign(match=mt0.predict(treated[[X]])),
    
    # 실험군 데이터를 학습한 모델로 대조군 데이터의 짝을 찾기
    untreated.assign(match=mt1.predict(untreated[[X]]))
])

predicted.head()

 
match 컬럼

  • 실험군 데이터(intervention=1)에는 mt0 모델을 사용한 예측 결과가 match 컬럼에 추가됨
  • 대조군 데이터(intervention=0)에는 mt1 모델을 사용한 예측 결과가 match 컬럼에 추가됨
  • 즉, 첫 번째 행을 설명하면,
    • T=1 실험군
    • 참여도(Y) = 0.27
    • 성향 점수(e(x)) = 0.59
    • 인 데이터의 T=0인 데이터의 예측 모델로 추정된 참여도(Y)
    • 는 곧 e(x)=0.59, Y=0.27인 관측값이 처치를 받지 않았을 때의 잠재적 결과 

실험군-대조군의 잠재적 결과를 구했으니, ATE를 추정할 수 있다.

Yjm(i)는 실험군에 속한 대상 i의 짝지어진 대상의 결과(=잠재적 결과)
np.mean((predicted[Y] - predicted["match"])*predicted[T] 
        + (predicted["match"] - predicted[Y])*(1-predicted[T]))
> 0.28777443474045966

✅ 매칭 추정량의 편향

  • 성향 점수 뿐만 아니라, 원래 특성 X에 바로 매칭할 수도 있다. 
  • 그러나 매칭 추정량은 편향될 수 있으며, X의 차원이 클수록 편향이 커진다.
  • 차원이 높아질수록 데이터가 희소해지고 매칭의 정확성이 떨어지기 때문
  • 편향 = 기대 결과와 매칭 결과 사이의 불일치 (decrepancy)
    • 실험군에 대한 편향 = μ0(Xi) - μ1(Xjm) * Xjm은 짝지어진 대상의 공변량
    • 대조군에 대한 편향 = μ1(Xjm) - μ0(Xi)
  • 따라서 편향을 피하면서 매칭을 사용하기 위해서는, 편향 보정식을 적용해야 한다.

매칭 추정량의 단점

  1. 편향될 가능성이 있다.
  2. 분산을 추정하기 어렵다.
  3. KNN은 X가 고차원인 경우, 대체로 효율이 크게 떨어진다. (← 성향점수만으로 매칭한다면 문제가 되지 않음)

→ 매칭 추정량은 많이 알려져 있으나, 크게 선호되지 않는 방식이다.


5.3.4 역확률 가중치
 

역확률 가중치(IPW, Inverse Propensity Weighting) 
: 처치의 역확률에 따라 데이터의 가중치를 재조정하여 해당 데이터가 처치에서 무작위 배정된 것처럼 보이게 함 

  • 성향 점수(P(T=t|X) 에 역수를 취해서 가중치를 부여하여 모든 실험 대상이 처치 t를 받았을 경우와 비슷한 유사 모집단 생성
  • 드문 처치 사례에 더 많은 가중치를 주는 것
  • 처치 받은 대상이 처치 받지 않은 것처럼 보인다면, 대조군이 처치 받았을 때 어떤 일이 일어났을지 Y1|T=0에 관한 유용한 정보를 제공할 수 있음

* 역확률 가중치 = 역성향점수 가중치


✅ EX. 관리자 교육(T)이 직원 참여도(Y)에 영향을 미칠까?

관리자 교육 효과 예제에 IPW를 적용하면,

 

  • x축은 개입(관리자 교육)을 받을 확률인 성향점수, y축은 결과 값 Y
  • 성향 점수가 낮은 관리자는, 교육을 받을 확률이 낮고, 이 경우 교육을 받은 관리자가 중요하기에 높은 가중치가 부여
  • 성향 점수가 높은 관리자는, 교육을 받을 확률이 높고, 이 경우 교육을 받지 않은 관리자가 중요하기에 낮은 가중치가 부여

역확률 가중치 적용

  • 개입을 받은 경우: 1/ e(X) 로 가중치 부여 
    • 개입 받을 확률(e(X))이 낮을 수록 가중치가 커지는 것
  • 개입을 받지 않은 경우: 1/1-e(X) 로 가중치 부여
    • 개입 받지 않을 확률(e(X))이 낮을 수록 가중치가 커지는 것

역확률 가중치(성향점수의 역수) 계산

# T=1의 가중치(성향점수의 역수)
weight_t = 1/data_ps.query("intervention==1")["propensity_score"]
# T=0의 가중치(성향점수의 역수)
weight_nt = 1/(1-data_ps.query("intervention==0")["propensity_score"])

 
실험군과 대조군의 결과값(Y) 계산

# T=1의 Y값
# T=1의 Y값
t1 = data_ps.query("intervention==1")["engagement_score"] 
# T=0의 Y값
t0 = data_ps.query("intervention==0")["engagement_score"]

 
ATE 추정 (T=1의 가중치가 적용된 평균 - T=0의 가중치가 적용된 평균)

# T=1의 가중치(성향점수)가 적용된 평균 Y값 
y1 = sum(t1*weight_t)/len(data_ps)
# T=0의 가중치(성향점수)가 적용된 평균 Y값
y0 = sum(t0*weight_nt)/len(data_ps)

print("E[Y1]:", y1)
print("E[Y0]:", y0)
print("ATE", y1 - y0)

> E[Y1]: 0.11656317232946772
> E[Y0]: -0.1494155364781444
> ATE 0.2659787088076121
  • 결과적으로 공변량 X를 보정하지 않고 단순히 얻은 결과보다 작은 ATE를 구했다.
  • 역확률 가중치를 바탕으로 얻은 결과는 OLS 결과와 유사하다. → 오류가 있는지 점검할 때 사용가능

역확률 가중치를 사용해서 추정된 ATE식

  1. 가중치 적용(분모) - T=1인 경우  1/e(X)의 가중치를, T=0인 경우 1/1-e(X)의 가중치를 부여
  2. 중앙값 중심 조정(분자) - T - e(X)는 개입 여부에서 성향 점수를 뺀 값으로,
    • 개입을 받은 경우 1 - e(X)가 되고,
    • 개입을 받지 않은 경우 0 - e(X)가 된다.
  3. 평균 계산
np.mean(data_ps["engagement_score"] 
        * (data_ps["intervention"] - data_ps["propensity_score"]) 
        / (data_ps["propensity_score"]*(1-data_ps["propensity_score"])))

✅ 회귀분석과 역확률 가중치

회귀분석에서의 인과효과 추정 식

 

역확률 가중치에서의 인과효과 추정식

→ 1 / E[Var(X|T)]는 상수이므로, 기댓값 안으로 옮겨 다시 식을 쓰면 아래와 같이 표현할 수 있다.

W = Var(T❘X) / E[Var(T❘X)]

 
기댓값 안에 있는 부분은 X로 정의한 그룹의 효과(CATE)를 식별

  • IPW(Inverse Probability Weighing)는 각 표본에 1을 가중치로 부여
  • 회귀분석은 T의 조건부 분산 (Var(T|X))으로 그룹 효과에 가중치를 부여
    • 회귀분석은 T의 변동이 큰 부분에 큰 가중치를 부여한다고 배웠었다.

→ 즉, 회귀분석과 IPW는 다르게 보이지만, 가중치 부여 방식을 제외하고는 거의 동일하다.


5.3.5 역확률 가중치의 분산

역확률 가중치의 표준오차를 계산하는 일은 간단하지 않다. IPW 추정값의 신뢰구간 구하기

  • IPW 추정값의 신뢰구간을 얻는 가장 간단한 방법은 부트스트랩 방법
    1. 데이터를 반복적응로 복원추출해서 여러 IPW 추정값을 구한다.
    2. 추정값의 2.5번째와 97.5번째 백분위수를 계산하여 95% 신뢰구간을 얻는다.

*patsydmatrix: 공식 형태로 된 문자열을 디자인 행렬로 변환해주는 함수
*.predict_proba() 메소드: 예측값이 아닌 모델에 대한 확률값을 얻을 때 사용, 두 개의 열(P(Y=0|X)와 P(Y=1|X))로 된 행렬을 출력한다.

 
 IPW 추정 과정을 함수로 구현하기

from sklearn.linear_model import LogisticRegression
from patsy import dmatrix

# IPW로 ATE를 추정하는 함수
def est_ate_with_ps(df, ps_formula, T, Y):
    # 데이터프레임 df를 디자인 행렬 X로 변환 (로지스틱 회귀의 input으로 사용)
    X = dmatrix(ps_formula, df)
    
    # 로지스틱 회귀 모델 생성, 디자인 행렬 x와 T로 모델 학습
    ps_model = LogisticRegression(penalty="none",
                                  max_iter=1000).fit(X, df[T])
    # 학습한 모델을 사용하여 각 샘플에 대해 T=1에 속할 확률 예측
    ps = ps_model.predict_proba(X)[:, 1]
    
    # ATE 추정(역확률 가중치 공식 활용)
    return np.mean((df[T]-ps) / (ps*(1-ps)) * df[Y])

 
IPW로 ATE 추정량을 계산하는 함수 사용

formula = """tenure + last_engagement_score + department_score
+ C(n_of_reports) + C(gender) + C(role)"""
T = "intervention"
Y = "engagement_score"

est_ate_with_ps(df, formula, T, Y)

> 0.2659755621752663

 
부트스트랩 과정에 적용하는 bootstrap 함수 정의

  1.  .sample(frac=1, replace=True) 메소드로 리샘플링을 진행하여 부트스트랩 표본 얻기
  2. 표본을 앞서 만든 ate추정 함수에 전달
  3. ate추정값을 단일 숫자로 반환
from joblib import Parallel, delayed # 병렬처리 (부트스트랩 반복 작업 가속화)

# rounds는 부트스트랩 반복횟수, pcts는 신뢰구간 pct tiles, 2.5%와 97.5%를 계산하여 95% 신뢰구간 반환
def bootstrap(data, est_fn, rounds=200, seed=123, pcts=[2.5, 97.5]):
    np.random.seed(seed)
    
    # n_jobs=4는 4개의 프로세스를 사용하여 병렬로 작업을 수행하도록 지정하는 것
    stats = Parallel(n_jobs=4)(
    	# delayed는 함수 호출을 지연시키는 데 사용
        # sampe(frac=1, replace=True)는 원본 크기와 동일한 크기의 복원 샘플을 생성
        delayed(est_fn)(data.sample(frac=1, replace=True))
        for _ in range(rounds)
    )
    
    return np.percentile(stats, pcts)

✅ Partial 함수
: 주어진 함수와 해당 함수의 일부 인수들을 받아서, 이 인수들이 미리 적용된 새로운 함수를 만들어줌

def addNumber(x, Number):
	return x + number
    
add2 = partial(addNumber, number=2)
add4 = partial(addNumber, number=4)

add2(3)
>>>> 5

add4(3)
>>>> 7

 
partial을 사용하여 est_ate_with_ps 함수를 호출하고 그 안의 수식,처치,결과 인수를 적용해보자

from toolz import partial

print(f"ATE: {est_ate_with_ps(df, formula, T, Y)}")

est_fn = partial(est_ate_with_ps, ps_formula=formula, T=T, Y=Y)
print(f"95% C.I.: ", bootstrap(df, est_fn))

> ATE: 0.2659755621752663
> 95% C.I.:  [0.22654315 0.30072595]
  • 선형 회귀분석을 사용하여 얻은 것과 유사한 신뢰구간이 나왔다.
  • 큰 가중치가 적용되면 성향점수 추정량의 분산이 크게 증가한다.
  • 큰 가중치를 가진다는 건, 몇몇 실험 대상이 최종 추정값에 큰 영향을 미친다는 의미이다.
  • 최종 추정값에 큰 영향을 주는 소수의 대상들이 분산 증가의 원인이 된다.
  • 성향 점수가 높은 부분에 대조군의 실험 대상이 적거나, 낮은 부분에 실험 대상이 적은 경우 큰 가중치를 가짐
  • 즉, 반사실적 결과를 추정할 대상이 적어진 것이기에, 결과에 잡음이 많을 수 있는 것 (편향▼ 분산▲)

✅ 인과적 콘텍스트 밴딧

: 콘텍스트 밴딧(Contextual bandit)강화학습의 한 종류로, 주어진 상황(context)에서 최적의 결정을 내리는 것을 목표로 함

 
샘플링과 추정이라는 두 가지 구성 요소로 이루어짐

  1. 샘플링: 아직 탐색되지 않은 영역에서 데이터 수집과 최적의 처치 배정의 균형을 맞춤
    • 즉, 새로운 데이터를 얻기 위해 다양한 처치를 시도하는 과정
    • ex. 알고리즘이 여러 종류의 광고를 무작위로 사람들에게 보여주고, 클릭 여부를 기록함
    • 이 광고를 보여주는 과정에서, 특정 광고는 특정 조건에서만 많이 보여졌을 수 있다는 점 고려
  2. 추정: 사용 가능한 데이터로 최적의 처치를 찾으려고 노력
    • 현재까지 모은 데이터를 분석하여 어떤 처치가 가장 좋은지 판단
    • ex. 수집한 데이터로 어떤 광고가 가장 많이 클릭되는지 파악함

이 때, 추정 단계최적의 처치 배정 메커니즘을 학습하려는 인과추론 문제로 쉽게 구성할 수 있다.
(알고리즘의 목표: 최적의 방식으로 처치를 배정하는 것)

  • 의사결정 과정이 확률적이라면, 각 처치를 배정할 확률인 성향 점수 e(x)를 얻을 수 있다.
    • 특정 상황에서 처치 A를 선택할 확률(ex. 광고를 클릭할 확률)이 70%라면, e(x)=0.7
  • 성향점수로 이미 처치가 선택되고, 관측된 결과가 있는 과거 데이터를 재조정(reweight)

5.3.6 안정된 성향점수 가중치

가중치가 너무 크거나 작다면, T의 주변확률로 가중치 안정화하기

 
실험군에 1/P(T=1|X) 만큼의 가중치를 주면, 원래 표본 크기와 같지만, 모든 대상이 처치를 받은 것처럼(혹은 받지 않은 것처럼) 행동하는 유사 모집단을 만든다.
→ 이러한 접근 방식 IPW를 머신러닝 관점에서 '중요도 샘플링'의 응용으로 바라볼 수 있다.


중요도 샘플링(Importance Sampling)

: 원본 분포 q(x)의 데이터가 있지만, 목표 분포 p(x)에서 샘플링하고 싶을 때, q(x)의 데이터를 p(x)/q(x)로 재조정하는 방식을 사용한다.

 

<IPW>

실험군에 1/P(T=1|X)의 가중치를 주는 것은 곧, 

<중요도 샘플링>

P(T=1|X) 분포(원본 분포)에서 나온 데이터를 사용해서 P(T=1)=1(목표분포)로 재구성하는 것과 같다. 

(재구성한 처치확률P(T=1)=1이 되면, 단순히 1이기에 더 이상 X에 종속이지 않음)
 
*원본 분포 = 표본을 얻기 쉬운 제안(proposal) 분포로, 중요도 샘플링은 구하기 어려운 목표 분포의 기댓값을 추정하는 것이 목표로 함
 

실험군과 대조군의 가중치 합원래 표본 크기에 얼마나 가까운지 확인해보자

print("Original Sample Size", data_ps.shape[0])
> Original Sample Size 10391

print("Treated Pseudo-Population Sample Size", sum(weight_t))
> Treated Pseudo-Population Sample Size 10435.089079197916

print("Untreated Pseudo-Population Sample Size", sum(weight_nt))
> Untreated Pseudo-Population Sample Size 10354.298899788304

 
만약 가중치가 너무 크다면(=처치 확률이 매우 낮다면) P(T|X) 값이 매우 작아져 계산상의 문제가 발생할 수 있음
해결하기 위해 T의 주변확률 P(T=t)로 가중치를 안정화할 수 있다.


주변 확률(marginal probability)
: 전체 데이터에서 특정 사건이 발생하는 빈도를 나타내는 확률로, 가중치 안정화 시 기준점으로 사용할 수 있다.

안정된(stabilized) 가중치

 
안정된 가중치는 실험군과 대조군의 유효 크기(effective size, ↔ 가중치의 합)가 각각 원래 실험군과 대조군의 유효 크기와 일치하는 유사 모집단을 재구성한다.
 
1. 처치의 주변확률( ↔ 전체에서 처치가 이루어진 비율) 계산

p_of_t = data_ps["intervention"].mean()

 
2. 실험-대조군의 안정화된 가중치 계산 
실험군 = 처치의 주변확률 / 성향 점수
대조군 = 1 - 처치의 주변확률 / 비처치 확률(1-성향점수) 

t1 = data_ps.query("intervention==1")
t0 = data_ps.query("intervention==0")

weight_t_stable = p_of_t/t1["propensity_score"]
weight_nt_stable = (1-p_of_t)/(1-t0["propensity_score"])

 
3. 유효크기(가중치의 합)가 원래 크기와 유사한지 확인

#원래 크기
print("Treat size:", len(t1))
# 안정된 가중치 적용 후 유효 크기
print("W treat", sum(weight_t_stable))
#원래 크기
print("Control size:", len(t0))
# 안정된 가중치 적용 후 유효 크기
print("W treat", sum(weight_nt_stable))

 
→ 안정화(stabilization)는 원래 성향점수의 균형을 이루려는 속성을 동일하게 유지한다. (이전과 동일한 ATE 추정값이 나오는 것을 확인할 수 있다.)


5.3.7 유사 모집단

IPW가 편향을 제거하는 방법 이해하기

 
처치 여부에 따라 추정된 성향점수 e^(x) 분포를 시각화하면, 관리자들의 P(T=1) 확률이 다르므로 T=1 인 사람들의 e(x)가 더 높은 경향이 생긴다.

 
처치여부에 따른 성향점수 그래프
좌측 그래프를 보면 앞서 언급한 것처럼, e(x)가 낮은 영역에서 대조군이 분포가 높기에, 실험군의 가중치가 증가한다.

* 중간(회색)부분에서 두 분포가 겹치게 되고, 이는 가중치가 적용된 데이터에서 처치를 받을(받지 않을) 확률이 동일해짐을 의미

 
(역확률 가중치 적용 후) 처치여부에 따른 성향점수 그래프
우측 그래프에서 e(x)가 낮은 영역에 부족한 실험군의 가중치를 증가시킴으로써 해당 현상이 해결됨을 확인할 수 있다.


5.3.8 선택편향

IPW 추정량은 교란편향 뿐만 아니라 선택편향도 보정할 수 있다.
 

  • IPW로 공통원인을 보정하여 교란편향을 보정할 수 있었다. 뿐만 아니라, 선택문제를 보정하는 데도 사용할 수 있다.
  •  예를 들어 앱에 대한 고객 만족도를 알고 싶다고 가정할 때, 미응답자들이 있기에 결과가 편향될 수 있다.
  • 비응답으로 인한 왜곡을 보정하여 전체 모집단의 특성을 정확하게 반영할 수 있다.

이를 보정하기 위해 IPW를 활용하면,

  1. 고객의 공변량(ex. 나이,소득 앱 사용량)을 사용해서 응답률(P(R=1|X))을 추정한다.
  2. 응답자(R=1)에게 1/P(R=1) 만큼의 가중치를 부여한다. 
  3. 마치 모두가 설문에 응답한 것처럼 보이는 유사 모집단을 생성한다.
  • 때로는 교란편향과 선택편향을 동시에 마주해야 한다.
  • 이 경우, 선택편향과 교란편향에 두 가중치의 곱을 사용할 수 있다. 

*값이 매우 작은 경우, 앞서 배운 것처럼 가중치를 주변확률 P(T=t)로 안정화하면 좋다.
* 교란 편향 보정 시 처치그룹과 비처치그룹 모두에 가중치를 부여한 반면, 선택 편향 보정 시 응답자에게만 가중치를 부여한다. 

 


5.3.9 편향-분산 트레이드오프

  • 언뜻 보면, 처치 배정 메커니즘을 더 잘 추정할수록 인과 추정값이 더 좋아질 것 같지만, 그렇지 않다.
  • T를 잘 예측하는 공변량 Xk가 있다면, 이 변수는 성향점수 e(x)에 대한 정확한 모델을 제공할 것이다.
  • 그러나, 해당 변수 Xk가 결과 변수 Y의 원인이 아니라면, 공통 원인(교란)이 아니기에 IPW 추정값의 분산만 높일 것 (4.9.1 잡음 유발 통제변수 참고)

예를 들어, T에 대해 매우 정확한 모델이 있다고 생각해보았을 때,
📌 이 모델은 모든 실험군에서 높은 성향점수를 보이고, (=처치를 받을 확률이 높다고 정확히 예측)
또 대조군에서는 낮은 성향점수를 보일 것이다.(=처치를 받지 않을 것이라 정확히 예측)
📌하지만 이렇게 하면 Yi|T=0을 추정할 수 있는 e(x)가 낮은 실험군이 없고, 반대로 Yi|T=1을 추정할 수 있는 e(x)가 높은 대조군이 남지 않는다.
 
반대로 처치가 무작위 배정된 상황을 생각해보았을 때,
📌 이 경우 성향점수 e^(x)의 예측력은 0이 되어야 한다. (←처치 받을 확률을 예측하기 어려울 것)
📌하지만 예측력이 없어도 이것이 처치 효과를 추정하기에는 최선이다.
 
→ 성향 점수 모델이 정확할 수록 편향이 작아지나, 매우 부정확한 인과 효과 추정량을 생성할 수 있다.
→ 편향을 통제할 수 있을 정도로 정밀하게 모델을 만들되, 너무 과도하면 분산 문제가 발생하기에 주의하기


 잘라내기
: IPW 추정량의 분산을 줄이기 위한 방법으로, 성향점수를 "항상 특정 수준 이상으로 유지"하는 것

  • 너무 큰 가중치(ex.100 이상)을 피하기 위해 1% 이상으로 설정하는 것
  • 가중치가 너무 크지 않도록 제한하는 방법도 있음
  • 가중치가 제한된 IPW는 더 이상 편향되지 않지만, 주의해야 한다.
    • 잘라내기를 너무 과하게 하여 e(x)가 낮은 샘플을 무시하거나, 가중치를 과도하게 줄이면, 특정 샘플들의 영향이 충분히 반영되지 않아 IPW 추정량의 변동성이 눈에 띄게 줄어들 것
    • 이로 인해 분산 감소가 뚜렷해지면, 편향이 오히려 증가하여 MSE(Mean Square Error, 평균제곱오차)가 낮아질 수 있다.

5.3.10 성향점수의 양수성 가정

 
인과추론 가정에서 편향-분산 트레이드 오프를 바라보면,

  1. 조건부 독립(=비교란성, unconfoundedness) 가정 
  2. 양수성 가정

두 가지 가정 중 조건부 독립 가정을 만족하는 방향으로 나아가기 위해 더 많은 변수를 추가하여 e(x) 성향점수 모델을 더 정교하게 만들 수 있다.
그러나 그렇게 하면 동시에, 대조군에서 멀리 떨어진 e^(x) 영역에 처치가 집중되고, 그러면 양수성 가정의 타당성이 떨어지게 된다. 

  • 당연하지만, IPW 재구성은 재조정할 수 있는 표본이 있을 때만 가능하다.
  • e(x)가 낮은 표본 중 처치 받은 표본이 없다면, 해당 영역에서 Yi 를 재구성할 수는 없다.
  • 이는 곧, IPW 측면에서 양수성 가정이 위배되었다고 볼 수 있다. 
  • 양수성이 위배되는 수준까지는 아니더라도, 큰 분산에서 오는 문제를 겪게 됨

시뮬레이션 데이터로 성향점수의 양수성 가정에 대해 직관적으로 이해해보자.

  • 실제 ATE는 1이지만, X가 T와 Y의 관계를 교란하는 상황
  • X가 클수록 Y는 작아지지만, 처치 받을 가능성(성향점수)는 높아진다.
  • 여기서 인과추정량을 구하면 하향 편향되고, 심지어 음수가 될 수 있음
  • 가운데 그래프(positivity check)를 보면, 실험-대조군의 e(x) 사이에 겹치는 부분이 없다. e(x)가 거의 0에 가까운 곳에 대조군(not treated)이 모여있지만, 실험군이 없어 해당 영역을 재구성할 수 없다. (양수성 가정 위배)
    • 실험군을 재구성하여 얻을 수 있는 대조군의 잠재적 결과(Yi|T=0)의 좋은 추정값을 얻지 못하게 됨
  • 오른쪽 그래프(IPW Data)를 보면, 오른쪽 대조군(t=0)의 가중치(원의 크기)가 매우 크다. (똑같이 왼쪽 실험군(t=1)의 가중치(원의 크기)가 매우 크다.
    • 가중치가 크면 IPW 추정량의 분산을 증가시킨다.

'큰 분산'과 '양수성 가정 위배' 이 두가지 문제를 종합하면, IPW추정량이 ATE를 1로 찾지 못하는 것을 볼 수 있다.

est_fn = partial(est_ate_with_ps, ps_formula="x", T="t", Y="y")
print("ATE:",  est_fn(df_no_pos))
print(f"95% C.I.: ", bootstrap(df_no_pos, est_fn))

> ATE: 0.6478011810615735
> 95% C.I.:  [0.41710504 0.88840195]

 
→ 심지어, 신뢰구간의 상한값(0.88)이 실제 ATE인 1보다 현저히 낮아보인다.
 
양수성 가정 위배는 IPW추정량만의 문제는 아니나, IPW로 양수성 문제에 선명하게 다가갈 수 있다.

  • 위의 가운데 그래프인(=propensity check) 처치 변수의 e(x) 분포를 그려봄으로써 양수성 가정을 잘 만족하는지 시각적으로 확인할 수 있다.

회귀분석의 한계를 극복할 수 있는 IPW추정량
: 회귀분석은 양수성 가정이 위배된 상황에서 잘 작동하지 않으나, IPW 추정량은 유효하게 작동할 수 있음

  • 회귀분석은 잠재적 결과의 평활도(smoothness)에 대한 가정을 한다. 즉, "공변량이 변화할 때 Y의 값이 부드럽게 변한다"고 가정한다.
  • 따라서 양수성 가정이 위배되거나, 특정 조건에서의 데이터가 부족하더라도, 모델은 부정확하더라도 특정값을 외삽을 통해서 예측을 하기에, 전혀 다른 값을 예측할 가능성이 있다.
  • 운이 좋게 데이터가 없는 영역을 외삽하여 ATE를 정확하게 찾을 수도 있으나, 이는 매우 운이 좋은 케이스

→ 반면에 IPW는 잠재적 결과의 형태에 대해 아무런 가정도 하지 않기에, 외삽이 필요한 경우 ATE를 정확하게 추정하기 어렵다.
 
평활도(smoothness, 연속성)

  • 조건부 기댓값 함수의 특성으로, 임계값이 변할 때 관련된 다른 잠재적 결과에 아무런 변화가 없다는 것을 의미한다.
  • 평활도 가정은 데이터의 변화를 부드럽게 따라갈 수 있도록 하기에, 전체 데이터에 걸쳐 일관성 있는 예측을 할 수 있도록 해주어 특정 지점에서 공변량X가 급격한 변화를 보이더라도 이를 설명할 수 있다.

 

Comments