Demo for the DoWhy causal API#

We show a simple example of adding a causal extension to any dataframe.

[1]:
import dowhy
dowhy.enable_notebook_rendering()

import dowhy.datasets
import dowhy.api
from dowhy.graph import build_graph_from_str

import numpy as np
import pandas as pd

from statsmodels.api import OLS
[2]:
data = dowhy.datasets.linear_dataset(beta=5,
        num_common_causes=1,
        num_instruments = 0,
        num_samples=1000,
        treatment_is_binary=True)
df = data['df']
df['y'] = df['y'] + np.random.normal(size=len(df)) # Adding noise to data. Without noise, the variance in Y|X, Z is zero, and mcmc fails.
nx_graph = build_graph_from_str(data["dot_graph"])

treatment= data["treatment_name"][0]
outcome = data["outcome_name"][0]
common_cause = data["common_causes_names"][0]
df
[2]:
W0 v0 y
0 1.382710 True 8.060313
1 1.472841 True 8.334425
2 0.306800 True 7.820742
3 -0.430429 False -0.455280
4 0.618401 True 6.239341
... ... ... ...
995 1.002819 True 9.206626
996 0.213227 True 6.627189
997 3.054601 True 10.629182
998 0.230412 True 6.199779
999 1.725729 True 8.568986

1000 rows × 3 columns

[3]:
# data['df'] is just a regular pandas.DataFrame
df.causal.do(x=treatment,
             variable_types={treatment: 'b', outcome: 'c', common_cause: 'c'},
             outcome=outcome,
             common_causes=[common_cause],
            ).groupby(treatment).mean().plot(y=outcome, kind='bar')
[3]:
<Axes: xlabel='v0'>
../_images/example_notebooks_dowhy_causal_api_3_1.png
[4]:
df.causal.do(x={treatment: 1},
              variable_types={treatment:'b', outcome: 'c', common_cause: 'c'},
              outcome=outcome,
              method='weighting',
              common_causes=[common_cause]
              ).groupby(treatment).mean().plot(y=outcome, kind='bar')
[4]:
<Axes: xlabel='v0'>
../_images/example_notebooks_dowhy_causal_api_4_1.png
[5]:
cdf_1 = df.causal.do(x={treatment: 1},
              variable_types={treatment: 'b', outcome: 'c', common_cause: 'c'},
              outcome=outcome,
              graph=nx_graph
              )

cdf_0 = df.causal.do(x={treatment: 0},
              variable_types={treatment: 'b', outcome: 'c', common_cause: 'c'},
              outcome=outcome,
              graph=nx_graph
              )

[6]:
cdf_0
[6]:
W0 v0 y propensity_score weight
0 1.857935 False 1.035500 0.044035 22.709352
1 1.441613 False 2.773858 0.080289 12.455070
2 1.161925 False 1.867316 0.118267 8.455410
3 2.289897 False 2.249772 0.023179 43.143088
4 -0.360114 False -0.769929 0.581352 1.720127
... ... ... ... ... ...
995 0.859367 False 0.020092 0.175907 5.684812
996 0.394338 False -0.685477 0.303598 3.293825
997 1.611883 False 1.782004 0.062979 15.878280
998 0.136252 False -2.412841 0.393196 2.543263
999 2.017139 False 2.659729 0.034817 28.721824

1000 rows × 5 columns

[7]:
cdf_1
[7]:
W0 v0 y propensity_score weight
0 0.413405 True 5.595959 0.702556 1.423374
1 1.392446 True 7.668865 0.913957 1.094144
2 0.726007 True 6.576239 0.792414 1.261967
3 2.509753 True 8.063277 0.983352 1.016930
4 -0.564910 True 4.925555 0.344610 2.901828
... ... ... ... ... ...
995 0.428467 True 5.023315 0.707367 1.413694
996 2.598522 True 8.081928 0.985443 1.014772
997 1.304708 True 6.729470 0.902753 1.107722
998 2.152605 True 7.396697 0.971536 1.029298
999 1.264880 True 6.376408 0.897250 1.114516

1000 rows × 5 columns

Comparing the estimate to Linear Regression#

First, estimating the effect using the causal data frame, and the 95% confidence interval.

[8]:
(cdf_1['y'] - cdf_0['y']).mean()
[8]:
$\displaystyle 5.43679388164681$
[9]:
1.96*(cdf_1['y'] - cdf_0['y']).std() / np.sqrt(len(df))
[9]:
$\displaystyle 0.144027847284715$

Comparing to the estimate from OLS.

[10]:
model = OLS(np.asarray(df[outcome]), np.asarray(df[[common_cause, treatment]], dtype=np.float64))
result = model.fit()
result.summary()
[10]:
OLS Regression Results
Dep. Variable: y R-squared (uncentered): 0.974
Model: OLS Adj. R-squared (uncentered): 0.974
Method: Least Squares F-statistic: 1.864e+04
Date: Sun, 25 Oct 2026 Prob (F-statistic): 0.00
Time: 21:11:19 Log-Likelihood: -1394.5
No. Observations: 1000 AIC: 2793.
Df Residuals: 998 BIC: 2803.
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
x1 1.4748 0.035 42.029 0.000 1.406 1.544
x2 5.0245 0.054 93.093 0.000 4.919 5.130
Omnibus: 3.385 Durbin-Watson: 2.003
Prob(Omnibus): 0.184 Jarque-Bera (JB): 3.256
Skew: 0.134 Prob(JB): 0.196
Kurtosis: 3.078 Cond. No. 2.97


Notes:
[1] R² is computed without centering (uncentered) since the model does not contain a constant.
[2] Standard Errors assume that the covariance matrix of the errors is correctly specified.