Skip to content

Commit ebee053

Browse files
committed
Add 'decrease' direction to ROPE probability and update docs
Extended the _compute_rope_probability function to support a 'decrease' direction, returning the probability that the effect is less than -min_effect. Added corresponding unit test. Updated documentation to clarify ROPE calculation for all directions and expanded reporting statistics and usage examples.
1 parent dba0975 commit ebee053

File tree

3 files changed

+72
-6
lines changed

3 files changed

+72
-6
lines changed

causalpy/reporting.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,10 @@ def _compute_rope_probability(
134134
"""
135135
if direction == "two-sided":
136136
return float((np.abs(effect) > min_effect).mean().values)
137-
else:
137+
elif direction == "increase":
138138
return float((effect > min_effect).mean().values)
139+
elif direction == "decrease":
140+
return float((effect < -min_effect).mean().values)
139141

140142

141143
def _format_number(x: float, decimals: int = 2) -> str:

causalpy/tests/test_reporting.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,21 @@ def test_compute_rope_probability_one_sided():
10071007
assert result == 0.2 # 1 out of 5
10081008

10091009

1010+
def test_compute_rope_probability_decrease():
1011+
"""Test _compute_rope_probability with direction='decrease'."""
1012+
import xarray as xr
1013+
1014+
from causalpy.reporting import _compute_rope_probability
1015+
1016+
# Create mock effect posterior with negative values
1017+
effect = xr.DataArray([0.5, -1.5, -2.5, -0.5, -3.0])
1018+
1019+
result = _compute_rope_probability(effect, min_effect=2.0, direction="decrease")
1020+
1021+
# effect < -2.0 for 2 values: -2.5, -3.0
1022+
assert result == 0.4 # 2 out of 5
1023+
1024+
10101025
def test_format_number():
10111026
"""Test _format_number helper."""
10121027
from causalpy.reporting import _format_number

docs/source/knowledgebase/reporting_statistics.md

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,25 @@ CausalPy supports two modeling frameworks, each with its own statistical paradig
1515
The reporting layer automatically detects which type of model you're using and generates appropriate statistics. You don't need to specify the statistical approach.
1616
:::
1717

18+
## Experiment Support
19+
20+
The `effect_summary()` method is available for the following experiment types:
21+
22+
| Experiment Type | PyMC Models | Scikit-learn (OLS) Models |
23+
|----------------|-------------|---------------------------|
24+
| Difference-in-Differences | ✅ Full support | ✅ Full support |
25+
| Regression Discontinuity | ✅ Full support | ✅ Full support |
26+
| Regression Kink | ✅ Full support | ❌ Not implemented |
27+
| Interrupted Time Series | ✅ Full support | ✅ Full support |
28+
| Synthetic Control | ✅ Full support | ✅ Full support |
29+
| PrePostNEGD | ❌ Use `.summary()` instead | ❌ Use `.summary()` instead |
30+
| Instrumental Variable | ❌ Not available | ❌ Not available |
31+
| Inverse Propensity Weighting | ❌ Not available | ❌ Not available |
32+
33+
:::{note}
34+
For experiments marked with ❌, use the experiment's `.summary()` method for results.
35+
:::
36+
1837
---
1938

2039
## Bayesian Statistics (PyMC Models)
@@ -69,8 +88,12 @@ Bayesian hypothesis testing uses posterior probabilities directly, making the in
6988
- **Example:** If `p_gt_0 = 0.95`, there's a 95% probability the effect is positive
7089

7190
**Two-Sided Tests**
72-
- `p_two_sided`: Two-sided posterior probability (analogous to two-sided p-value)
73-
- `prob_of_effect`: Probability of an effect in either direction (1 - p_two_sided)
91+
- `p_two_sided`: Probability of observing an effect at least this extreme in either direction
92+
- **Calculation:** `2 × min(P(effect > 0), P(effect < 0))`
93+
- This mirrors the frequentist two-sided p-value approach
94+
- Example: If 97% of posterior is > 0 and 3% is < 0, then p_two_sided = 2 × 0.03 = 0.06
95+
- `prob_of_effect`: Probability of a non-zero effect in either direction (1 - p_two_sided)
96+
- Continuing the example: prob_of_effect = 1 - 0.06 = 0.94 (94% probability of some effect)
7497
- **When to use:** When you don't have a directional hypothesis
7598
- **Interpretation:** `prob_of_effect = 0.95` means 95% probability of a non-zero effect
7699

@@ -93,8 +116,9 @@ Unlike frequentist p-values, Bayesian posterior probabilities answer the questio
93116

94117
**How it works:**
95118
1. You specify `min_effect` (the smallest effect size you consider meaningful)
96-
2. For directional tests: `p_rope` = P(|effect| > min_effect)
97-
3. For two-sided tests: `p_rope` = P(|effect| > min_effect)
119+
2. For "increase" direction: `p_rope` = P(effect > min_effect)
120+
3. For "decrease" direction: `p_rope` = P(effect < -min_effect)
121+
4. For "two-sided" direction: `p_rope` = P(|effect| > min_effect)
98122

99123
**Example:**
100124
```python
@@ -235,6 +259,29 @@ For experiments with multiple post-treatment time points:
235259

236260
## Usage Examples
237261

262+
### Understanding the Output
263+
264+
The `effect_summary()` method returns an `EffectSummary` object with two attributes:
265+
266+
**Numerical Summary (.table):**
267+
268+
Returns a pandas DataFrame with all statistics:
269+
270+
```python
271+
summary = result.effect_summary()
272+
print(summary.table)
273+
```
274+
275+
**Prose Summary (.text):**
276+
277+
Returns a human-readable interpretation ready for reports:
278+
279+
```python
280+
print(summary.text)
281+
# Output: "The average treatment effect was 2.50 (95% HDI [1.20, 3.80]),
282+
# with a posterior probability of an increase of 0.975."
283+
```
284+
238285
### Basic usage (default Bayesian):
239286
```python
240287
import causalpy as cp
@@ -267,7 +314,9 @@ summary = result.effect_summary(
267314
direction="increase",
268315
min_effect=2.0 # ROPE analysis
269316
)
270-
# Now summary.table includes p_rope column
317+
# Access results
318+
print(summary.table) # p_rope column included
319+
print(summary.text) # Prose interpretation
271320
```
272321

273322
### For time-series experiments with custom window:

0 commit comments

Comments
 (0)