PyMetaAnalysis 0.4.0__tar.gz → 0.6.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.
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/.github/workflows/ci.yml +1 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/.github/workflows/pages.yml +1 -2
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/.github/workflows/release.yml +7 -3
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/.gitignore +1 -0
- pymetaanalysis-0.6.0/CHANGELOG.md +204 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/CITATION.cff +2 -2
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/PKG-INFO +15 -4
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/README.md +13 -3
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/adr/0002-statistical-policy.md +15 -6
- pymetaanalysis-0.6.0/docs/adr/0004-hartung-knapp-prediction-intervals.md +46 -0
- pymetaanalysis-0.6.0/docs/adr/0005-mantel-haenszel-risk-difference.md +65 -0
- pymetaanalysis-0.6.0/docs/adr/0006-peto-odds-ratio.md +87 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/development.md +2 -2
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/binary-outcomes.md +33 -5
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/input-data.md +18 -2
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/meta-regression.md +4 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/method-selection.md +70 -12
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/provenance-reporting.md +12 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/r-interoperability.md +34 -5
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/sensitivity-analysis.md +15 -7
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/zero-events.md +43 -6
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/index.md +7 -5
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/installation.md +1 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/limitations.md +15 -6
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/methods/statistical-methods.md +152 -26
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/reference/api.md +45 -17
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/reference/report-schema.md +2 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/reference/results.md +56 -8
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/releasing.md +18 -14
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/validation.md +51 -18
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/mkdocs.yml +3 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/pyproject.toml +3 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/__init__.py +2 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/_version.py +1 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/api.py +65 -17
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/binary_api.py +126 -30
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/continuous_api.py +37 -16
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/data.py +40 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/design_matrix.py +80 -21
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/effect_sizes/binary.py +154 -19
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/effect_sizes/continuous.py +34 -4
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/estimators/__init__.py +3 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/estimators/inverse_variance.py +22 -6
- pymetaanalysis-0.6.0/src/meta_analyze/estimators/mantel_haenszel.py +183 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/estimators/meta_regression.py +117 -34
- pymetaanalysis-0.6.0/src/meta_analyze/estimators/peto.py +154 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/estimators/tau2.py +42 -20
- pymetaanalysis-0.6.0/src/meta_analyze/heterogeneity.py +285 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/_utils.py +10 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/forest.py +24 -5
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/subgroup_forest.py +32 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_api.py +19 -6
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_collinearity.py +3 -22
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_results.py +48 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_sensitivity.py +14 -38
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/reporting.py +50 -21
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/results.py +170 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/sensitivity.py +115 -33
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/subgroups.py +61 -12
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/README.md +29 -9
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/binary_metafor.json +72 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_binary_metafor.R +97 -17
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_generic_metafor.R +32 -8
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_meta_regression_influence_metafor.R +22 -8
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_meta_regression_metafor.R +83 -2
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_workflow_metafor.R +10 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generic_metafor.json +27 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_influence_metafor.json +327 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_metafor.json +205 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/workflow_metafor.json +6 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_api.py +236 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_binary.py +339 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_continuous.py +41 -0
- pymetaanalysis-0.6.0/tests/test_estimators.py +412 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_funnel_plot.py +1 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_meta_regression.py +79 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_numerical_stability.py +128 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_plotting.py +11 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_properties.py +189 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_r_references.py +254 -6
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_influence.py +65 -22
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_plotting.py +1 -1
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_sensitivity.py +25 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_release_readiness.py +39 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_reporting.py +47 -4
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_sensitivity.py +108 -6
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_subgroups.py +120 -13
- pymetaanalysis-0.4.0/CHANGELOG.md +0 -108
- pymetaanalysis-0.4.0/src/meta_analyze/estimators/mantel_haenszel.py +0 -101
- pymetaanalysis-0.4.0/src/meta_analyze/heterogeneity.py +0 -99
- pymetaanalysis-0.4.0/tests/test_estimators.py +0 -147
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/CONTRIBUTING.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/LICENSE +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/SECURITY.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/benchmarks/README.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/benchmarks/benchmark_core.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/adr/0001-optional-matplotlib.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/adr/0003-meta-regression-prediction-intervals.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/citation.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/getting-started.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/continuous-outcomes.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/generic-effects.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/plotting.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/stylesheets/extra.css +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/examples/README.md +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/examples/meta_regression.ipynb +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/examples/quickstart.ipynb +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/config.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/effect_sizes/__init__.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/exceptions.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/__init__.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/funnel.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/regression.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/provenance.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/py.typed +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_contrasts.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/binary_input.csv +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/binary_sparse_input.csv +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/continuous_input.csv +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/continuous_metafor.json +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_continuous_metafor.R +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_meta_regression_collinearity_metafor.R +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_meta_regression_contrasts_metafor.R +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generic_input.csv +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_boundary_input.csv +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_collinearity_metafor.json +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_contrasts_metafor.json +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_input.csv +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/workflow_input.csv +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_documentation.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_reference_results.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_collinearity.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_contrasts.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tools/check_release.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tools/execute_notebooks.py +0 -0
- {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tools/inspect_distribution.py +0 -0
|
@@ -8,7 +8,7 @@ on:
|
|
|
8
8
|
|
|
9
9
|
concurrency:
|
|
10
10
|
group: pages
|
|
11
|
-
cancel-in-progress:
|
|
11
|
+
cancel-in-progress: false
|
|
12
12
|
|
|
13
13
|
jobs:
|
|
14
14
|
build:
|
|
@@ -17,7 +17,6 @@ jobs:
|
|
|
17
17
|
timeout-minutes: 10
|
|
18
18
|
permissions:
|
|
19
19
|
contents: read
|
|
20
|
-
pages: write
|
|
21
20
|
|
|
22
21
|
steps:
|
|
23
22
|
- name: Check out repository
|
|
@@ -35,14 +35,17 @@ jobs:
|
|
|
35
35
|
cache: pip
|
|
36
36
|
cache-dependency-path: pyproject.toml
|
|
37
37
|
|
|
38
|
-
- name: Install
|
|
38
|
+
- name: Install release dependencies
|
|
39
39
|
run: |
|
|
40
40
|
python -m pip install --upgrade pip
|
|
41
|
-
python -m pip install build twine
|
|
41
|
+
python -m pip install ".[test]" build twine
|
|
42
42
|
|
|
43
43
|
- name: Validate release metadata
|
|
44
44
|
run: python tools/check_release.py --tag "$GITHUB_REF_NAME"
|
|
45
45
|
|
|
46
|
+
- name: Run tests with branch coverage
|
|
47
|
+
run: python -m pytest --cov=meta_analyze --cov-branch --cov-report=term-missing
|
|
48
|
+
|
|
46
49
|
- name: Build distributions
|
|
47
50
|
run: python -m build
|
|
48
51
|
|
|
@@ -91,7 +94,8 @@ jobs:
|
|
|
91
94
|
path: dist/
|
|
92
95
|
|
|
93
96
|
- name: Publish to PyPI
|
|
94
|
-
|
|
97
|
+
# release/v1.14, pinned because this step holds the PyPI OIDC permission.
|
|
98
|
+
uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247
|
|
95
99
|
|
|
96
100
|
github-release:
|
|
97
101
|
name: Create GitHub Release
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to PyMetaAnalysis will be documented in this file.
|
|
4
|
+
|
|
5
|
+
Changes planned for the next release accumulate under `Unreleased`.
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
## 0.6.0 - 2026-08-13
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- common-effect Peto one-step odds-ratio pooling, including Peto-specific
|
|
14
|
+
study estimates, O-minus-E heterogeneity, explicit approximation warnings,
|
|
15
|
+
provenance/report metadata, and independent R `metafor` references;
|
|
16
|
+
- common-effect Mantel-Haenszel risk-difference pooling with the
|
|
17
|
+
Sato-Greenland-Robins sampling variance, explicit method metadata,
|
|
18
|
+
sparse-table policy integration, and independent R `metafor` references.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- isolated builds temporarily cap Hatchling below 1.32 so the release
|
|
23
|
+
workflow continues to produce Core Metadata 2.4 accepted by Twine 6.2;
|
|
24
|
+
the cap can be removed once Twine validates Metadata 2.5.
|
|
25
|
+
|
|
26
|
+
## 0.5.0 - 2026-07-25
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- random-effects inverse-variance results now provide opt-in Q-profile
|
|
31
|
+
confidence intervals for tau-squared, tau, I-squared, and H-squared, with an
|
|
32
|
+
explicit formal-empty-set flag at the constrained `[0, 0]` boundary.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- sensitivity and influence workflows now borrow internal fitted buffers during
|
|
37
|
+
refits instead of repeatedly materializing public defensive copies;
|
|
38
|
+
- Meta-regression stores its classic coefficient covariance alongside the
|
|
39
|
+
selected inference covariance and reuses one shared precision-geometry
|
|
40
|
+
implementation across fitting and diagnostics.
|
|
41
|
+
- independent `metafor` fixtures now cover categorical and multivariable
|
|
42
|
+
influence diagnostics, no-intercept Riley prediction intervals, and explicit
|
|
43
|
+
Mantel-Haenszel pooling correction; iterative failure paths have direct
|
|
44
|
+
regression tests.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- inverse-variance means, heterogeneity statistics, and pooling and
|
|
49
|
+
meta-regression tau-squared equations now use overflow-safe relative-weight
|
|
50
|
+
calculations at the supported float64 boundary;
|
|
51
|
+
- subnormal variances and non-finite derived effects now raise explicit domain
|
|
52
|
+
errors instead of leaking runtime warnings or returning invalid results;
|
|
53
|
+
- binary OR, RD, and Mantel-Haenszel arithmetic now avoids intermediate
|
|
54
|
+
overflow for very large finite counts;
|
|
55
|
+
- the sensitivity guide no longer incorrectly states that Meta-regression
|
|
56
|
+
Cook's distance and DFBETAS are unavailable.
|
|
57
|
+
- subgroup-differences tests now use classic model variances independently of
|
|
58
|
+
Hartung-Knapp confidence-interval adjustments;
|
|
59
|
+
- leave-one-out and cumulative workflows now retain or skip, respectively,
|
|
60
|
+
reduced Mantel-Haenszel fits that are not estimable instead of aborting the
|
|
61
|
+
complete sensitivity analysis;
|
|
62
|
+
- forest and subgroup-forest plots now reject non-positive displayed
|
|
63
|
+
coordinates before enabling a logarithmic axis;
|
|
64
|
+
- uncorrected risk-ratio analyses now accept a zero non-event cell when the
|
|
65
|
+
study effect and sampling variance remain well defined.
|
|
66
|
+
- Hartung-Knapp random-effects prediction intervals now use the selected
|
|
67
|
+
adjusted pooled-mean variance and are recorded as `HK-PR`, matching
|
|
68
|
+
`metafor` Riley predictions;
|
|
69
|
+
- random-effects subgroup analyses now retain single-study subgroups through
|
|
70
|
+
an explicit, warned common-effect fallback instead of failing the complete
|
|
71
|
+
analysis;
|
|
72
|
+
- tagged releases now rerun the full branch-coverage test suite before
|
|
73
|
+
distributions can be built and published.
|
|
74
|
+
- tau-squared methods and SMD variance conventions now use `None` as the
|
|
75
|
+
context-sensitive default, so explicitly inapplicable settings raise domain
|
|
76
|
+
errors instead of being silently ignored;
|
|
77
|
+
- duplicate study labels now add a row-position warning while preserving
|
|
78
|
+
`row_id` as the unique audit key;
|
|
79
|
+
- report JSON now serializes `pd.NaT` study labels as `null` rather than the
|
|
80
|
+
string `"NaT"`.
|
|
81
|
+
- Meta-regression with `missing="drop"` now determines complete-row exclusions
|
|
82
|
+
before validating moderator values, so invalid values in already excluded
|
|
83
|
+
rows cannot abort the analysis;
|
|
84
|
+
- cumulative analysis now rejects ambiguous string `order` selectors that
|
|
85
|
+
exist in both source data and study results;
|
|
86
|
+
- empty inputs now report that at least one study row is required, and binary
|
|
87
|
+
zero-cell errors identify when `correction_scope="none"` disables an
|
|
88
|
+
otherwise positive correction.
|
|
89
|
+
- iterative tau-squared estimators now mark only an exact constrained zero as
|
|
90
|
+
a boundary solution, rather than treating every positive root below `atol`
|
|
91
|
+
as zero;
|
|
92
|
+
- the exported pooling and Meta-regression tau-squared estimators now reject
|
|
93
|
+
insufficient study or residual degrees of freedom with domain-specific
|
|
94
|
+
errors;
|
|
95
|
+
- the Mantel-Haenszel estimator now rejects empty and zero-total strata before
|
|
96
|
+
division, preventing NaN propagation and misleading variance diagnostics.
|
|
97
|
+
- prediction-interval metadata is now `None` when too few studies prevent an
|
|
98
|
+
interval from being calculated;
|
|
99
|
+
- categorical moderator encoding no longer conflates booleans, integers, and
|
|
100
|
+
floating-point values through Python's cross-type numeric equality;
|
|
101
|
+
- CI now covers Python 3.14, Pages deployments are not cancelled mid-flight,
|
|
102
|
+
and the credential-bearing PyPI publisher action is pinned to an immutable
|
|
103
|
+
commit.
|
|
104
|
+
|
|
105
|
+
## 0.4.0 - 2026-07-23
|
|
106
|
+
|
|
107
|
+
### Added
|
|
108
|
+
|
|
109
|
+
- leave-one-out Meta-regression refits with model-level diagnostics,
|
|
110
|
+
coefficient changes, explicit unidentifiable-deletion records, and preserved
|
|
111
|
+
provenance.
|
|
112
|
+
- exact Meta-regression externally standardized residuals, Cook's distances,
|
|
113
|
+
DFBETAS, transparent screening thresholds, and fixed-version R `metafor`
|
|
114
|
+
cross-software fixtures.
|
|
115
|
+
- Meta-regression term VIF, moderator-level GVIF/GSIF, and weighted,
|
|
116
|
+
column-scaled condition diagnostics with variance-decomposition proportions,
|
|
117
|
+
heuristic-only flags, and R `metafor` cross-software fixtures.
|
|
118
|
+
- explicit named Meta-regression linear contrasts with nonzero null values,
|
|
119
|
+
individual z/t inference, joint chi-squared/F tests, labeled coefficient
|
|
120
|
+
matrices, and R `metafor` cross-software fixtures.
|
|
121
|
+
- opt-in Riley Meta-regression true-effect prediction intervals using
|
|
122
|
+
`t_(k-p-1)`, with explicit residual-df validation, preserved refit
|
|
123
|
+
configuration, and fixed-version R `metafor` boundary references.
|
|
124
|
+
|
|
125
|
+
## 0.3.0 - 2026-07-22
|
|
126
|
+
|
|
127
|
+
### Added
|
|
128
|
+
|
|
129
|
+
- pandas-first `meta_regression()` for numeric, explicitly encoded categorical,
|
|
130
|
+
and multiple study-level moderators;
|
|
131
|
+
- common- and mixed-effects weighted regression with generalized DL, PM, and
|
|
132
|
+
REML residual tau-squared estimators;
|
|
133
|
+
- normal, Hartung-Knapp, and safeguarded Hartung-Knapp coefficient inference,
|
|
134
|
+
distribution-explicit moderator tests, residual heterogeneity, pseudo-R²,
|
|
135
|
+
prediction, provenance, and structured reports;
|
|
136
|
+
- optional weighted bubble plots for intercept-containing Meta-regression fits
|
|
137
|
+
with exactly one numeric moderator;
|
|
138
|
+
- independent R `metafor` fixtures covering numeric, categorical,
|
|
139
|
+
multivariable, zero-tau-squared, missing-row, and small-sample cases;
|
|
140
|
+
- an executable Meta-regression notebook plus a multivariable performance
|
|
141
|
+
baseline and expanded property, numerical-stability, and warning tests.
|
|
142
|
+
|
|
143
|
+
### Changed
|
|
144
|
+
|
|
145
|
+
- report schema 1.2 adds the `meta_regression` report type.
|
|
146
|
+
|
|
147
|
+
## 0.2.1 - 2026-07-17
|
|
148
|
+
|
|
149
|
+
### Fixed
|
|
150
|
+
|
|
151
|
+
- README documentation and repository links use absolute URLs so they resolve
|
|
152
|
+
correctly when the project description is rendered on PyPI.
|
|
153
|
+
|
|
154
|
+
## 0.2.0 - 2026-07-16
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
|
|
158
|
+
- generic `meta_analysis()` accepts either sampling variances or standard
|
|
159
|
+
errors, with explicit validation and auditable conversion provenance.
|
|
160
|
+
|
|
161
|
+
### Changed
|
|
162
|
+
|
|
163
|
+
- package author metadata identifies the project maintainer directly.
|
|
164
|
+
|
|
165
|
+
### Fixed
|
|
166
|
+
|
|
167
|
+
- GitHub Release creation receives explicit repository context in tag-driven
|
|
168
|
+
release jobs.
|
|
169
|
+
|
|
170
|
+
## 0.1.0 - 2026-07-15
|
|
171
|
+
|
|
172
|
+
### Added
|
|
173
|
+
|
|
174
|
+
- pandas-first generic, binary, and continuous study-level meta-analysis APIs;
|
|
175
|
+
- common-effect and random-effects inverse-variance models;
|
|
176
|
+
- common-effect Mantel-Haenszel OR/RR pooling;
|
|
177
|
+
- REML, Paule-Mandel, and DerSimonian-Laird tau-squared estimators;
|
|
178
|
+
- normal, Hartung-Knapp, and safeguarded Hartung-Knapp confidence intervals;
|
|
179
|
+
- HTS random-effects prediction intervals;
|
|
180
|
+
- subgroup, leave-one-out, and cumulative workflows;
|
|
181
|
+
- optional Matplotlib forest, subgroup forest, and funnel plots;
|
|
182
|
+
- immutable results, diagnostics, provenance, Methods text, and JSON/Markdown
|
|
183
|
+
reports;
|
|
184
|
+
- R `metafor` cross-software fixtures, property tests, and numerical edge-case
|
|
185
|
+
coverage;
|
|
186
|
+
- explicit RD zero-variance boundary policy and heterogeneity-definition
|
|
187
|
+
reporting;
|
|
188
|
+
- complete MkDocs user, methods, API, validation, limitation, and development
|
|
189
|
+
documentation;
|
|
190
|
+
- R `meta`/`metafor` terminology and parameter mappings;
|
|
191
|
+
- machine-readable citation metadata and an executable end-to-end notebook;
|
|
192
|
+
- GitHub Pages and PyPI Trusted Publishing release workflows;
|
|
193
|
+
- release metadata, distribution-content, notebook-execution, and performance
|
|
194
|
+
baseline tooling.
|
|
195
|
+
|
|
196
|
+
### Changed
|
|
197
|
+
|
|
198
|
+
- independent external statistical review is documented as a recommended
|
|
199
|
+
validation activity rather than a release requirement;
|
|
200
|
+
- report schema 1.1 records `heterogeneity.i2_method`;
|
|
201
|
+
- random-effects I-squared/H-squared use tau-squared and typical within-study
|
|
202
|
+
variance, while common-effect/MH analyses retain Q-based definitions;
|
|
203
|
+
- random-effects summaries provide method-selection notes for small-study and
|
|
204
|
+
positive-heterogeneity cases.
|
|
@@ -8,8 +8,8 @@ authors:
|
|
|
8
8
|
- family-names: Ding
|
|
9
9
|
given-names: Zhaobo
|
|
10
10
|
email: ding.zb@yahoo.com
|
|
11
|
-
version: 0.
|
|
12
|
-
date-released: 2026-
|
|
11
|
+
version: 0.6.0
|
|
12
|
+
date-released: 2026-08-13
|
|
13
13
|
repository-code: https://github.com/ZhaoboDing/PyMetaAnalysis
|
|
14
14
|
url: https://zhaoboding.github.io/PyMetaAnalysis/
|
|
15
15
|
license: MIT
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyMetaAnalysis
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: A pandas-first, auditable meta-analysis library for Python
|
|
5
5
|
Project-URL: Documentation, https://zhaoboding.github.io/PyMetaAnalysis/
|
|
6
6
|
Project-URL: Source, https://github.com/ZhaoboDing/PyMetaAnalysis
|
|
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
22
|
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
22
23
|
Requires-Python: >=3.10
|
|
23
24
|
Requires-Dist: numpy>=1.24
|
|
@@ -132,14 +133,17 @@ not individual-level or causal effects.
|
|
|
132
133
|
| Input | Effects | Pooling/models |
|
|
133
134
|
| --- | --- | --- |
|
|
134
135
|
| Effect + sampling variance or standard error | Generic | Common/random inverse variance |
|
|
135
|
-
| Two-group events + totals | OR, RR, RD | Common MH OR
|
|
136
|
+
| Two-group events + totals | OR, RR, RD | Common MH; common Peto OR; common/random IV |
|
|
136
137
|
| Two-group means + SDs + sizes | MD, Hedges' g | Common/random inverse variance |
|
|
137
138
|
| Effect + variance/SE + moderators | Generic | Common/mixed Meta-regression |
|
|
138
139
|
|
|
139
140
|
Random-effects inverse-variance models support REML (default), Paule-Mandel,
|
|
140
141
|
and DerSimonian-Laird tau-squared estimators. Mean confidence intervals support
|
|
141
142
|
the normal default plus unmodified and safeguarded Hartung-Knapp variants.
|
|
142
|
-
Eligible random-effects fits include an HTS prediction interval
|
|
143
|
+
Eligible random-effects fits include an HTS prediction interval under normal
|
|
144
|
+
inference and an HK-PR interval under either Hartung-Knapp variant. Call
|
|
145
|
+
`result.tau2_confidence_interval()` for a Q-profile interval around
|
|
146
|
+
heterogeneity.
|
|
143
147
|
|
|
144
148
|
Generic analyses accept exactly one of `variance=` or `standard_error=`.
|
|
145
149
|
Standard errors are squared internally and the conversion is recorded in the
|
|
@@ -149,6 +153,12 @@ Sparse binary behavior is explicit: study-level and Mantel-Haenszel continuity
|
|
|
149
153
|
corrections are separate, relative-effect double-zero/double-all rows remain
|
|
150
154
|
visible as exclusions, and RD exposes
|
|
151
155
|
`rd_zero_variance="correct" | "exclude"`.
|
|
156
|
+
Peto OR uses raw tables for pooling and a separate one-step study estimator;
|
|
157
|
+
it always reports a caution that its approximation is intended for rare
|
|
158
|
+
outcomes, similar within-study arm sizes, and effects that are not large.
|
|
159
|
+
Common-effect MH risk differences use the Sato-Greenland-Robins sampling
|
|
160
|
+
variance; random-effects binary analyses continue to use inverse-variance
|
|
161
|
+
pooling.
|
|
152
162
|
|
|
153
163
|
## Inspect and report
|
|
154
164
|
|
|
@@ -157,6 +167,7 @@ result.estimate
|
|
|
157
167
|
result.display_estimate
|
|
158
168
|
result.ci
|
|
159
169
|
result.tau2
|
|
170
|
+
tau2_interval = result.tau2_confidence_interval()
|
|
160
171
|
result.i2
|
|
161
172
|
result.i2_method
|
|
162
173
|
result.diagnostics
|
|
@@ -247,7 +258,7 @@ python -m mkdocs serve
|
|
|
247
258
|
|
|
248
259
|
The test suite combines hand calculations, statistical invariants, numerical
|
|
249
260
|
edge cases, and committed R `metafor` reference fixtures. CI covers Python
|
|
250
|
-
3.10–3.
|
|
261
|
+
3.10–3.14, declared dependency lower bounds, strict typing/linting, docs, and
|
|
251
262
|
distribution builds.
|
|
252
263
|
|
|
253
264
|
This is independent cross-software validation, not a formal external
|
|
@@ -83,14 +83,17 @@ not individual-level or causal effects.
|
|
|
83
83
|
| Input | Effects | Pooling/models |
|
|
84
84
|
| --- | --- | --- |
|
|
85
85
|
| Effect + sampling variance or standard error | Generic | Common/random inverse variance |
|
|
86
|
-
| Two-group events + totals | OR, RR, RD | Common MH OR
|
|
86
|
+
| Two-group events + totals | OR, RR, RD | Common MH; common Peto OR; common/random IV |
|
|
87
87
|
| Two-group means + SDs + sizes | MD, Hedges' g | Common/random inverse variance |
|
|
88
88
|
| Effect + variance/SE + moderators | Generic | Common/mixed Meta-regression |
|
|
89
89
|
|
|
90
90
|
Random-effects inverse-variance models support REML (default), Paule-Mandel,
|
|
91
91
|
and DerSimonian-Laird tau-squared estimators. Mean confidence intervals support
|
|
92
92
|
the normal default plus unmodified and safeguarded Hartung-Knapp variants.
|
|
93
|
-
Eligible random-effects fits include an HTS prediction interval
|
|
93
|
+
Eligible random-effects fits include an HTS prediction interval under normal
|
|
94
|
+
inference and an HK-PR interval under either Hartung-Knapp variant. Call
|
|
95
|
+
`result.tau2_confidence_interval()` for a Q-profile interval around
|
|
96
|
+
heterogeneity.
|
|
94
97
|
|
|
95
98
|
Generic analyses accept exactly one of `variance=` or `standard_error=`.
|
|
96
99
|
Standard errors are squared internally and the conversion is recorded in the
|
|
@@ -100,6 +103,12 @@ Sparse binary behavior is explicit: study-level and Mantel-Haenszel continuity
|
|
|
100
103
|
corrections are separate, relative-effect double-zero/double-all rows remain
|
|
101
104
|
visible as exclusions, and RD exposes
|
|
102
105
|
`rd_zero_variance="correct" | "exclude"`.
|
|
106
|
+
Peto OR uses raw tables for pooling and a separate one-step study estimator;
|
|
107
|
+
it always reports a caution that its approximation is intended for rare
|
|
108
|
+
outcomes, similar within-study arm sizes, and effects that are not large.
|
|
109
|
+
Common-effect MH risk differences use the Sato-Greenland-Robins sampling
|
|
110
|
+
variance; random-effects binary analyses continue to use inverse-variance
|
|
111
|
+
pooling.
|
|
103
112
|
|
|
104
113
|
## Inspect and report
|
|
105
114
|
|
|
@@ -108,6 +117,7 @@ result.estimate
|
|
|
108
117
|
result.display_estimate
|
|
109
118
|
result.ci
|
|
110
119
|
result.tau2
|
|
120
|
+
tau2_interval = result.tau2_confidence_interval()
|
|
111
121
|
result.i2
|
|
112
122
|
result.i2_method
|
|
113
123
|
result.diagnostics
|
|
@@ -198,7 +208,7 @@ python -m mkdocs serve
|
|
|
198
208
|
|
|
199
209
|
The test suite combines hand calculations, statistical invariants, numerical
|
|
200
210
|
edge cases, and committed R `metafor` reference fixtures. CI covers Python
|
|
201
|
-
3.10–3.
|
|
211
|
+
3.10–3.14, declared dependency lower bounds, strict typing/linting, docs, and
|
|
202
212
|
distribution builds.
|
|
203
213
|
|
|
204
214
|
This is independent cross-software validation, not a formal external
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
- Status: Accepted
|
|
4
4
|
- Date: 2026-07-15
|
|
5
|
+
- Amendment: the prediction-interval variance decision is superseded by
|
|
6
|
+
[ADR 0004](0004-hartung-knapp-prediction-intervals.md).
|
|
7
|
+
- Amendment: the decision to defer Mantel-Haenszel risk differences is
|
|
8
|
+
superseded by [ADR 0005](0005-mantel-haenszel-risk-difference.md).
|
|
9
|
+
- Amendment: the decision to defer Peto pooling is superseded by
|
|
10
|
+
[ADR 0006](0006-peto-odds-ratio.md).
|
|
5
11
|
|
|
6
12
|
## Context
|
|
7
13
|
|
|
@@ -42,13 +48,15 @@ option, and a provenance transformation.
|
|
|
42
48
|
Mantel-Haenszel pooling remains a common-effect estimator for OR and RR. It
|
|
43
49
|
uses raw tables by default and has a correction setting separate from the one
|
|
44
50
|
used for individual-study effects. Random-effects Mantel-Haenszel, RD
|
|
45
|
-
Mantel-Haenszel, and Peto pooling
|
|
51
|
+
Mantel-Haenszel, and Peto pooling were outside the scope of this original
|
|
52
|
+
decision; ADRs 0005 and 0006 supersede the latter two deferrals.
|
|
46
53
|
|
|
47
54
|
### Heterogeneity
|
|
48
55
|
|
|
49
56
|
Cochran's Q, degrees of freedom, and p-value always use common-effect inverse-
|
|
50
57
|
variance weights. Common-effect and Mantel-Haenszel analyses use Q-based
|
|
51
|
-
I-squared and H-squared.
|
|
58
|
+
I-squared and H-squared. ADR 0006 adds Peto's estimator-specific Q while
|
|
59
|
+
retaining those Q-based inconsistency transformations.
|
|
52
60
|
|
|
53
61
|
Random-effects analyses use:
|
|
54
62
|
|
|
@@ -65,10 +73,11 @@ percentage in human-readable output.
|
|
|
65
73
|
|
|
66
74
|
### Prediction intervals
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
The original decision used the Higgins-Thompson-Spiegelhalter prediction
|
|
77
|
+
interval with `k - 2` degrees of freedom and the classic variance of the
|
|
78
|
+
pooled mean for every confidence-interval method. ADR 0004 replaces that
|
|
79
|
+
variance rule for Hartung-Knapp fits while retaining the study-count boundary
|
|
80
|
+
and small-sample warning.
|
|
72
81
|
|
|
73
82
|
## Validation
|
|
74
83
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# ADR 0004: Hartung-Knapp prediction intervals
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2026-07-24
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
ADR 0002 applied the classic pooled-mean variance to every `k - 2`
|
|
9
|
+
random-effects prediction interval. That kept the interval independent of
|
|
10
|
+
`ci_method`, but it diverged from `metafor` Riley predictions and the
|
|
11
|
+
Hartung-Knapp Partlett-Riley option in R `meta`. Both use the covariance
|
|
12
|
+
selected for mean inference inside the prediction variance.
|
|
13
|
+
|
|
14
|
+
This difference was material when the unmodified Hartung-Knapp variance was
|
|
15
|
+
below or above the classic variance. The result metadata still identified the
|
|
16
|
+
interval as `HTS`, so callers could not discover the difference from method
|
|
17
|
+
configuration alone.
|
|
18
|
+
|
|
19
|
+
## Decision
|
|
20
|
+
|
|
21
|
+
Random-effects inverse-variance prediction intervals retain the `k - 2`
|
|
22
|
+
critical value and three-study minimum:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
mu_hat +/- t_(k - 2, 1 - alpha/2)
|
|
26
|
+
* sqrt(tau^2 + Var_selected(mu_hat))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- normal inference uses the classic pooled-mean variance and records `HTS`;
|
|
30
|
+
- `hartung_knapp` uses its unmodified adjusted variance and records `HK-PR`;
|
|
31
|
+
- `hartung_knapp_adhoc` uses its lower-bounded adjusted variance and records
|
|
32
|
+
`HK-PR`.
|
|
33
|
+
|
|
34
|
+
Committed values are generated directly from
|
|
35
|
+
`metafor::predict(fit, predtype="Riley")` for all three inference choices.
|
|
36
|
+
Prediction intervals remain unavailable below three included studies and
|
|
37
|
+
retain the explicit warning with three or four studies.
|
|
38
|
+
|
|
39
|
+
## Consequences
|
|
40
|
+
|
|
41
|
+
- prediction intervals and mean intervals use a coherent selected covariance;
|
|
42
|
+
- HK and safeguarded HK prediction intervals can differ from the normal HTS
|
|
43
|
+
interval even when tau-squared and the pooled estimate are unchanged;
|
|
44
|
+
- `result.method.prediction_interval_method` distinguishes `HTS` from
|
|
45
|
+
`HK-PR`;
|
|
46
|
+
- this decision supersedes only the prediction-variance paragraph of ADR 0002.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# ADR 0005: Mantel-Haenszel risk difference
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2026-08-13
|
|
5
|
+
- Supersedes: the RD exclusion from the Mantel-Haenszel scope in
|
|
6
|
+
[ADR 0002](0002-statistical-policy.md)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
ADR 0002 limited Mantel-Haenszel pooling to common-effect odds ratios and risk
|
|
11
|
+
ratios while the risk-difference estimator and its variance convention were
|
|
12
|
+
still undecided. This left inverse variance as the only pooling method for RD,
|
|
13
|
+
although conventional R implementations provide a common-effect MH RD.
|
|
14
|
+
|
|
15
|
+
The point estimator is straightforward, but several variance estimators have
|
|
16
|
+
appeared in the literature. The selected rule must work under both large-
|
|
17
|
+
stratum and sparse-data limiting models, preserve treatment/control symmetry,
|
|
18
|
+
and remain explicit in reports and cross-software validation.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
PyMetaAnalysis supports `measure="RD", method="MH", model="common"`. With
|
|
23
|
+
treatment total `n1_i`, control total `n0_i`, total `N_i`, and
|
|
24
|
+
`w_i = n1_i n0_i / N_i`, the estimate is:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
RD_i = a_i / n1_i - c_i / n0_i
|
|
28
|
+
RD_MH = sum(w_i RD_i) / sum(w_i)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The normal confidence interval uses the Sato-Greenland-Robins sampling
|
|
32
|
+
variance. The resolved method options record
|
|
33
|
+
`mh_rd_variance="Sato-Greenland-Robins"`.
|
|
34
|
+
|
|
35
|
+
Raw tables are used for MH pooling by default. `mh_continuity_correction` and
|
|
36
|
+
`mh_correction_scope` remain the only settings that alter MH pooling tables;
|
|
37
|
+
the separate study-effect correction continues to control displayed study
|
|
38
|
+
uncertainty and the inverse-variance heterogeneity calculation. The existing
|
|
39
|
+
`rd_zero_variance` policy determines whether boundary studies enter all
|
|
40
|
+
synthesis calculations. A non-positive pooled Sato variance raises a domain
|
|
41
|
+
error instead of silently adding a correction.
|
|
42
|
+
|
|
43
|
+
Random-effects MH remains unsupported. Random-effects RD continues to use
|
|
44
|
+
inverse-variance pooling with an explicit tau-squared estimator.
|
|
45
|
+
|
|
46
|
+
## Validation
|
|
47
|
+
|
|
48
|
+
- direct formula tests cover the estimate, Sato variance, weights, and normal
|
|
49
|
+
interval;
|
|
50
|
+
- treatment/control swaps negate the estimate and mirror its interval without
|
|
51
|
+
changing the standard error;
|
|
52
|
+
- row reordering and common count scaling preserve the expected invariants;
|
|
53
|
+
- extreme finite counts exercise the overflow-safe scaled implementation;
|
|
54
|
+
- boundary-policy, explicit-correction, subgroup, leave-one-out, and
|
|
55
|
+
cumulative paths are covered; and
|
|
56
|
+
- fixed-version `metafor::rma.mh(measure="RD")` fixtures cover ordinary,
|
|
57
|
+
sparse, and explicitly corrected tables.
|
|
58
|
+
|
|
59
|
+
## Consequences
|
|
60
|
+
|
|
61
|
+
- common-effect OR, RR, and RD all support MH or inverse-variance pooling;
|
|
62
|
+
- study-table MH weights for RD are proportional to `n1_i n0_i / N_i`;
|
|
63
|
+
- the selected RD variance convention is recoverable from method metadata and
|
|
64
|
+
generated reports; and
|
|
65
|
+
- documentation must continue to distinguish MH RD from random-effects IV RD.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# ADR 0006: Peto one-step odds ratio
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2026-08-13
|
|
5
|
+
- Supersedes: the Peto deferral in
|
|
6
|
+
[ADR 0002](0002-statistical-policy.md)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
Peto's one-step method is a conventional common-effect estimator for binary
|
|
11
|
+
outcomes and is particularly associated with rare-event meta-analysis. It is
|
|
12
|
+
not interchangeable with an ordinary inverse-variance odds ratio: it derives
|
|
13
|
+
both the study contribution and pooled estimate from observed-minus-expected
|
|
14
|
+
events and hypergeometric information.
|
|
15
|
+
|
|
16
|
+
The approximation can be biased when treatment and control group sizes differ
|
|
17
|
+
substantially within studies, effects are large, or events are not rare. Its
|
|
18
|
+
zero-cell behavior also differs from ordinary log odds ratios, so pooling and
|
|
19
|
+
display corrections must not be conflated.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
PyMetaAnalysis supports `measure="OR", method="Peto", model="common"` with
|
|
24
|
+
`ci_method="normal"`. `"peto_one_step"` is an accepted alias and the resolved
|
|
25
|
+
pooling method is `"peto"`.
|
|
26
|
+
|
|
27
|
+
For stratum `i`, let `O_i = a_i`, `m_i = a_i + c_i`, treatment and control
|
|
28
|
+
totals be `n1_i` and `n0_i`, and `N_i = n1_i + n0_i`. Define:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
E_i = m_i n1_i / N_i
|
|
32
|
+
V_i = m_i (N_i - m_i) n1_i n0_i / (N_i^2 (N_i - 1))
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The individual and pooled model-scale estimates are:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
y_i = (O_i - E_i) / V_i
|
|
39
|
+
Var(y_i) = 1 / V_i
|
|
40
|
+
y_Peto = sum(O_i - E_i) / sum(V_i)
|
|
41
|
+
Var(y_Peto) = 1 / sum(V_i)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Pooling always uses raw 2-by-2 tables. The existing
|
|
45
|
+
`continuity_correction` and `correction_scope` settings affect only displayed
|
|
46
|
+
study estimates and variances; there is no Peto pooling correction parameter.
|
|
47
|
+
Double-zero and double-all rows are excluded before every synthesis
|
|
48
|
+
calculation because they contain no relative-effect information.
|
|
49
|
+
|
|
50
|
+
Peto heterogeneity uses the fitted pooled coefficient and the same
|
|
51
|
+
observed-minus-expected contributions:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Q = sum(((O_i - E_i) - y_Peto V_i)^2 / V_i)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Q-based I-squared and H-squared follow the project's common-effect
|
|
58
|
+
conventions. Method options record `peto_pooling_tables="raw"` and
|
|
59
|
+
`peto_heterogeneity="O-minus-E"`. Every Peto result carries an approximation
|
|
60
|
+
warning naming the rare-outcome, balanced-arm, and modest-effect conditions.
|
|
61
|
+
|
|
62
|
+
Random-effects Peto and Peto RR/RD are unsupported. Users requesting those
|
|
63
|
+
estimands must select an implemented inverse-variance or Mantel-Haenszel
|
|
64
|
+
combination explicitly.
|
|
65
|
+
|
|
66
|
+
## Validation
|
|
67
|
+
|
|
68
|
+
- direct formula tests cover study estimates, pooled estimate, variance,
|
|
69
|
+
weights, confidence interval, and Peto Q;
|
|
70
|
+
- treatment/control swapping reverses and exponentiates the log-OR limits as
|
|
71
|
+
expected, while row order leaves the fit unchanged;
|
|
72
|
+
- count scaling and extreme finite-count tests exercise overflow-safe
|
|
73
|
+
arithmetic;
|
|
74
|
+
- sparse tables verify that study-level correction does not alter raw Peto
|
|
75
|
+
pooling and that double-zero/double-all rows are excluded; and
|
|
76
|
+
- fixed-version `metafor::escalc(measure="PETO")` and `metafor::rma.peto()`
|
|
77
|
+
fixtures cover ordinary and sparse datasets.
|
|
78
|
+
|
|
79
|
+
## Consequences
|
|
80
|
+
|
|
81
|
+
- common-effect binary OR now offers MH, Peto, and inverse-variance pooling;
|
|
82
|
+
- Peto results remain on the log-OR model scale and use exponentiated display
|
|
83
|
+
values like other OR results;
|
|
84
|
+
- sensitivity, subgroup, provenance, reporting, and plotting workflows reuse
|
|
85
|
+
the same public result contracts; and
|
|
86
|
+
- documentation and reports must preserve the Peto applicability warning
|
|
87
|
+
rather than presenting it as a general sparse-data default.
|
|
@@ -11,7 +11,7 @@ cd PyMetaAnalysis
|
|
|
11
11
|
python -m pip install -e ".[test,dev,docs,plot]"
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Use a supported Python version (3.10–3.
|
|
14
|
+
Use a supported Python version (3.10–3.14). Keep changes focused and preserve
|
|
15
15
|
unrelated worktree modifications.
|
|
16
16
|
|
|
17
17
|
## Run checks
|
|
@@ -31,7 +31,7 @@ python -m build
|
|
|
31
31
|
python tools/inspect_distribution.py dist
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
The CI matrix also tests Python 3.10–3.
|
|
34
|
+
The CI matrix also tests Python 3.10–3.14 and declared dependency lower bounds.
|
|
35
35
|
Install the `notebook` extra before running the notebook executor.
|
|
36
36
|
|
|
37
37
|
## Statistical changes
|