Skip to content

Commit cd9241f

Browse files
authored
Merge pull request #375 from CITCOM-project/jmafoster1/sharr
Removed adequacy warning catching and made alpha an MR parameter
2 parents 6325ced + 32fbf15 commit cd9241f

4 files changed

Lines changed: 46 additions & 37 deletions

File tree

causal_testing/testing/causal_test_adequacy.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
from itertools import combinations
88

99
import pandas as pd
10-
from lifelines.exceptions import ConvergenceError
11-
from numpy.linalg import LinAlgError
1210

1311
from causal_testing.specification.causal_dag import CausalDAG
1412
from causal_testing.testing.causal_test_case import CausalTestCase
@@ -104,21 +102,9 @@ def measure_adequacy(self):
104102
estimator.df = estimator.df[estimator.df[self.group_by].isin(ids)]
105103
else:
106104
estimator.df = estimator.df.sample(len(estimator.df), replace=True, random_state=i)
107-
try:
108-
result = self.test_case.execute_test(estimator)
109-
outcomes.append(self.test_case.expected_causal_effect.apply(result))
110-
results.append(result.effect_estimate.to_df())
111-
except LinAlgError:
112-
logger.warning("Adequacy LinAlgError")
113-
continue
114-
except ConvergenceError:
115-
logger.warning("Adequacy ConvergenceError")
116-
continue
117-
except ValueError as e:
118-
logger.warning(f"Adequacy ValueError: {e}")
119-
continue
120-
# outcomes = [self.test_case.expected_causal_effect.apply(c) for c in results]
121-
# results = pd.concat([c.effect_estimate.to_df() for c in results])
105+
result = self.test_case.execute_test(estimator)
106+
outcomes.append(self.test_case.expected_causal_effect.apply(result))
107+
results.append(result.effect_estimate.to_df())
122108
results = pd.concat(results)
123109
results["var"] = results.index
124110
results["passed"] = outcomes

causal_testing/testing/metamorphic_relation.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,38 +33,62 @@ def __eq__(self, other):
3333
same_adjustment_set = set(self.adjustment_vars) == set(other.adjustment_vars)
3434
return same_type and same_treatment and same_outcome and same_effect and same_adjustment_set
3535

36-
37-
class ShouldCause(MetamorphicRelation):
38-
"""Class representing a should cause metamorphic relation."""
39-
4036
def to_json_stub(
4137
self,
4238
skip: bool = False,
4339
estimate_type: str = "coefficient",
4440
effect_type: str = "direct",
4541
estimator: str = "LinearRegressionEstimator",
42+
alpha: float = 0.05,
4643
) -> dict:
4744
"""
4845
Convert to a JSON frontend stub string for user customisation.
4946
:param skip: Whether to skip the test (default False).
5047
:param effect_type: The type of causal effect to consider (total or direct)
5148
:param estimate_type: The estimate type to use when evaluating tests
5249
:param estimator: The name of the estimator class to use when evaluating the test
50+
:param alpha: The significance level to use when calculating the confidence intervals
5351
"""
5452
return {
5553
"name": str(self),
5654
"estimator": estimator,
5755
"estimate_type": estimate_type,
5856
"effect": effect_type,
5957
"treatment_variable": self.base_test_case.treatment_variable,
60-
"expected_effect": {self.base_test_case.outcome_variable: "SomeEffect"},
6158
"formula": (
6259
f"{self.base_test_case.outcome_variable} ~ "
6360
f"{' + '.join([self.base_test_case.treatment_variable] + self.adjustment_vars)}"
6461
),
62+
"alpha": alpha,
6563
"skip": skip,
6664
}
6765

