Как вычислить доверительный интервал метода Difference in Differences с использованием Python?

#python #ab-testing #t-test #hypothesis-test #experimental-design

#python #ab-тестирование #t-тест #проверка гипотезы #экспериментальный дизайн

Вопрос:

Я пытаюсь проанализировать общее количество активных минут на пользователя до и после эксперимента. Здесь я включил связанные пользовательские данные до и после эксперимента — variant_number = 0 указывает контрольную группу, а 1 означает группу лечения. В частности, меня интересует среднее значение (среднее общее количество активных минут на пользователя).

Сначала я вычислил разницу в результатах лечения до и после и разницу в результатах контроля до и после (-183,7 и 19,4 соответственно). В этом случае разница в различиях = 203,1.

Мне интересно, как я могу использовать Python для построения 95% доверительного интервала разницы в различиях? (При необходимости я могу предоставить больше кода / контекста)

Ответ №1:

Вы можете использовать линейную модель и измерить эффект взаимодействия ( group[T.1]:period[T.pre] ниже). Средняя разница в различиях для этих смоделированных данных заключается -223.1779 в том, что p-значение для взаимодействия является p < 5e-4 настолько значительным, а доверительный интервал 95% [-276.360, -169.995] равен .

 import statsmodels.api as sm
import statsmodels.formula.api as smf
import pandas as pd
import numpy as np
np.random.seed(14)

minutes_0_pre = np.random.normal(loc=478, scale=1821, size=39776)
minutes_1_pre = np.random.normal(loc=275, scale=1078, size=9921)

minutes_0_post = np.random.normal(loc=458, scale=1653, size=37425)
minutes_1_post = np.random.normal(loc=458, scale=1681, size=9208)

df = pd.DataFrame({'minutes': np.concatenate((minutes_0_pre, minutes_1_pre, minutes_0_post, minutes_1_post)),
                   'group': np.concatenate((np.repeat(a='0', repeats=minutes_0_pre.size),
                                            np.repeat(a='1', repeats=minutes_1_pre.size),
                                            np.repeat(a='0', repeats=minutes_0_post.size),
                                            np.repeat(a='1', repeats=minutes_1_post.size))),
                   'period': np.concatenate((np.repeat(a='pre', repeats=minutes_0_pre.size   minutes_1_pre.size),
                                            np.repeat(a='post', repeats=minutes_0_post.size   minutes_1_post.size)))
                   })
model = smf.glm('minutes ~ group * period', df, family=sm.families.Gaussian()).fit()
print(model.summary())
 

Вывод:

 Generalized Linear Model Regression Results                  
==============================================================================
Dep. Variable:                minutes   No. Observations:                96330
Model:                            GLM   Df Residuals:                    96326
Model Family:                Gaussian   Df Model:                            3
Link Function:               identity   Scale:                      2.8182e 06
Method:                          IRLS   Log-Likelihood:            -8.5201e 05
Date:                Mon, 18 Jan 2021   Deviance:                   2.7147e 11
Time:                        23:05:53   Pearson chi2:                 2.71e 11
No. Iterations:                     3                                         
Covariance Type:            nonrobust                                         
============================================================================================
                               coef    std err          z      P>|z|      [0.025      0.975]
--------------------------------------------------------------------------------------------
Intercept                  456.2792      8.678     52.581      0.000     439.271     473.287
group[T.1]                  14.9314     19.529      0.765      0.445     -23.344      53.207
period[T.pre]               21.7417     12.089      1.798      0.072      -1.953      45.437
group[T.1]:period[T.pre]  -223.1779     27.134     -8.225      0.000    -276.360    -169.995
============================================================================================
 

Редактировать:

Поскольку ваша сводная статистика показывает, что ваше распределение сильно искажено, самонастройка на самом деле является более надежным методом оценки доверительных интервалов:

 r = 1000
bootstrap = np.zeros(r)

for i in range(0, r):
    sample_index = np.random.choice(a=range(0, df.shape[0]), size=df.shape[0], replace=True)
    df_sample = df.iloc[sample_index]
    model = smf.glm('minutes ~ group * period', df_sample, family=sm.families.Gaussian()).fit()
    bootstrap[i] = model.params.iloc[3]  # interaction

bootstrap = pd.DataFrame(bootstrap, columns=['interaction'])
print(bootstrap.quantile([0.025, 0.975]).T)
 

Вывод:

                   0.025       0.975
interaction -273.524899 -175.373177