Skip to content

Commit f1e5a0f

Browse files
committed
Deprecated cubic spline estimator - functionality subsumed by LR estimator
1 parent 3123ceb commit f1e5a0f

4 files changed

Lines changed: 30 additions & 128 deletions

File tree

causal_testing/estimation/abstract_regression_estimator.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import Any
77

88
import pandas as pd
9-
from patsy import ModelDesc, dmatrices, dmatrix # pylint: disable = no-name-in-module
9+
from patsy import ModelDesc, build_design_matrices, dmatrices # pylint: disable = no-name-in-module
1010
from statsmodels.regression.linear_model import RegressionResultsWrapper
1111

1212
from causal_testing.estimation.abstract_estimator import Estimator
@@ -114,7 +114,7 @@ def _setup_covariates(self, df: pd.DataFrame) -> pd.Series:
114114
_, covariate_data = dmatrices(self.formula, df, return_type="dataframe")
115115
df = pd.concat([df, covariate_data[[col for col in covariate_data.columns if col not in df]]], axis=1)
116116
covariates = covariate_data.columns.tolist()
117-
return covariates, df.dropna(subset=covariates)
117+
return df.dropna(subset=covariates), covariates, covariate_data.design_info
118118

119119
@property
120120
@abstractmethod
@@ -143,8 +143,9 @@ def fit_model(self, df: pd.DataFrame) -> RegressionResultsWrapper:
143143
:param df: The data to use.
144144
:return: The model after fitting to data.
145145
"""
146-
covariates, df = self._setup_covariates(df)
146+
df, covariates, design_info = self._setup_covariates(df)
147147
model = self.regressor(df[self.outcome_variable], df[covariates]).fit(disp=0)
148+
model.design_info = design_info
148149
return model
149150

150151
def treatment_columns(self, model: RegressionResultsWrapper) -> list[str]:
@@ -180,7 +181,7 @@ def _predict(self, df) -> pd.DataFrame:
180181

181182
for k, v in self.adjustment_config.items():
182183
x[k] = v
183-
x = dmatrix(self.formula.split("~")[1], x, return_type="dataframe")
184+
x = build_design_matrices([model.design_info], x, return_type="dataframe")[0]
184185

185186
return model.get_prediction(x).summary_frame()
186187

causal_testing/estimation/cubic_spline_estimator.py

Lines changed: 0 additions & 88 deletions
This file was deleted.

tests/estimation_tests/test_cubic_spline_estimator.py

Lines changed: 0 additions & 36 deletions
This file was deleted.

tests/estimation_tests/test_linear_regression_estimator.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,3 +406,28 @@ def test_categorical_confidence_intervals(self):
406406
self.assertTrue(
407407
effect_estimate.ci_high.round(2).equals(pd.Series({"color[T.grey]": 23.95, "color[T.orange]": 17.08}))
408408
)
409+
410+
def test_program_11_3_linear_regression(self):
411+
"""Test whether the cublic_spline regression implementation produces the same results as program 11.3 (p. 162).
412+
https://www.hsph.harvard.edu/miguel-hernan/wp-content/uploads/sites/1268/2023/10/hernanrobins_WhatIf_30sep23.pdf
413+
Slightly modified as Hernan et al. use linear regression for this example.
414+
"""
415+
416+
df = load_chapter_11_df()
417+
418+
cublic_spline_estimator = LinearRegressionEstimator(
419+
treatment_variable="treatments",
420+
outcome_variable="outcomes",
421+
treatment_value=1,
422+
control_value=0,
423+
formula="outcomes ~ cr(treatments, df=3)",
424+
)
425+
426+
ate_1 = cublic_spline_estimator.estimate_ate_calculated(df).value
427+
428+
cublic_spline_estimator.treatment_value = 2
429+
ate_2 = cublic_spline_estimator.estimate_ate_calculated(df).value
430+
431+
# Doubling the treatemebnt value should roughly but not exactly double the ATE
432+
self.assertNotEqual(ate_1[0] * 2, ate_2[0])
433+
self.assertAlmostEqual(ate_1[0] * 2, ate_2[0])

0 commit comments

Comments
 (0)