66+
67+
class ShouldCause(MetamorphicRelation):
68+
"""Class representing a should cause metamorphic relation."""
69+
70+
def to_json_stub(
71+
self,
72+
skip: bool = False,
73+
estimate_type: str = "coefficient",
74+
effect_type: str = "direct",
75+
estimator: str = "LinearRegressionEstimator",
76+
alpha: float = 0.05,
77+
) -> dict:
78+
"""
79+
Convert to a JSON frontend stub string for user customisation.
80+
:param skip: Whether to skip the test (default False).
81+
:param effect_type: The type of causal effect to consider (total or direct)
82+
:param estimate_type: The estimate type to use when evaluating tests
83+
:param estimator: The name of the estimator class to use when evaluating the test
84+
:param alpha: The significance level to use when calculating the confidence intervals
85+
"""
86+
return super().to_json_stub(
87+
skip=skip, estimate_type=estimate_type, effect_type=effect_type, estimator=estimator, alpha=alpha
88+
) | {
89+
"expected_effect": {self.base_test_case.outcome_variable: "SomeEffect"},
90+
}
91+
6892
def __str__(self):
6993
formatted_str = f"{self.base_test_case.treatment_variable} --> {self.base_test_case.outcome_variable}"
7094
if self.adjustment_vars:
@@ -81,27 +105,20 @@ def to_json_stub(
81105
estimate_type: str = "coefficient",
82106
effect_type: str = "direct",
83107
estimator: str = "LinearRegressionEstimator",
108+
alpha: float = 0.05,
84109
) -> dict:
85110
"""
86111
Convert to a JSON frontend stub string for user customisation.
87112
:param skip: Whether to skip the test (default False).
88113
:param effect_type: The type of causal effect to consider (total or direct)
89114
:param estimate_type: The estimate type to use when evaluating tests
90115
:param estimator: The name of the estimator class to use when evaluating the test
116+
:param alpha: The significance level to use when calculating the confidence intervals
91117
"""
92-
return {
93-
"name": str(self),
94-
"estimator": estimator,
95-
"estimate_type": estimate_type,
96-
"effect": effect_type,
97-
"treatment_variable": self.base_test_case.treatment_variable,
118+
return super().to_json_stub(
119+
skip=skip, estimate_type=estimate_type, effect_type=effect_type, estimator=estimator, alpha=alpha
120+
) | {
98121
"expected_effect": {self.base_test_case.outcome_variable: "NoEffect"},
99-
"formula": (
100-
f"{self.base_test_case.outcome_variable} ~ "
101-
f"{' + '.join([self.base_test_case.treatment_variable] + self.adjustment_vars)}"
102-
),
103-
"alpha": 0.05,
104-
"skip": skip,
105122
}
106123

107124
def __str__(self):

pyproject.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ dependencies = [
1818
"lifelines~=0.30.0",
1919
"networkx>=3.4,<3.5",
2020
"numpy>=1.26.0,<=2.2.0",
21-
"pandas>=2.1",
21+
"pandas>=2.1,<3",
2222
"scikit_learn~=1.4",
2323
"scipy>=1.12.0,<=1.16.2",
2424
"statsmodels~=0.14",
@@ -100,8 +100,12 @@ skip_missing_interpreters = false # fail if devs don’t have all required Pytho
100100
description = "Run pytest under {base_python}"
101101
extras = ["dev","test"]
102102
deps = ["pytest"]
103-
commands = [["pytest"]]
104-
103+
commands = [
104+
[
105+
"pytest",
106+
"{posargs:tests}",
107+
],
108+
]
105109
# Automatically test for type-checking (TODO: enable type checking in env_list in the future)
106110
[tool.tox.env.type]
107111
description = "Run type checks with mypy on the codebase"

tests/testing_tests/test_metamorphic_relations.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def test_should_cause_json_stub(self):
104104
"formula": "Z ~ X1",
105105
"treatment_variable": "X1",
106106
"name": "X1 --> Z",
107+
"alpha": 0.05,
107108
"skip": False,
108109
},
109110
)
@@ -130,6 +131,7 @@ def test_should_cause_logistic_json_stub(self):
130131
"formula": "Z ~ X1",
131132
"treatment_variable": "X1",
132133
"name": "X1 --> Z",
134+
"alpha": 0.05,
133135
"skip": False,
134136
},
135137
)

0 commit comments

Comments
 (0)