간단한 선형 회귀 분석은 본질적으로 인과 관계 모델입니다
다음은 선형 회귀 모델이 원인이되지 않는 경우에 대한 예입니다. 약물이 시간 0 ( t = 0 ) 에 취해지고 t = 1 에서 심장 마 비율에 영향을 미치지 않는다는 우선 순위 를 가정 해 봅시다 . 에서 심장 마비 t = 1 에서 심장 마비에 영향 = 2 t을 (즉, 이전의 손상이 손상에 더 민감 마음을한다). t = 3 에서의 생존은 사람들이 t = 2 에서 심장 마비를했는지의 여부에 달려 있습니다. t = 1에서의 심장 마비는 t = 3 에서의 생존에 실제로 영향을 미치겠 지만, 우리는 화살표가 없습니다. 간단.
전설은 다음과 같습니다.
실제 인과 관계 그래프는 다음과 같습니다.
이제 우리가 그 심장 발작 모르는 척하자 1 = t을 에서 약물을 복용 무관 t = 0 그래서 우리는에서 심장 마비에 대한 약물의 효과를 추정하는 간단한 선형 회귀 모델을 구성 t = 0 . 여기서 예측 변수는 Drug t = 0 이고 결과 변수는 Heart Attack t = 1 입니다. 우리가 가진 유일한 데이터는 t = 3 에서 살아남은 사람들뿐 이므로 해당 데이터에 대해 회귀 분석을 실행합니다.
약물 계수 t = 0에 대한 95 % 베이지안 신뢰할 수있는 구간은 다음과 같습니다 .
우리가 볼 수있는 많은 확률이 0보다 크므로 효과가있는 것 같습니다! 그러나 우리 는 효과가 0 이라는 우선 순위 를 알고 있습니다. Judea Pearl과 다른 사람들이 개발 한 인과 관계 수학은이 예에서 (충돌 자의 자손에 의한 조절 때문에) 편향이 있음을 훨씬 쉽게 알 수있게합니다. 유대의 연구는 이러한 상황에서 전체 데이터 세트를 사용해야한다는 것 (즉, 살아남은 사람들을 보지 말 것)은 편향된 길을 제거해야한다는 것을 암시한다.
전체 데이터 세트를 볼 때 95 % 신뢰할 수있는 간격은 다음과 같습니다 (즉, 생존 한 사람들에 대해서는 조절하지 않음).
.
0에 밀집되어 있으며 기본적으로 전혀 관련이 없습니다.
실제 사례에서는 상황이 그렇게 간단하지 않을 수 있습니다. 체계적인 편향 (혼동, 선택 편향 등)을 유발할 수있는 더 많은 변수가있을 수 있습니다. 분석에서 조정할 내용은 Pearl에 의해 수학되었습니다. 알고리즘은 조정할 변수를 제안하거나 조정이 체계적인 편견을 제거하기에 충분하지 않은 경우 알려줍니다. 이 공식적인 이론이 확립되면, 우리는 조정해야 할 것과 조정하지 말아야 할 것에 대해 논쟁하는 데 많은 시간을 소비 할 필요가 없습니다. 결과가 건전한 지 아닌지에 대한 결론에 빠르게 도달 할 수 있습니다. 실험을 더 잘 설계하고 관측 데이터를보다 쉽게 분석 할 수 있습니다.
다음 은 Miguel Hernàn의 Causal DAG 온라인 강좌입니다. 교수 / 과학자 / 통계학자가 당면한 문제에 대해 반대 결론을 내린 실제 사례 연구가 많이 있습니다. 그들 중 일부는 역설처럼 보일 수 있습니다. 그러나 Judea Pearl의 d-separation 및 backdoor-criterion을 통해 쉽게 해결할 수 있습니다 .
참고로 여기에 데이터 생성 프로세스에 대한 코드와 위에 표시된 신뢰할 수있는 간격에 대한 코드가 있습니다.
import numpy as np
import pandas as pd
import statsmodels as sm
import pymc3 as pm
from sklearn.linear_model import LinearRegression
%matplotlib inline
# notice that taking the drug is independent of heart attack at time 1.
# heart_attack_time_1 doesn't "listen" to take_drug_t_0
take_drug_t_0 = np.random.binomial(n=1, p=0.7, size=10000)
heart_attack_time_1 = np.random.binomial(n=1, p=0.4, size=10000)
proba_heart_attack_time_2 = []
# heart_attack_time_1 increases the probability of heart_attack_time_2. Let's say
# it's because it weakens the heart and makes it more susceptible to further
# injuries
#
# Yet, take_drug_t_0 decreases the probability of heart attacks happening at
# time 2
for drug_t_0, heart_attack_t_1 in zip(take_drug_t_0, heart_attack_time_1):
if drug_t_0 == 0 and heart_attack_t_1 == 0:
proba_heart_attack_time_2.append(0.1)
elif drug_t_0 == 1 and heart_attack_t_1 == 0:
proba_heart_attack_time_2.append(0.1)
elif drug_t_0 == 0 and heart_attack_t_1 == 1:
proba_heart_attack_time_2.append(0.5)
elif drug_t_0 == 1 and heart_attack_t_1 == 1:
proba_heart_attack_time_2.append(0.05)
heart_attack_time_2 = np.random.binomial(
n=2, p=proba_heart_attack_time_2, size=10000
)
# people who've had a heart attack at time 2 are more likely to die by time 3
proba_survive_t_3 = []
for heart_attack_t_2 in heart_attack_time_2:
if heart_attack_t_2 == 0:
proba_survive_t_3.append(0.95)
else:
proba_survive_t_3.append(0.6)
survive_t_3 = np.random.binomial(
n=1, p=proba_survive_t_3, size=10000
)
df = pd.DataFrame(
{
'survive_t_3': survive_t_3,
'take_drug_t_0': take_drug_t_0,
'heart_attack_time_1': heart_attack_time_1,
'heart_attack_time_2': heart_attack_time_2
}
)
# we only have access to data of the people who survived
survive_t_3_data = df[
df['survive_t_3'] == 1
]
survive_t_3_X = survive_t_3_data[['take_drug_t_0']]
lr = LinearRegression()
lr.fit(survive_t_3_X, survive_t_3_data['heart_attack_time_1'])
lr.coef_
with pm.Model() as collider_bias_model_normal:
alpha = pm.Normal(name='alpha', mu=0, sd=1)
take_drug_t_0 = pm.Normal(name='take_drug_t_0', mu=0, sd=1)
summation = alpha + take_drug_t_0 * survive_t_3_data['take_drug_t_0']
sigma = pm.Exponential('sigma', lam=1)
pm.Normal(
name='observed',
mu=summation,
sd=sigma,
observed=survive_t_3_data['heart_attack_time_1']
)
collider_bias_normal_trace = pm.sample(2000, tune=1000)
pm.plot_posterior(collider_bias_normal_trace['take_drug_t_0'])
with pm.Model() as no_collider_bias_model_normal:
alpha = pm.Normal(name='alpha', mu=0, sd=1)
take_drug_t_0 = pm.Normal(name='take_drug_t_0', mu=0, sd=1)
summation = alpha + take_drug_t_0 * df['take_drug_t_0']
sigma = pm.Exponential('sigma', lam=1)
pm.Normal(
name='observed',
mu=summation,
sd=sigma,
observed=df['heart_attack_time_1']
)
no_collider_bias_normal_trace = pm.sample(2000, tune=2000)
pm.plot_posterior(no_collider_bias_normal_trace['take_drug_t_0'])