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.946486 True 9.601481
1 0.830639 False 1.848806
2 -0.146411 True 6.541884
3 1.111248 True 6.600895
4 -0.059885 True 3.016531
... ... ... ...
995 0.091708 True 4.413204
996 0.632677 True 4.706617
997 0.437943 True 5.230384
998 2.558886 True 9.743775
999 1.665350 True 8.772056

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 0.397159 False 0.659022 0.369388 2.707182
1 2.229516 False 4.665517 0.046024 21.727891
2 0.463989 False 1.447101 0.348441 2.869930
3 1.154969 False 1.776468 0.172590 5.794071
4 -0.686871 False -2.221900 0.719539 1.389778
... ... ... ... ... ...
995 0.651798 False 0.020120 0.292806 3.415234
996 1.505612 False 1.669227 0.114544 8.730250
997 -1.652279 False -3.144685 0.905302 1.104604
998 0.374365 False 1.510566 0.376651 2.654976
999 1.025267 False 1.324563 0.199303 5.017491

1000 rows × 5 columns

[7]:
cdf_1
[7]:
W0 v0 y propensity_score weight
0 0.007914 True 5.214271 0.501122 1.995523
1 1.886673 True 8.859618 0.928531 1.076969
2 0.988608 True 6.329401 0.792606 1.261660
3 0.801659 True 6.300524 0.747625 1.337569
4 0.382875 True 6.355585 0.626067 1.597273
... ... ... ... ... ...
995 1.167872 True 6.102895 0.829906 1.204956
996 1.473154 True 7.980661 0.880893 1.135211
997 0.553763 True 6.335199 0.678791 1.473208
998 0.259339 True 6.149736 0.585905 1.706763
999 1.017072 True 6.894531 0.798909 1.251707

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.13983696214543$
[9]:
1.96*(cdf_1['y'] - cdf_0['y']).std() / np.sqrt(len(df))
[9]:
$\displaystyle 0.172382321522194$

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.976
Model: OLS Adj. R-squared (uncentered): 0.976
Method: Least Squares F-statistic: 2.047e+04
Date: Sun, 19 Jul 2026 Prob (F-statistic): 0.00
Time: 05:31:53 Log-Likelihood: -1370.0
No. Observations: 1000 AIC: 2744.
Df Residuals: 998 BIC: 2754.
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
x1 1.8546 0.035 53.162 0.000 1.786 1.923
x2 4.9893 0.053 93.914 0.000 4.885 5.094
Omnibus: 2.229 Durbin-Watson: 1.924
Prob(Omnibus): 0.328 Jarque-Bera (JB): 2.284
Skew: 0.112 Prob(JB): 0.319
Kurtosis: 2.933 Cond. No. 2.85


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.