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 -2.247335 False -0.090581
1 -1.503762 False 1.307209
2 -0.777193 False 0.105160
3 -1.585974 False -0.060173
4 -1.379426 False 0.122786
... ... ... ...
995 -1.849564 False -1.295807
996 0.005362 True 6.482623
997 -0.965112 False -0.523507
998 1.619186 True 5.751097
999 -2.210199 False -1.342487

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.116747 False -0.650379 0.533290 1.875151
1 0.398550 False 1.625360 0.278994 3.584302
2 -0.638976 False -0.313215 0.773948 1.292077
3 -2.445989 False -1.324983 0.993490 1.006553
4 0.063364 False 0.187604 0.439026 2.277769
... ... ... ... ... ...
995 0.277661 False 1.555587 0.332827 3.004564
996 -0.105346 False -1.668103 0.527323 1.896371
997 0.986471 False -0.110637 0.101117 9.889561
998 1.120470 False 0.170661 0.078244 12.780606
999 -0.633969 False -1.697038 0.772102 1.295166

1000 rows × 5 columns

[7]:
cdf_1
[7]:
W0 v0 y propensity_score weight
0 0.918400 True 4.068973 0.885120 1.129790
1 -0.055773 True 5.436169 0.498692 2.005244
2 -1.036358 True 5.039064 0.112468 8.891390
3 -2.387011 True 3.407307 0.007363 135.821579
4 0.010005 True 4.396085 0.533199 1.875472
... ... ... ... ... ...
995 -1.313551 True 4.976713 0.066097 15.129279
996 -0.645481 True 5.608666 0.223670 4.470877
997 -1.079661 True 3.187964 0.103701 9.643144
998 0.563046 True 4.409812 0.785012 1.273865
999 0.083991 True 6.139209 0.571619 1.749416

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

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.904
Model: OLS Adj. R-squared (uncentered): 0.903
Method: Least Squares F-statistic: 4673.
Date: Tue, 08 Sep 2026 Prob (F-statistic): 0.00
Time: 22:36:31 Log-Likelihood: -1380.6
No. Observations: 1000 AIC: 2765.
Df Residuals: 998 BIC: 2775.
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
x1 0.4951 0.026 19.174 0.000 0.444 0.546
x2 5.0548 0.054 92.799 0.000 4.948 5.162
Omnibus: 2.336 Durbin-Watson: 1.994
Prob(Omnibus): 0.311 Jarque-Bera (JB): 2.196
Skew: -0.104 Prob(JB): 0.334
Kurtosis: 3.097 Cond. No. 2.12


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.