correlation-tost 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arijana Bohr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,79 @@
1
+ Metadata-Version: 2.4
2
+ Name: correlation-tost
3
+ Version: 0.1.0
4
+ Summary: TOST equivalence testing for Pearson correlations.
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: numpy>=1.23
10
+ Requires-Dist: scipy>=1.9
11
+ Provides-Extra: test
12
+ Requires-Dist: pytest>=7; extra == "test"
13
+ Dynamic: license-file
14
+
15
+ # correlation-tost
16
+
17
+ A lightweight Python implementation of the two one-sided tests (TOST) procedure for equivalence testing of Pearson correlations.
18
+
19
+ The test uses Fisher's z transformation and has been numerically validated against R's `TOSTER::corsum_test`.
20
+
21
+ ## Installation
22
+
23
+ Install directly from GitHub with `pip`:
24
+
25
+ ```bash
26
+ pip install git+https://github.com/ArijanaBohr/correlation-tost.git
27
+ ```
28
+
29
+ **Requirements:** Python ≥ 3.9, NumPy, SciPy
30
+
31
+ ## Quick start
32
+
33
+
34
+ ```python
35
+ from correlation_tost import pearson_tost
36
+
37
+ result = pearson_tost(
38
+ observed=0.30, # observed Pearson correlation
39
+ target=0.30, # target Pearson correlation
40
+ n=10_000, # sample size
41
+ margin=0.10, # equivalence margin
42
+ alpha=0.05, # significance level
43
+ )
44
+
45
+ print(result["equivalent"]) # True / False
46
+ print(result["p_value"]) # overall TOST p-value
47
+ ```
48
+
49
+ The equivalence bounds are defined in Pearson correlation units as
50
+ `[target - margin, target + margin]`. Fisher's z transformation is applied
51
+ internally when performing the test.
52
+
53
+ ## Output
54
+
55
+ `pearson_tost` returns a dictionary with the following keys:
56
+
57
+ | Key | Description |
58
+ |----------------|---------------------------------------------------------------|
59
+ | `p_value` | Overall TOST p-value |
60
+ | `p_lower` | p-value for the lower-bound test |
61
+ | `p_upper` | p-value for the upper-bound test |
62
+ | `z_stat_lower` | Test statistic for the lower-bound test |
63
+ | `z_stat_upper` | Test statistic for the upper-bound test |
64
+ | `ci_lower` | Lower confidence interval bound |
65
+ | `ci_upper` | Upper confidence interval bound |
66
+ | `equivalent` | Whether equivalence is concluded at the specified `alpha` |
67
+
68
+ ## Validation
69
+
70
+ The implementation was independently validated against
71
+ `TOSTER::corsum_test(method = "pearson", alternative = "equivalence")`
72
+ across:
73
+
74
+ - positive, negative, and zero correlations
75
+ - multiple sample sizes
76
+ - multiple equivalence margins
77
+ - a range of correlation strengths
78
+
79
+ The package itself does **not** depend on R, rpy2, or TOSTER.
@@ -0,0 +1,65 @@
1
+ # correlation-tost
2
+
3
+ A lightweight Python implementation of the two one-sided tests (TOST) procedure for equivalence testing of Pearson correlations.
4
+
5
+ The test uses Fisher's z transformation and has been numerically validated against R's `TOSTER::corsum_test`.
6
+
7
+ ## Installation
8
+
9
+ Install directly from GitHub with `pip`:
10
+
11
+ ```bash
12
+ pip install git+https://github.com/ArijanaBohr/correlation-tost.git
13
+ ```
14
+
15
+ **Requirements:** Python ≥ 3.9, NumPy, SciPy
16
+
17
+ ## Quick start
18
+
19
+
20
+ ```python
21
+ from correlation_tost import pearson_tost
22
+
23
+ result = pearson_tost(
24
+ observed=0.30, # observed Pearson correlation
25
+ target=0.30, # target Pearson correlation
26
+ n=10_000, # sample size
27
+ margin=0.10, # equivalence margin
28
+ alpha=0.05, # significance level
29
+ )
30
+
31
+ print(result["equivalent"]) # True / False
32
+ print(result["p_value"]) # overall TOST p-value
33
+ ```
34
+
35
+ The equivalence bounds are defined in Pearson correlation units as
36
+ `[target - margin, target + margin]`. Fisher's z transformation is applied
37
+ internally when performing the test.
38
+
39
+ ## Output
40
+
41
+ `pearson_tost` returns a dictionary with the following keys:
42
+
43
+ | Key | Description |
44
+ |----------------|---------------------------------------------------------------|
45
+ | `p_value` | Overall TOST p-value |
46
+ | `p_lower` | p-value for the lower-bound test |
47
+ | `p_upper` | p-value for the upper-bound test |
48
+ | `z_stat_lower` | Test statistic for the lower-bound test |
49
+ | `z_stat_upper` | Test statistic for the upper-bound test |
50
+ | `ci_lower` | Lower confidence interval bound |
51
+ | `ci_upper` | Upper confidence interval bound |
52
+ | `equivalent` | Whether equivalence is concluded at the specified `alpha` |
53
+
54
+ ## Validation
55
+
56
+ The implementation was independently validated against
57
+ `TOSTER::corsum_test(method = "pearson", alternative = "equivalence")`
58
+ across:
59
+
60
+ - positive, negative, and zero correlations
61
+ - multiple sample sizes
62
+ - multiple equivalence margins
63
+ - a range of correlation strengths
64
+
65
+ The package itself does **not** depend on R, rpy2, or TOSTER.
@@ -0,0 +1,23 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "correlation-tost"
7
+ version = "0.1.0"
8
+ license = "MIT"
9
+ description = "TOST equivalence testing for Pearson correlations."
10
+ readme = "README.md"
11
+ requires-python = ">=3.9"
12
+ dependencies = [
13
+ "numpy>=1.23",
14
+ "scipy>=1.9",
15
+ ]
16
+
17
+ [project.optional-dependencies]
18
+ test = [
19
+ "pytest>=7",
20
+ ]
21
+
22
+ [tool.setuptools.packages.find]
23
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ from ._tost import pearson_tost
2
+
3
+ __all__ = ["pearson_tost"]
@@ -0,0 +1,96 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ from scipy.stats import norm
5
+
6
+
7
+ def pearson_tost(
8
+ observed: float,
9
+ target: float,
10
+ n: int,
11
+ margin: float = 0.10,
12
+ alpha: float = 0.05,
13
+ ) -> dict[str, float | bool]:
14
+ """Test equivalence between an observed and target Pearson correlation.
15
+
16
+ Equivalence is assessed using two one-sided tests (TOST) after applying
17
+ Fisher's z transformation to the observed correlation and equivalence
18
+ bounds.
19
+
20
+ Parameters
21
+ ----------
22
+ observed
23
+ Observed Pearson correlation coefficient.
24
+ target
25
+ Target Pearson correlation coefficient.
26
+ n
27
+ Sample size used to estimate the observed correlation.
28
+ margin
29
+ Equivalence margin in Pearson correlation units. The equivalence
30
+ interval is ``[target - margin, target + margin]``.
31
+ alpha
32
+ Significance level for each one-sided test.
33
+
34
+ Returns
35
+ -------
36
+ dict
37
+ Test p-value, one-sided p-values, test statistics, confidence
38
+ interval, and equivalence decision.
39
+ """
40
+ if n <= 3:
41
+ raise ValueError("n must be greater than 3.")
42
+
43
+ if not -1 <= observed <= 1:
44
+ raise ValueError("observed must be between -1 and 1.")
45
+
46
+ if not -1 <= target <= 1:
47
+ raise ValueError("target must be between -1 and 1.")
48
+
49
+ if margin <= 0:
50
+ raise ValueError("margin must be greater than 0.")
51
+
52
+ if not 0 < alpha < 0.5:
53
+ raise ValueError("alpha must be between 0 and 0.5.")
54
+
55
+ eps = 1e-12
56
+
57
+ observed = float(np.clip(observed, -1 + eps, 1 - eps))
58
+ lower = float(np.clip(target - margin, -1 + eps, 1 - eps))
59
+ upper = float(np.clip(target + margin, -1 + eps, 1 - eps))
60
+
61
+ z_observed = np.arctanh(observed)
62
+ z_lower = np.arctanh(lower)
63
+ z_upper = np.arctanh(upper)
64
+
65
+ se = 1.0 / np.sqrt(n - 3)
66
+
67
+ # Lower one-sided test:
68
+ # H0: rho <= lower
69
+ # H1: rho > lower
70
+ z_stat_lower = (z_observed - z_lower) / se
71
+ p_lower = norm.sf(z_stat_lower)
72
+
73
+ # Upper one-sided test:
74
+ # H0: rho >= upper
75
+ # H1: rho < upper
76
+ z_stat_upper = (z_observed - z_upper) / se
77
+ p_upper = norm.cdf(z_stat_upper)
78
+
79
+ # Both one-sided tests must reject for equivalence.
80
+ p_value = max(p_lower, p_upper)
81
+
82
+ # 100 * (1 - 2 * alpha)% confidence interval.
83
+ z_crit = norm.ppf(1 - alpha)
84
+ ci_lower = np.tanh(z_observed - z_crit * se)
85
+ ci_upper = np.tanh(z_observed + z_crit * se)
86
+
87
+ return {
88
+ "p_value": float(p_value),
89
+ "p_lower": float(p_lower),
90
+ "p_upper": float(p_upper),
91
+ "z_stat_lower": float(z_stat_lower),
92
+ "z_stat_upper": float(z_stat_upper),
93
+ "ci_lower": float(ci_lower),
94
+ "ci_upper": float(ci_upper),
95
+ "equivalent": bool(p_value < alpha),
96
+ }
@@ -0,0 +1,79 @@
1
+ Metadata-Version: 2.4
2
+ Name: correlation-tost
3
+ Version: 0.1.0
4
+ Summary: TOST equivalence testing for Pearson correlations.
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: numpy>=1.23
10
+ Requires-Dist: scipy>=1.9
11
+ Provides-Extra: test
12
+ Requires-Dist: pytest>=7; extra == "test"
13
+ Dynamic: license-file
14
+
15
+ # correlation-tost
16
+
17
+ A lightweight Python implementation of the two one-sided tests (TOST) procedure for equivalence testing of Pearson correlations.
18
+
19
+ The test uses Fisher's z transformation and has been numerically validated against R's `TOSTER::corsum_test`.
20
+
21
+ ## Installation
22
+
23
+ Install directly from GitHub with `pip`:
24
+
25
+ ```bash
26
+ pip install git+https://github.com/ArijanaBohr/correlation-tost.git
27
+ ```
28
+
29
+ **Requirements:** Python ≥ 3.9, NumPy, SciPy
30
+
31
+ ## Quick start
32
+
33
+
34
+ ```python
35
+ from correlation_tost import pearson_tost
36
+
37
+ result = pearson_tost(
38
+ observed=0.30, # observed Pearson correlation
39
+ target=0.30, # target Pearson correlation
40
+ n=10_000, # sample size
41
+ margin=0.10, # equivalence margin
42
+ alpha=0.05, # significance level
43
+ )
44
+
45
+ print(result["equivalent"]) # True / False
46
+ print(result["p_value"]) # overall TOST p-value
47
+ ```
48
+
49
+ The equivalence bounds are defined in Pearson correlation units as
50
+ `[target - margin, target + margin]`. Fisher's z transformation is applied
51
+ internally when performing the test.
52
+
53
+ ## Output
54
+
55
+ `pearson_tost` returns a dictionary with the following keys:
56
+
57
+ | Key | Description |
58
+ |----------------|---------------------------------------------------------------|
59
+ | `p_value` | Overall TOST p-value |
60
+ | `p_lower` | p-value for the lower-bound test |
61
+ | `p_upper` | p-value for the upper-bound test |
62
+ | `z_stat_lower` | Test statistic for the lower-bound test |
63
+ | `z_stat_upper` | Test statistic for the upper-bound test |
64
+ | `ci_lower` | Lower confidence interval bound |
65
+ | `ci_upper` | Upper confidence interval bound |
66
+ | `equivalent` | Whether equivalence is concluded at the specified `alpha` |
67
+
68
+ ## Validation
69
+
70
+ The implementation was independently validated against
71
+ `TOSTER::corsum_test(method = "pearson", alternative = "equivalence")`
72
+ across:
73
+
74
+ - positive, negative, and zero correlations
75
+ - multiple sample sizes
76
+ - multiple equivalence margins
77
+ - a range of correlation strengths
78
+
79
+ The package itself does **not** depend on R, rpy2, or TOSTER.
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/correlation_tost/__init__.py
5
+ src/correlation_tost/_tost.py
6
+ src/correlation_tost.egg-info/PKG-INFO
7
+ src/correlation_tost.egg-info/SOURCES.txt
8
+ src/correlation_tost.egg-info/dependency_links.txt
9
+ src/correlation_tost.egg-info/requires.txt
10
+ src/correlation_tost.egg-info/top_level.txt
11
+ tests/test_tost.py
@@ -0,0 +1,5 @@
1
+ numpy>=1.23
2
+ scipy>=1.9
3
+
4
+ [test]
5
+ pytest>=7
@@ -0,0 +1 @@
1
+ correlation_tost
@@ -0,0 +1,51 @@
1
+ import pytest
2
+
3
+ from correlation_tost import pearson_tost
4
+
5
+
6
+ def test_matches_toster_reference_case():
7
+ """Match a reference result from TOSTER::corsum_test."""
8
+ result = pearson_tost(
9
+ observed=0.30,
10
+ target=0.30,
11
+ n=10_000,
12
+ margin=0.10,
13
+ alpha=0.05,
14
+ )
15
+
16
+ assert result["p_value"] == pytest.approx(
17
+ 6.513681924396496e-27,
18
+ rel=1e-12,
19
+ )
20
+ assert result["ci_lower"] == pytest.approx(
21
+ 0.2849567,
22
+ abs=1e-7,
23
+ )
24
+ assert result["ci_upper"] == pytest.approx(
25
+ 0.3148956,
26
+ abs=1e-7,
27
+ )
28
+ assert result["equivalent"] is True
29
+
30
+
31
+ @pytest.mark.parametrize(
32
+ "kwargs, message",
33
+ [
34
+ ({"n": 3}, "n must be greater than 3"),
35
+ ({"observed": 1.1}, "observed must be between -1 and 1"),
36
+ ({"target": -1.1}, "target must be between -1 and 1"),
37
+ ({"margin": 0.0}, "margin must be greater than 0"),
38
+ ({"alpha": 0.0}, "alpha must be between 0 and 0.5"),
39
+ ({"alpha": 0.5}, "alpha must be between 0 and 0.5"),
40
+ ],
41
+ )
42
+ def test_invalid_inputs(kwargs, message):
43
+ params = {
44
+ "observed": 0.30,
45
+ "target": 0.30,
46
+ "n": 100,
47
+ }
48
+ params.update(kwargs)
49
+
50
+ with pytest.raises(ValueError, match=message):
51
+ pearson_tost(**params)