Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion causal_testing/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from causal_testing.specification.causal_specification import CausalSpecification
from causal_testing.testing.causal_test_case import CausalTestCase
from causal_testing.testing.base_test_case import BaseTestCase
from causal_testing.testing.causal_test_outcome import NoEffect, SomeEffect, Positive, Negative
from causal_testing.testing.causal_effect import NoEffect, SomeEffect, Positive, Negative
from causal_testing.testing.causal_test_result import CausalTestResult, TestValue
from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator
from causal_testing.estimation.logistic_regression_estimator import LogisticRegressionEstimator
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pylint: disable=too-few-public-methods
"""This module contains the CausalTestOutcome abstract class, as well as the concrete extension classes:
"""This module contains the CausalEffect abstract class, as well as the concrete extension classes:
ExactValue, Positive, Negative, SomeEffect, NoEffect"""

from abc import ABC, abstractmethod
Expand All @@ -9,7 +9,7 @@
from causal_testing.testing.causal_test_result import CausalTestResult


class CausalTestOutcome(ABC):
class CausalEffect(ABC):
"""An abstract class representing an expected causal effect."""

@abstractmethod
Expand All @@ -23,7 +23,7 @@
return type(self).__name__


class SomeEffect(CausalTestOutcome):
class SomeEffect(CausalEffect):
"""An extension of TestOutcome representing that the expected causal effect should not be zero."""

def apply(self, res: CausalTestResult) -> bool:
Expand All @@ -41,7 +41,7 @@
raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome")


class NoEffect(CausalTestOutcome):
class NoEffect(CausalEffect):
"""An extension of TestOutcome representing that the expected causal effect should be zero."""

def __init__(self, atol: float = 1e-10, ctol: float = 0.05):
Expand Down Expand Up @@ -73,22 +73,37 @@
raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome")


class ExactValue(SomeEffect):
class ExactValue(CausalEffect):
"""An extension of TestOutcome representing that the expected causal effect should be a specific value."""

def __init__(self, value: float, atol: float = None):
def __init__(self, value: float, atol: float = None, ci_low: float = None, ci_high: float = None):
if (ci_low is not None) ^ (ci_high is not None):
raise ValueError("If specifying confidence intervals, must specify `ci_low` and `ci_high` parameters.")
if atol is not None and atol < 0:
raise ValueError("Tolerance must be an absolute (positive) value.")

self.value = value
if atol is None:
self.atol = abs(value * 0.05)
else:
self.atol = atol
if self.atol < 0:
raise ValueError("Tolerance must be an absolute value.")
self.ci_low = ci_low
self.ci_high = ci_high
self.atol = atol if atol is not None else abs(value * 0.05)

if self.ci_low is not None and self.ci_high is not None:
if not self.ci_low <= self.value <= self.ci_high:
raise ValueError("Specified value falls outside the specified confidence intervals.")
if self.value - self.atol < self.ci_low or self.value + self.atol > self.ci_high:
raise ValueError(

Check warning on line 94 in causal_testing/testing/causal_effect.py

View check run for this annotation

Codecov / codecov/patch

causal_testing/testing/causal_effect.py#L94

Added line #L94 was not covered by tests
"Arithmetic tolerance falls outside the confidence intervals."
"Try specifying a smaller value of atol."
)

def apply(self, res: CausalTestResult) -> bool:
if res.ci_valid():
return super().apply(res) and np.isclose(res.test_value.value, self.value, atol=self.atol)
return np.isclose(res.test_value.value, self.value, atol=self.atol)
close = np.isclose(res.test_value.value, self.value, atol=self.atol)
if res.ci_valid() and self.ci_low is not None and self.ci_high is not None:
return all(
close and self.ci_low <= ci_low and self.ci_high >= ci_high
for ci_low, ci_high in zip(res.ci_low(), res.ci_high())
)
return close

def __str__(self):
return f"ExactValue: {self.value}±{self.atol}"
Expand Down
4 changes: 2 additions & 2 deletions causal_testing/testing/causal_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Any

from causal_testing.specification.variable import Variable
from causal_testing.testing.causal_test_outcome import CausalTestOutcome
from causal_testing.testing.causal_effect import CausalEffect
from causal_testing.testing.base_test_case import BaseTestCase
from causal_testing.estimation.abstract_estimator import Estimator
from causal_testing.testing.causal_test_result import CausalTestResult, TestValue
Expand All @@ -26,7 +26,7 @@ def __init__(
# pylint: disable=too-many-arguments
self,
base_test_case: BaseTestCase,
expected_causal_effect: CausalTestOutcome,
expected_causal_effect: CausalEffect,
estimate_type: str = "ate",
estimate_params: dict = None,
effect_modifier_configuration: dict[Variable:Any] = None,
Expand Down
2 changes: 1 addition & 1 deletion dafni/main_dafni.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import pandas as pd
from causal_testing.specification.scenario import Scenario
from causal_testing.specification.variable import Input, Output
from causal_testing.testing.causal_test_outcome import Positive, Negative, NoEffect, SomeEffect
from causal_testing.testing.causal_effect import Positive, Negative, NoEffect, SomeEffect
from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator
from causal_testing.estimation.logistic_regression_estimator import LogisticRegressionEstimator
from causal_testing.json_front.json_class import JsonUtility
Expand Down
2 changes: 1 addition & 1 deletion docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ the given output and input and the desired effect. This information is the minim

from causal_testing.testing.base_test_case import BaseTestCase
from causal_testing.testing.causal_test_case import CausalTestCase
from causal_testing.testing.causal_test_outcome import Positive
from causal_testing.testing.causal_effect import Positive
from causal_testing.testing.effect import Effect

base_test_case = BaseTestCase(
Expand Down
2 changes: 1 addition & 1 deletion examples/covasim_/doubling_beta/example_beta.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import numpy as np
from causal_testing.specification.variable import Input, Output
from causal_testing.testing.causal_test_case import CausalTestCase
from causal_testing.testing.causal_test_outcome import Positive
from causal_testing.testing.causal_effect import Positive
from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator
from causal_testing.testing.base_test_case import BaseTestCase

Expand Down
2 changes: 1 addition & 1 deletion examples/covasim_/vaccinating_elderly/example_vaccine.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from causal_testing.specification.variable import Input, Output
from causal_testing.specification.causal_specification import CausalSpecification
from causal_testing.testing.causal_test_case import CausalTestCase
from causal_testing.testing.causal_test_outcome import Positive, Negative, NoEffect
from causal_testing.testing.causal_effect import Positive, Negative, NoEffect
from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator
from causal_testing.testing.base_test_case import BaseTestCase

Expand Down
2 changes: 1 addition & 1 deletion examples/lr91/example_max_conductances.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from causal_testing.specification.variable import Input, Output
from causal_testing.specification.causal_specification import CausalSpecification
from causal_testing.testing.causal_test_case import CausalTestCase
from causal_testing.testing.causal_test_outcome import Positive, Negative, NoEffect
from causal_testing.testing.causal_effect import Positive, Negative, NoEffect
from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator
from causal_testing.testing.base_test_case import BaseTestCase
from matplotlib.pyplot import rcParams
Expand Down
2 changes: 1 addition & 1 deletion examples/poisson-line-process/example_pure_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from causal_testing.specification.variable import Input, Output
from causal_testing.specification.causal_specification import CausalSpecification
from causal_testing.testing.causal_test_case import CausalTestCase
from causal_testing.testing.causal_test_outcome import ExactValue, Positive
from causal_testing.testing.causal_effect import ExactValue, Positive
from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator
from causal_testing.estimation.abstract_estimator import Estimator
from causal_testing.testing.base_test_case import BaseTestCase
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import unittest
import pandas as pd
from causal_testing.testing.causal_test_outcome import ExactValue, SomeEffect, Positive, Negative, NoEffect
from causal_testing.testing.causal_effect import ExactValue, SomeEffect, Positive, Negative, NoEffect
from causal_testing.testing.causal_test_result import CausalTestResult, TestValue
from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator
from causal_testing.utils.validation import CausalValidator
from causal_testing.testing.base_test_case import BaseTestCase
from causal_testing.specification.variable import Input, Output


class TestCausalTestOutcome(unittest.TestCase):
"""Test the TestCausalTestOutcome basic methods."""
class TestCausalEffect(unittest.TestCase):
"""Test the TestCausalEffect basic methods."""

def setUp(self) -> None:
base_test_case = BaseTestCase(Input("A", float), Output("A", float))
Expand Down Expand Up @@ -181,6 +181,28 @@ def test_exactValue_pass_ci(self):
ev = ExactValue(5, 0.1)
self.assertTrue(ev.apply(ctr))

def test_exactValue_ci_pass_ci(self):
test_value = TestValue(type="ate", value=pd.Series(5.05))
ctr = CausalTestResult(
estimator=self.estimator,
test_value=test_value,
confidence_intervals=[pd.Series(4.1), pd.Series(5.9)],
effect_modifier_configuration=None,
)
ev = ExactValue(5, ci_low=4, ci_high=6)
self.assertTrue(ev.apply(ctr))

def test_exactValue_ci_fail_ci(self):
test_value = TestValue(type="ate", value=pd.Series(5.05))
ctr = CausalTestResult(
estimator=self.estimator,
test_value=test_value,
confidence_intervals=[pd.Series(3.9), pd.Series(6.1)],
effect_modifier_configuration=None,
)
ev = ExactValue(5, ci_low=4, ci_high=6)
self.assertFalse(ev.apply(ctr))

def test_exactValue_fail(self):
test_value = TestValue(type="ate", value=pd.Series(0))
ctr = CausalTestResult(
Expand All @@ -196,6 +218,22 @@ def test_invalid_atol(self):
with self.assertRaises(ValueError):
ExactValue(5, -0.1)

def test_unspecified_ci_high(self):
with self.assertRaises(ValueError):
ExactValue(5, ci_low=-0.1)

def test_unspecified_ci_low(self):
with self.assertRaises(ValueError):
ExactValue(5, ci_high=-0.1)

def test_invalid_ci_range(self):
with self.assertRaises(ValueError):
ExactValue(5, ci_low=6, ci_high=7, atol=0.05)

def test_invalid_ci_atol(self):
with self.assertRaises(ValueError):
ExactValue(1000, ci_low=1001, ci_high=1002, atol=0.05)

def test_invalid(self):
test_value = TestValue(type="invalid", value=pd.Series(5.05))
ctr = CausalTestResult(
Expand Down
2 changes: 1 addition & 1 deletion tests/testing_tests/test_causal_test_adequacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from causal_testing.testing.base_test_case import BaseTestCase
from causal_testing.testing.causal_test_case import CausalTestCase
from causal_testing.testing.causal_test_adequacy import DAGAdequacy
from causal_testing.testing.causal_test_outcome import NoEffect, SomeEffect
from causal_testing.testing.causal_effect import NoEffect, SomeEffect
from causal_testing.specification.scenario import Scenario
from causal_testing.testing.causal_test_adequacy import DataAdequacy
from causal_testing.specification.variable import Input, Output
Expand Down
2 changes: 1 addition & 1 deletion tests/testing_tests/test_causal_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from causal_testing.specification.variable import Input, Output
from causal_testing.specification.causal_dag import CausalDAG
from causal_testing.testing.causal_test_case import CausalTestCase
from causal_testing.testing.causal_test_outcome import ExactValue
from causal_testing.testing.causal_effect import ExactValue
from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator
from causal_testing.testing.base_test_case import BaseTestCase

Expand Down