PyMetaAnalysis 0.6.0__tar.gz → 0.8.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.6.0 → pymetaanalysis-0.8.0}/CHANGELOG.md +66 -7
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/CITATION.cff +2 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/PKG-INFO +16 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/README.md +15 -4
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/benchmarks/README.md +5 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/benchmarks/benchmark_core.py +8 -0
- pymetaanalysis-0.8.0/docs/adr/0007-fisher-z-correlation.md +66 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/citation.md +1 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/getting-started.md +30 -4
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/binary-outcomes.md +21 -0
- pymetaanalysis-0.8.0/docs/guides/correlation-outcomes.md +150 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/input-data.md +3 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/meta-regression.md +5 -4
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/method-selection.md +2 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/plotting.md +49 -4
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/r-interoperability.md +77 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/sensitivity-analysis.md +2 -2
- pymetaanalysis-0.8.0/docs/guides/small-study-effects.md +257 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/zero-events.md +16 -7
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/index.md +14 -11
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/limitations.md +34 -6
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/methods/statistical-methods.md +137 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/reference/api.md +99 -11
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/reference/report-schema.md +10 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/reference/results.md +83 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/validation.md +34 -8
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/mkdocs.yml +3 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/__init__.py +6 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/_version.py +1 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/binary_api.py +25 -9
- pymetaanalysis-0.8.0/src/meta_analyze/correlation_api.py +317 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/design_matrix.py +22 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/effect_sizes/__init__.py +8 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/effect_sizes/binary.py +3 -4
- pymetaanalysis-0.8.0/src/meta_analyze/effect_sizes/correlation.py +215 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/mantel_haenszel.py +3 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/peto.py +10 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/heterogeneity.py +8 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/_utils.py +3 -0
- pymetaanalysis-0.8.0/src/meta_analyze/plotting/funnel.py +444 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/reporting.py +7 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/results.py +51 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/sensitivity.py +26 -4
- pymetaanalysis-0.8.0/src/meta_analyze/small_study_effects.py +961 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/subgroups.py +4 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/README.md +34 -10
- pymetaanalysis-0.8.0/tests/reference/correlation_input.csv +9 -0
- pymetaanalysis-0.8.0/tests/reference/correlation_metafor.json +27 -0
- pymetaanalysis-0.8.0/tests/reference/generate_correlation_metafor.R +59 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_generic_metafor.R +10 -0
- pymetaanalysis-0.8.0/tests/reference/generate_harbord_small_study_effects_meta.R +73 -0
- pymetaanalysis-0.8.0/tests/reference/generate_peters_small_study_effects_meta.R +71 -0
- pymetaanalysis-0.8.0/tests/reference/generate_small_study_effects_metafor.R +56 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_workflow_metafor.R +29 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generic_metafor.json +7 -0
- pymetaanalysis-0.8.0/tests/reference/harbord_small_study_effects_meta.json +24 -0
- pymetaanalysis-0.8.0/tests/reference/peters_small_study_effects_input.csv +13 -0
- pymetaanalysis-0.8.0/tests/reference/peters_small_study_effects_meta.json +25 -0
- pymetaanalysis-0.8.0/tests/reference/small_study_effects_input.csv +13 -0
- pymetaanalysis-0.8.0/tests/reference/small_study_effects_metafor.json +20 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/workflow_metafor.json +14 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_binary.py +79 -2
- pymetaanalysis-0.8.0/tests/test_correlation.py +288 -0
- pymetaanalysis-0.8.0/tests/test_funnel_plot.py +499 -0
- pymetaanalysis-0.8.0/tests/test_harbord_small_study_effects.py +330 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_meta_regression.py +42 -13
- pymetaanalysis-0.8.0/tests/test_peters_small_study_effects.py +301 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_plotting.py +24 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_properties.py +62 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_r_references.py +79 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_release_readiness.py +1 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_sensitivity.py +24 -0
- pymetaanalysis-0.8.0/tests/test_small_study_effects.py +264 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_subgroups.py +15 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tools/check_release.py +30 -0
- pymetaanalysis-0.6.0/src/meta_analyze/plotting/funnel.py +0 -168
- pymetaanalysis-0.6.0/tests/test_funnel_plot.py +0 -198
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/.github/workflows/ci.yml +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/.github/workflows/pages.yml +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/.github/workflows/release.yml +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/.gitignore +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/CONTRIBUTING.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/LICENSE +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/SECURITY.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0001-optional-matplotlib.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0002-statistical-policy.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0003-meta-regression-prediction-intervals.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0004-hartung-knapp-prediction-intervals.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0005-mantel-haenszel-risk-difference.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0006-peto-odds-ratio.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/development.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/continuous-outcomes.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/generic-effects.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/provenance-reporting.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/installation.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/releasing.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/stylesheets/extra.css +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/examples/README.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/examples/meta_regression.ipynb +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/examples/quickstart.ipynb +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/pyproject.toml +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/api.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/config.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/continuous_api.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/data.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/effect_sizes/continuous.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/__init__.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/inverse_variance.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/meta_regression.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/tau2.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/exceptions.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/__init__.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/forest.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/regression.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/subgroup_forest.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/provenance.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/py.typed +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_api.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_collinearity.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_contrasts.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_results.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_sensitivity.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/binary_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/binary_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/binary_sparse_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/continuous_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/continuous_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_binary_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_continuous_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_meta_regression_collinearity_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_meta_regression_contrasts_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_meta_regression_influence_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_meta_regression_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generic_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_boundary_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_collinearity_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_contrasts_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_influence_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/workflow_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_api.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_continuous.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_documentation.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_estimators.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_numerical_stability.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_reference_results.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_collinearity.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_contrasts.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_influence.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_plotting.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_sensitivity.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_reporting.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tools/execute_notebooks.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tools/inspect_distribution.py +0 -0
|
@@ -6,6 +6,57 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 0.8.0 - 2026-09-04
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `MetaAnalysisResult.funnel()` supports optional contour-enhanced two-sided
|
|
14
|
+
significance regions with validated levels, display-scale null references,
|
|
15
|
+
configurable colors and legend, while preserving pooled pseudo-limit lines.
|
|
16
|
+
- `MetaAnalysisResult.egger_test()` implements the classical standard-error
|
|
17
|
+
Egger regression test for funnel-plot asymmetry with multiplicative
|
|
18
|
+
dispersion, t inference, an explicitly labeled limit estimate, applicability
|
|
19
|
+
warnings, and an independent R `metafor` reference fixture.
|
|
20
|
+
- `MetaAnalysisResult.harbord_test()` implements the Harbord efficient-score
|
|
21
|
+
test for two-group binary odds ratios, without continuity correction, with
|
|
22
|
+
multiplicative dispersion, t inference, and an independent R `meta`
|
|
23
|
+
reference fixture.
|
|
24
|
+
- `MetaAnalysisResult.peters_test()` implements the Peters regression test for
|
|
25
|
+
two-group binary odds ratios, reusing the recorded study-level continuity
|
|
26
|
+
correction and validating the slope, limit estimate, and multiplicative
|
|
27
|
+
dispersion against an independent R `meta` reference fixture.
|
|
28
|
+
|
|
29
|
+
## 0.7.0 - 2026-09-02
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- `meta_correlation()` for independent study-level correlations using Fisher's
|
|
34
|
+
r-to-z transformation (`ZCOR`), `1 / (n - 3)` sampling variances, common- or
|
|
35
|
+
REML/PM/DL random-effects inverse-variance pooling, back-transformed result
|
|
36
|
+
displays, subgroup and sensitivity workflows, plotting, provenance, reports,
|
|
37
|
+
and independent R `metafor` references.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- integer-valued floating-point categorical moderators now match declared
|
|
42
|
+
integer levels while booleans remain distinct, supporting pandas columns
|
|
43
|
+
promoted to floating point by missing values;
|
|
44
|
+
- MH pooling corrections now use `None` as the context-sensitive scope default;
|
|
45
|
+
explicitly supplying either MH-only option to IV or Peto pooling raises an
|
|
46
|
+
error, and non-MH method metadata no longer records unused MH settings;
|
|
47
|
+
- estimator documentation now makes the pooled-mean-only Q-profile contract,
|
|
48
|
+
the prefiltered `fit_peto()` input contract, and sparse MH RD boundary policy
|
|
49
|
+
explicit;
|
|
50
|
+
- fixed-version `metafor` references now cover a two-study Hartung-Knapp
|
|
51
|
+
interval and Q-profile intervals reached through random-effects subgroups.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- normal-inference subgroup tests reuse each fitted standard error directly,
|
|
56
|
+
avoiding an unnecessary recomputation and last-bit numerical drift.
|
|
57
|
+
- Peto observed-minus-expected arithmetic now uses a treatment/control-symmetric
|
|
58
|
+
formulation, preventing avoidable last-bit drift for highly imbalanced arms.
|
|
59
|
+
|
|
9
60
|
## 0.6.0 - 2026-08-13
|
|
10
61
|
|
|
11
62
|
### Added
|
|
@@ -43,6 +94,21 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
43
94
|
Mantel-Haenszel pooling correction; iterative failure paths have direct
|
|
44
95
|
regression tests.
|
|
45
96
|
|
|
97
|
+
### Breaking changes
|
|
98
|
+
|
|
99
|
+
- explicitly supplying `tau2_method` to a common-effect model, including the
|
|
100
|
+
former default spelling `"REML"`, now raises an error instead of being
|
|
101
|
+
ignored; explicitly inapplicable SMD variance settings follow the same rule;
|
|
102
|
+
- cumulative analysis now rejects a string `order` selector when the name is
|
|
103
|
+
present in both source data and the calculated study table, instead of
|
|
104
|
+
silently preferring the source-data column;
|
|
105
|
+
- `LeaveOneOutResult.results` now preserves failed refits as `None`, and its
|
|
106
|
+
table adds `refit_success`, `error_type`, and `error_message` columns;
|
|
107
|
+
- pooled-result `prediction_interval_method` metadata now uses `null` when an
|
|
108
|
+
interval is unavailable and `"HK-PR"` for Hartung-Knapp intervals. Report
|
|
109
|
+
schema 1.2 remains unchanged because the field itself was already present;
|
|
110
|
+
consumers must handle the documented value set.
|
|
111
|
+
|
|
46
112
|
### Fixed
|
|
47
113
|
|
|
48
114
|
- inverse-variance means, heterogeneity statistics, and pooling and
|
|
@@ -71,9 +137,6 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
71
137
|
analysis;
|
|
72
138
|
- tagged releases now rerun the full branch-coverage test suite before
|
|
73
139
|
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
140
|
- duplicate study labels now add a row-position warning while preserving
|
|
78
141
|
`row_id` as the unique audit key;
|
|
79
142
|
- report JSON now serializes `pd.NaT` study labels as `null` rather than the
|
|
@@ -81,8 +144,6 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
81
144
|
- Meta-regression with `missing="drop"` now determines complete-row exclusions
|
|
82
145
|
before validating moderator values, so invalid values in already excluded
|
|
83
146
|
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
147
|
- empty inputs now report that at least one study row is required, and binary
|
|
87
148
|
zero-cell errors identify when `correction_scope="none"` disables an
|
|
88
149
|
otherwise positive correction.
|
|
@@ -94,8 +155,6 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
94
155
|
errors;
|
|
95
156
|
- the Mantel-Haenszel estimator now rejects empty and zero-total strata before
|
|
96
157
|
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
158
|
- categorical moderator encoding no longer conflates booleans, integers, and
|
|
100
159
|
floating-point values through Python's cross-type numeric equality;
|
|
101
160
|
- CI now covers Python 3.14, Pages deployments are not cancelled mid-flight,
|
|
@@ -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.8.0
|
|
12
|
+
date-released: 2026-09-04
|
|
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.8.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
|
|
@@ -135,6 +135,7 @@ not individual-level or causal effects.
|
|
|
135
135
|
| Effect + sampling variance or standard error | Generic | Common/random inverse variance |
|
|
136
136
|
| Two-group events + totals | OR, RR, RD | Common MH; common Peto OR; common/random IV |
|
|
137
137
|
| Two-group means + SDs + sizes | MD, Hedges' g | Common/random inverse variance |
|
|
138
|
+
| Correlations + sample sizes | Fisher's z (`ZCOR`) | Common/random inverse variance |
|
|
138
139
|
| Effect + variance/SE + moderators | Generic | Common/mixed Meta-regression |
|
|
139
140
|
|
|
140
141
|
Random-effects inverse-variance models support REML (default), Paule-Mandel,
|
|
@@ -182,7 +183,8 @@ markdown = report.to_markdown()
|
|
|
182
183
|
|
|
183
184
|
OR and RR remain on the log model scale in auditable numeric attributes;
|
|
184
185
|
`display_estimate`, `display_ci`, and `display_prediction_interval` provide
|
|
185
|
-
exponentiated ratios.
|
|
186
|
+
exponentiated ratios. `ZCOR` results similarly retain Fisher's z internally
|
|
187
|
+
and expose back-transformed correlations through the display properties.
|
|
186
188
|
|
|
187
189
|
Rows excluded by missing-value or sparse-data policies remain in
|
|
188
190
|
`study_results` with a stable `row_id`, `included=False`, and an
|
|
@@ -193,6 +195,9 @@ Rows excluded by missing-value or sparse-data policies remain in
|
|
|
193
195
|
```python
|
|
194
196
|
leave_one_out = result.leave_one_out().to_dataframe()
|
|
195
197
|
cumulative = result.cumulative(order="publication_year").to_dataframe()
|
|
198
|
+
egger = result.egger_test()
|
|
199
|
+
harbord = binary_or_result.harbord_test()
|
|
200
|
+
peters = binary_or_result.peters_test()
|
|
196
201
|
regression_deleted = regression.leave_one_out()
|
|
197
202
|
regression_coefficient_changes = regression_deleted.coefficients
|
|
198
203
|
regression_influence = regression.influence()
|
|
@@ -208,10 +213,16 @@ south_vs_east = regression.contrast(
|
|
|
208
213
|
|
|
209
214
|
ax = result.forest(show_prediction_interval=True)
|
|
210
215
|
ax = result.funnel()
|
|
216
|
+
contour_ax = result.funnel(contour_levels=(0.90, 0.95, 0.99))
|
|
211
217
|
```
|
|
212
218
|
|
|
213
219
|
Plotting methods return Matplotlib axes and never call `show()`. Funnel plots
|
|
214
|
-
are descriptive small-study-effect diagnostics
|
|
220
|
+
are descriptive small-study-effect diagnostics; optional significance contours
|
|
221
|
+
show where two-sided p-value bands fall relative to the null. Classical Egger
|
|
222
|
+
regression is available for general effects, while Harbord and Peters provide
|
|
223
|
+
outcome-specific alternatives for two-group binary odds ratios. All include
|
|
224
|
+
explicit applicability cautions. Neither a funnel plot nor any test proves
|
|
225
|
+
publication bias.
|
|
215
226
|
Meta-regression leave-one-out results also expose a long-form coefficient
|
|
216
227
|
change table. Exact influence diagnostics add externally standardized
|
|
217
228
|
residuals, Cook's distance, DFBETAS, and explicit heuristic screening
|
|
@@ -235,10 +246,10 @@ The complete documentation is published at
|
|
|
235
246
|
- [Installation](https://zhaoboding.github.io/PyMetaAnalysis/installation/)
|
|
236
247
|
- [Getting started](https://zhaoboding.github.io/PyMetaAnalysis/getting-started/)
|
|
237
248
|
- [Input data and row decisions](https://zhaoboding.github.io/PyMetaAnalysis/guides/input-data/)
|
|
238
|
-
- [Generic](https://zhaoboding.github.io/PyMetaAnalysis/guides/generic-effects/), [binary](https://zhaoboding.github.io/PyMetaAnalysis/guides/binary-outcomes/),
|
|
249
|
+
- [Generic](https://zhaoboding.github.io/PyMetaAnalysis/guides/generic-effects/), [binary](https://zhaoboding.github.io/PyMetaAnalysis/guides/binary-outcomes/), [continuous](https://zhaoboding.github.io/PyMetaAnalysis/guides/continuous-outcomes/), and [correlation](https://zhaoboding.github.io/PyMetaAnalysis/guides/correlation-outcomes/) guides
|
|
239
250
|
- [Meta-regression](https://zhaoboding.github.io/PyMetaAnalysis/guides/meta-regression/)
|
|
240
251
|
- [Choosing methods](https://zhaoboding.github.io/PyMetaAnalysis/guides/method-selection/) and [statistical formulas](https://zhaoboding.github.io/PyMetaAnalysis/methods/statistical-methods/)
|
|
241
|
-
- [Sensitivity analysis](https://zhaoboding.github.io/PyMetaAnalysis/guides/sensitivity-analysis/) and [plotting](https://zhaoboding.github.io/PyMetaAnalysis/guides/plotting/)
|
|
252
|
+
- [Sensitivity analysis](https://zhaoboding.github.io/PyMetaAnalysis/guides/sensitivity-analysis/), [small-study effects](https://zhaoboding.github.io/PyMetaAnalysis/guides/small-study-effects/), and [plotting](https://zhaoboding.github.io/PyMetaAnalysis/guides/plotting/)
|
|
242
253
|
- [Public API](https://zhaoboding.github.io/PyMetaAnalysis/reference/api/), [result objects](https://zhaoboding.github.io/PyMetaAnalysis/reference/results/), and [report schema](https://zhaoboding.github.io/PyMetaAnalysis/reference/report-schema/)
|
|
243
254
|
- [Validation strategy](https://zhaoboding.github.io/PyMetaAnalysis/validation/) and [scope/limitations](https://zhaoboding.github.io/PyMetaAnalysis/limitations/)
|
|
244
255
|
- [Citation guidance](https://zhaoboding.github.io/PyMetaAnalysis/citation/)
|
|
@@ -85,6 +85,7 @@ not individual-level or causal effects.
|
|
|
85
85
|
| Effect + sampling variance or standard error | Generic | Common/random inverse variance |
|
|
86
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
|
+
| Correlations + sample sizes | Fisher's z (`ZCOR`) | Common/random inverse variance |
|
|
88
89
|
| Effect + variance/SE + moderators | Generic | Common/mixed Meta-regression |
|
|
89
90
|
|
|
90
91
|
Random-effects inverse-variance models support REML (default), Paule-Mandel,
|
|
@@ -132,7 +133,8 @@ markdown = report.to_markdown()
|
|
|
132
133
|
|
|
133
134
|
OR and RR remain on the log model scale in auditable numeric attributes;
|
|
134
135
|
`display_estimate`, `display_ci`, and `display_prediction_interval` provide
|
|
135
|
-
exponentiated ratios.
|
|
136
|
+
exponentiated ratios. `ZCOR` results similarly retain Fisher's z internally
|
|
137
|
+
and expose back-transformed correlations through the display properties.
|
|
136
138
|
|
|
137
139
|
Rows excluded by missing-value or sparse-data policies remain in
|
|
138
140
|
`study_results` with a stable `row_id`, `included=False`, and an
|
|
@@ -143,6 +145,9 @@ Rows excluded by missing-value or sparse-data policies remain in
|
|
|
143
145
|
```python
|
|
144
146
|
leave_one_out = result.leave_one_out().to_dataframe()
|
|
145
147
|
cumulative = result.cumulative(order="publication_year").to_dataframe()
|
|
148
|
+
egger = result.egger_test()
|
|
149
|
+
harbord = binary_or_result.harbord_test()
|
|
150
|
+
peters = binary_or_result.peters_test()
|
|
146
151
|
regression_deleted = regression.leave_one_out()
|
|
147
152
|
regression_coefficient_changes = regression_deleted.coefficients
|
|
148
153
|
regression_influence = regression.influence()
|
|
@@ -158,10 +163,16 @@ south_vs_east = regression.contrast(
|
|
|
158
163
|
|
|
159
164
|
ax = result.forest(show_prediction_interval=True)
|
|
160
165
|
ax = result.funnel()
|
|
166
|
+
contour_ax = result.funnel(contour_levels=(0.90, 0.95, 0.99))
|
|
161
167
|
```
|
|
162
168
|
|
|
163
169
|
Plotting methods return Matplotlib axes and never call `show()`. Funnel plots
|
|
164
|
-
are descriptive small-study-effect diagnostics
|
|
170
|
+
are descriptive small-study-effect diagnostics; optional significance contours
|
|
171
|
+
show where two-sided p-value bands fall relative to the null. Classical Egger
|
|
172
|
+
regression is available for general effects, while Harbord and Peters provide
|
|
173
|
+
outcome-specific alternatives for two-group binary odds ratios. All include
|
|
174
|
+
explicit applicability cautions. Neither a funnel plot nor any test proves
|
|
175
|
+
publication bias.
|
|
165
176
|
Meta-regression leave-one-out results also expose a long-form coefficient
|
|
166
177
|
change table. Exact influence diagnostics add externally standardized
|
|
167
178
|
residuals, Cook's distance, DFBETAS, and explicit heuristic screening
|
|
@@ -185,10 +196,10 @@ The complete documentation is published at
|
|
|
185
196
|
- [Installation](https://zhaoboding.github.io/PyMetaAnalysis/installation/)
|
|
186
197
|
- [Getting started](https://zhaoboding.github.io/PyMetaAnalysis/getting-started/)
|
|
187
198
|
- [Input data and row decisions](https://zhaoboding.github.io/PyMetaAnalysis/guides/input-data/)
|
|
188
|
-
- [Generic](https://zhaoboding.github.io/PyMetaAnalysis/guides/generic-effects/), [binary](https://zhaoboding.github.io/PyMetaAnalysis/guides/binary-outcomes/),
|
|
199
|
+
- [Generic](https://zhaoboding.github.io/PyMetaAnalysis/guides/generic-effects/), [binary](https://zhaoboding.github.io/PyMetaAnalysis/guides/binary-outcomes/), [continuous](https://zhaoboding.github.io/PyMetaAnalysis/guides/continuous-outcomes/), and [correlation](https://zhaoboding.github.io/PyMetaAnalysis/guides/correlation-outcomes/) guides
|
|
189
200
|
- [Meta-regression](https://zhaoboding.github.io/PyMetaAnalysis/guides/meta-regression/)
|
|
190
201
|
- [Choosing methods](https://zhaoboding.github.io/PyMetaAnalysis/guides/method-selection/) and [statistical formulas](https://zhaoboding.github.io/PyMetaAnalysis/methods/statistical-methods/)
|
|
191
|
-
- [Sensitivity analysis](https://zhaoboding.github.io/PyMetaAnalysis/guides/sensitivity-analysis/) and [plotting](https://zhaoboding.github.io/PyMetaAnalysis/guides/plotting/)
|
|
202
|
+
- [Sensitivity analysis](https://zhaoboding.github.io/PyMetaAnalysis/guides/sensitivity-analysis/), [small-study effects](https://zhaoboding.github.io/PyMetaAnalysis/guides/small-study-effects/), and [plotting](https://zhaoboding.github.io/PyMetaAnalysis/guides/plotting/)
|
|
192
203
|
- [Public API](https://zhaoboding.github.io/PyMetaAnalysis/reference/api/), [result objects](https://zhaoboding.github.io/PyMetaAnalysis/reference/results/), and [report schema](https://zhaoboding.github.io/PyMetaAnalysis/reference/report-schema/)
|
|
193
204
|
- [Validation strategy](https://zhaoboding.github.io/PyMetaAnalysis/validation/) and [scope/limitations](https://zhaoboding.github.io/PyMetaAnalysis/limitations/)
|
|
194
205
|
- [Citation guidance](https://zhaoboding.github.io/PyMetaAnalysis/citation/)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Core performance baseline
|
|
2
2
|
|
|
3
|
-
`benchmark_core.py` measures representative generic, binary, continuous,
|
|
4
|
-
multivariable Meta-regression random-effects fits using
|
|
5
|
-
data. Correctness remains the primary performance
|
|
6
|
-
is intended to reveal large regressions, not to
|
|
7
|
-
threshold.
|
|
3
|
+
`benchmark_core.py` measures representative generic, binary, continuous,
|
|
4
|
+
correlation, and multivariable Meta-regression random-effects fits using
|
|
5
|
+
deterministic synthetic data. Correctness remains the primary performance
|
|
6
|
+
requirement; this benchmark is intended to reveal large regressions, not to
|
|
7
|
+
enforce a fragile wall-clock threshold.
|
|
8
8
|
|
|
9
9
|
Run the default benchmark with:
|
|
10
10
|
|
|
@@ -48,6 +48,8 @@ def _cases(studies: int) -> dict[str, Callable[[], object]]:
|
|
|
48
48
|
mean_treat = mean_control + rng.normal(0.25, 0.18, size=studies)
|
|
49
49
|
sd_treat = rng.uniform(0.7, 1.6, size=studies)
|
|
50
50
|
sd_control = rng.uniform(0.7, 1.6, size=studies)
|
|
51
|
+
correlation = rng.uniform(-0.65, 0.65, size=studies)
|
|
52
|
+
correlation_n = rng.integers(20, 300, size=studies)
|
|
51
53
|
|
|
52
54
|
return {
|
|
53
55
|
"generic_random_reml": lambda: ma.meta_analysis(
|
|
@@ -77,6 +79,12 @@ def _cases(studies: int) -> dict[str, Callable[[], object]]:
|
|
|
77
79
|
model="random",
|
|
78
80
|
tau2_method="REML",
|
|
79
81
|
),
|
|
82
|
+
"correlation_random_reml": lambda: ma.meta_correlation(
|
|
83
|
+
correlation=correlation,
|
|
84
|
+
n=correlation_n,
|
|
85
|
+
model="random",
|
|
86
|
+
tau2_method="REML",
|
|
87
|
+
),
|
|
80
88
|
"meta_regression_multivariable_reml": lambda: ma.meta_regression(
|
|
81
89
|
effect=generic_effect,
|
|
82
90
|
variance=generic_variance,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# ADR 0007: Fisher's z correlation pooling
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2026-09-02
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Study-level correlations are common in behavioral, educational, and medical
|
|
9
|
+
research. Directly pooling raw correlations is possible but their sampling
|
|
10
|
+
distribution is bounded, asymmetric away from zero, and has a variance that
|
|
11
|
+
depends on the underlying correlation. Fisher's r-to-z transformation is the
|
|
12
|
+
standard first implementation in R `meta` and `metafor` and composes with the
|
|
13
|
+
library's existing inverse-variance machinery.
|
|
14
|
+
|
|
15
|
+
The API also needs an explicit position on perfect correlations, very small
|
|
16
|
+
samples, displayed values, and multiple correlations drawn from the same
|
|
17
|
+
participants.
|
|
18
|
+
|
|
19
|
+
## Decision
|
|
20
|
+
|
|
21
|
+
`meta_correlation()` accepts raw `correlation` and sample size `n`, but its
|
|
22
|
+
first supported measure is only `ZCOR`:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
y_i = atanh(r_i)
|
|
26
|
+
v_i = 1 / (n_i - 3)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
All fitting and heterogeneity calculations use Fisher's z. Result display
|
|
30
|
+
properties and plots use `tanh` to return the correlation scale. The result
|
|
31
|
+
records `effect_scale="fisher_z"`, `display_scale="tanh"`, the transformation,
|
|
32
|
+
variance equation, affected rows, and input sources.
|
|
33
|
+
|
|
34
|
+
Included correlations must be finite and strictly between -1 and 1. Sample
|
|
35
|
+
sizes must be whole numbers of at least 4. The implementation does not clip
|
|
36
|
+
perfect correlations or replace invalid sample sizes because either action
|
|
37
|
+
would introduce an undocumented effect or variance.
|
|
38
|
+
|
|
39
|
+
The default is the library's random-effects inverse-variance policy: REML
|
|
40
|
+
tau-squared and a normal confidence interval. Common effects, PM/DL, the two
|
|
41
|
+
documented Hartung-Knapp options, shared prediction intervals, Q-profile
|
|
42
|
+
heterogeneity intervals, subgroups, repeated-fit sensitivity, reports, and
|
|
43
|
+
plots reuse their existing contracts.
|
|
44
|
+
|
|
45
|
+
Rows are assumed independent. Duplicate labels remain allowed and warned, but
|
|
46
|
+
do not imply a dependence correction. Raw-correlation pooling (`COR`),
|
|
47
|
+
dependent correlations, partial/rank correlations, and reliability
|
|
48
|
+
corrections are deferred.
|
|
49
|
+
|
|
50
|
+
## Validation
|
|
51
|
+
|
|
52
|
+
Committed fixtures generated by `metafor::escalc(measure="ZCOR")` and
|
|
53
|
+
`rma.uni()` validate study effects, variances, common-effect and REML fits,
|
|
54
|
+
weights, and back-transformation. Targeted and property-based tests cover
|
|
55
|
+
domain boundaries, missing rows, sign symmetry, row-order invariance,
|
|
56
|
+
subgroups, sensitivity refits, reports, and Matplotlib coordinates.
|
|
57
|
+
|
|
58
|
+
## Consequences
|
|
59
|
+
|
|
60
|
+
- users can supply pandas columns without calculating z values or variances;
|
|
61
|
+
- model-scale and correlation-scale results remain distinguishable;
|
|
62
|
+
- behavior matches a documented R workflow without importing R at runtime;
|
|
63
|
+
- perfect correlations and samples smaller than four require an upstream,
|
|
64
|
+
scientifically justified decision rather than silent repair;
|
|
65
|
+
- users with dependent correlations must use a method outside the current
|
|
66
|
+
univariate scope.
|
|
@@ -19,7 +19,7 @@ print(ma.__version__)
|
|
|
19
19
|
A provisional citation can use:
|
|
20
20
|
|
|
21
21
|
```text
|
|
22
|
-
|
|
22
|
+
Zhaobo Ding. PyMetaAnalysis (version <version>):
|
|
23
23
|
a pandas-first meta-analysis library for Python.
|
|
24
24
|
https://github.com/ZhaoboDing/PyMetaAnalysis
|
|
25
25
|
```
|
|
@@ -120,8 +120,9 @@ schema, strict JSON behavior, and subgroup reports.
|
|
|
120
120
|
## 6. Understand model and display scales
|
|
121
121
|
|
|
122
122
|
Generic effects, MD, SMD, and RD use the identity scale. OR and RR are modeled
|
|
123
|
-
on a log scale,
|
|
124
|
-
|
|
123
|
+
on a log scale, while `ZCOR` is modeled on Fisher's z scale. Their audit-
|
|
124
|
+
friendly numeric attributes remain on those model scales. Use display
|
|
125
|
+
properties for ratios and back-transformed correlations:
|
|
125
126
|
|
|
126
127
|
```python
|
|
127
128
|
result.display_estimate
|
|
@@ -130,7 +131,8 @@ result.display_prediction_interval
|
|
|
130
131
|
```
|
|
131
132
|
|
|
132
133
|
The [binary-outcome guide](guides/binary-outcomes.md) includes a complete ratio
|
|
133
|
-
example.
|
|
134
|
+
example; the [correlation guide](guides/correlation-outcomes.md) explains the
|
|
135
|
+
Fisher transformation.
|
|
134
136
|
|
|
135
137
|
## 7. Check sensitivity
|
|
136
138
|
|
|
@@ -158,10 +160,34 @@ After installing the `plot` extra:
|
|
|
158
160
|
```python
|
|
159
161
|
ax = result.forest(show_prediction_interval=True)
|
|
160
162
|
ax = result.funnel()
|
|
163
|
+
contour_ax = result.funnel(contour_levels=(0.90, 0.95, 0.99))
|
|
161
164
|
```
|
|
162
165
|
|
|
163
166
|
Both methods return a Matplotlib `Axes` and never call `show()`. This keeps them
|
|
164
|
-
usable in notebooks, scripts, tests, and composed figures.
|
|
167
|
+
usable in notebooks, scripts, tests, and composed figures. Funnel contours show
|
|
168
|
+
two-sided significance regions around the null effect; they do not estimate
|
|
169
|
+
missing studies.
|
|
170
|
+
|
|
171
|
+
The classical Egger regression test is available separately from plotting:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
egger = result.egger_test()
|
|
175
|
+
print(egger)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
It tests for funnel-plot asymmetry or small-study effects, not publication bias
|
|
179
|
+
itself. Read [small-study effects](guides/small-study-effects.md) before using or
|
|
180
|
+
interpreting it.
|
|
181
|
+
|
|
182
|
+
For a two-group binary odds-ratio result, the outcome-specific Harbord and
|
|
183
|
+
Peters tests are also available:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
harbord = binary_or_result.harbord_test()
|
|
187
|
+
peters = binary_or_result.peters_test()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
They require the retained event and group-size counts from `meta_binary()`.
|
|
165
191
|
|
|
166
192
|
See [plotting](guides/plotting.md) for every parameter, display-scale rules,
|
|
167
193
|
axes composition, and interpretation cautions.
|
|
@@ -120,6 +120,27 @@ calculations. See [zero-event studies](zero-events.md) for details.
|
|
|
120
120
|
Use `method="IV"` for random-effects RD or when inverse-variance common-effect
|
|
121
121
|
pooling is the prespecified estimator.
|
|
122
122
|
|
|
123
|
+
## Harbord and Peters small-study-effect tests for odds ratios
|
|
124
|
+
|
|
125
|
+
An OR result retains the original two-group counts needed for both
|
|
126
|
+
outcome-specific regressions:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
harbord = odds_ratio_result.harbord_test()
|
|
130
|
+
peters = odds_ratio_result.peters_test()
|
|
131
|
+
print(harbord)
|
|
132
|
+
print(peters)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Call these only when the result was fitted with `measure="OR"`. Harbord uses
|
|
136
|
+
null efficient scores and no continuity correction; Peters reconstructs study
|
|
137
|
+
log odds ratios with the recorded study-level correction. Both are independent
|
|
138
|
+
of the source MH, IV, random-effects IV, or Peto pooling choice. They diagnose
|
|
139
|
+
different forms of small-study association and do not prove publication bias
|
|
140
|
+
or replace the pooled estimate. See
|
|
141
|
+
[small-study effects](small-study-effects.md) for the complete method and
|
|
142
|
+
interpretation contract.
|
|
143
|
+
|
|
123
144
|
## Input validation
|
|
124
145
|
|
|
125
146
|
Event counts and sample sizes must be finite, integer-valued, and non-negative;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Correlation outcomes
|
|
2
|
+
|
|
3
|
+
Use `meta_correlation()` when each independent study contributes a Pearson
|
|
4
|
+
correlation and its sample size. The first implementation deliberately
|
|
5
|
+
supports only Fisher's z (`measure="ZCOR"`), the conventional
|
|
6
|
+
variance-stabilizing route implemented by R `metafor::escalc(measure="ZCOR")`
|
|
7
|
+
and `meta::metacor(sm="ZCOR")`.
|
|
8
|
+
|
|
9
|
+
## DataFrame input
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import pandas as pd
|
|
13
|
+
import meta_analyze as ma
|
|
14
|
+
|
|
15
|
+
studies = pd.DataFrame(
|
|
16
|
+
{
|
|
17
|
+
"r": [0.18, 0.42, -0.05, 0.31, 0.27],
|
|
18
|
+
"sample_size": [84, 120, 63, 95, 150],
|
|
19
|
+
},
|
|
20
|
+
index=["Study A", "Study B", "Study C", "Study D", "Study E"],
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
result = ma.meta_correlation(
|
|
24
|
+
studies,
|
|
25
|
+
correlation="r",
|
|
26
|
+
n="sample_size",
|
|
27
|
+
model="random",
|
|
28
|
+
tau2_method="REML",
|
|
29
|
+
)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Omitting `study=` uses the DataFrame index. Lists, NumPy arrays, and pandas
|
|
33
|
+
Series are also accepted directly.
|
|
34
|
+
|
|
35
|
+
## Model and display scales
|
|
36
|
+
|
|
37
|
+
Each study is transformed before fitting:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
z_i = atanh(r_i)
|
|
41
|
+
variance_i = 1 / (n_i - 3)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The model, confidence interval, prediction interval, tau-squared, and
|
|
45
|
+
heterogeneity calculations remain on Fisher's z scale. This is explicit in
|
|
46
|
+
the result:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
result.effect_scale # "fisher_z"
|
|
50
|
+
result.estimate # pooled Fisher's z
|
|
51
|
+
result.ci # Fisher's z confidence interval
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Use display properties for back-transformed correlations:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
result.display_scale # "tanh"
|
|
58
|
+
result.display_estimate
|
|
59
|
+
result.display_ci
|
|
60
|
+
result.display_prediction_interval
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The pooled correlation is `tanh(pooled_z)`. It is not a direct weighted
|
|
64
|
+
average of the raw correlations.
|
|
65
|
+
|
|
66
|
+
## Input boundaries
|
|
67
|
+
|
|
68
|
+
Included rows must satisfy:
|
|
69
|
+
|
|
70
|
+
- a finite correlation strictly between -1 and 1;
|
|
71
|
+
- a whole-number sample size of at least 4.
|
|
72
|
+
|
|
73
|
+
Values at -1 or 1 would produce an infinite Fisher's z. A sample size no
|
|
74
|
+
larger than 3 would make `1 / (n - 3)` non-positive or undefined. Both cases
|
|
75
|
+
raise `InvalidStudyDataError` instead of being clipped or corrected.
|
|
76
|
+
|
|
77
|
+
With `missing="drop"`, missing correlation or sample-size rows remain in
|
|
78
|
+
`study_results` as explicit exclusions. Invalid non-missing values still
|
|
79
|
+
raise an error.
|
|
80
|
+
|
|
81
|
+
## Models and uncertainty
|
|
82
|
+
|
|
83
|
+
The default is a random-effects inverse-variance model with REML. Common-
|
|
84
|
+
effect pooling and the same random-effects choices as the generic API are
|
|
85
|
+
available:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
common = ma.meta_correlation(
|
|
89
|
+
studies,
|
|
90
|
+
correlation="r",
|
|
91
|
+
n="sample_size",
|
|
92
|
+
model="common",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
hk = ma.meta_correlation(
|
|
96
|
+
studies,
|
|
97
|
+
correlation="r",
|
|
98
|
+
n="sample_size",
|
|
99
|
+
model="random",
|
|
100
|
+
tau2_method="PM",
|
|
101
|
+
ci_method="hartung_knapp_adhoc",
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`tau2_method` supports REML, PM, and DL for random effects. Normal,
|
|
106
|
+
Hartung-Knapp, prediction-interval, and Q-profile behavior follows the shared
|
|
107
|
+
inverse-variance implementation and remains on the z scale until displayed.
|
|
108
|
+
|
|
109
|
+
## Subgroups, sensitivity, reports, and plots
|
|
110
|
+
|
|
111
|
+
The standard workflows are available without reconstructing effects by hand:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
studies = studies.assign(
|
|
115
|
+
population=["adult", "adult", "adult", "youth", "youth"],
|
|
116
|
+
publication_year=[2001, 2004, 2008, 2011, 2015],
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
subgroups = ma.meta_correlation(
|
|
120
|
+
studies,
|
|
121
|
+
correlation="r",
|
|
122
|
+
n="sample_size",
|
|
123
|
+
subgroup="population",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
leave_one_out = result.leave_one_out().to_dataframe()
|
|
127
|
+
cumulative = result.cumulative(order="publication_year").to_dataframe()
|
|
128
|
+
methods = result.method_details()
|
|
129
|
+
report = result.report().to_dict()
|
|
130
|
+
forest_ax = result.forest()
|
|
131
|
+
funnel_ax = result.funnel()
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Forest and funnel x-coordinates are back-transformed correlations on a linear
|
|
135
|
+
axis by default. Funnel standard errors remain model-scale Fisher's z standard
|
|
136
|
+
errors.
|
|
137
|
+
|
|
138
|
+
## Independence boundary
|
|
139
|
+
|
|
140
|
+
This API assumes one independent effect per study. Repeated outcomes,
|
|
141
|
+
different variable pairs, or multiple time points from the same participants
|
|
142
|
+
are statistically dependent even if their rows have different labels.
|
|
143
|
+
PyMetaAnalysis does not currently estimate the covariance matrix or fit a
|
|
144
|
+
multilevel/multivariate model for those data. Select one prespecified effect,
|
|
145
|
+
combine effects using an appropriate external method, or use software that
|
|
146
|
+
models dependence explicitly.
|
|
147
|
+
|
|
148
|
+
The first release also does not support raw-correlation pooling (`COR`),
|
|
149
|
+
partial correlations, rank correlations, or reliability corrections. Passing
|
|
150
|
+
`measure="COR"` raises `UnsupportedMethodError`.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Every analysis entry point accepts either DataFrame column names or
|
|
4
4
|
one-dimensional array-like values. This page describes rules shared by the
|
|
5
|
-
generic, binary, and
|
|
5
|
+
generic, binary, continuous, and correlation APIs.
|
|
6
6
|
|
|
7
7
|
## DataFrame columns
|
|
8
8
|
|
|
@@ -105,8 +105,9 @@ silently assigning or dropping them would change the subgroup definition.
|
|
|
105
105
|
| Generic | finite effect; finite, strictly positive sampling variance large enough for a finite float64 inverse weight |
|
|
106
106
|
| Binary | integer event counts and totals; positive totals; `0 <= events <= total` |
|
|
107
107
|
| Continuous | finite means/SDs; non-negative SDs; integer group sizes of at least 2 |
|
|
108
|
+
| Correlation | finite `-1 < correlation < 1`; integer sample size `n >= 4` |
|
|
108
109
|
|
|
109
|
-
Binary and
|
|
110
|
+
Binary, continuous, and correlation APIs preserve their raw input columns in
|
|
110
111
|
`study_results`. Derived effects, variances, correction indicators, and
|
|
111
112
|
weights appear alongside them.
|
|
112
113
|
|
|
@@ -67,10 +67,11 @@ This produces terms such as `region[Asia]` and `region[North America]`, each
|
|
|
67
67
|
relative to `Europe`. The reference never depends on row order. Undeclared
|
|
68
68
|
levels, levels absent after exclusions, and string moderators omitted from
|
|
69
69
|
`categorical=` are errors rather than implicit recoding decisions.
|
|
70
|
-
Categorical matching
|
|
71
|
-
equivalent,
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
Categorical matching keeps booleans distinct from numeric levels. Python and
|
|
71
|
+
NumPy integers are equivalent, and integer-valued floats such as `1.0` match
|
|
72
|
+
the corresponding integer level `1`. This accommodates pandas integer columns
|
|
73
|
+
that become floating point after introducing a missing value. Non-integer
|
|
74
|
+
floats such as `1.5` do not match integer levels.
|
|
74
75
|
|
|
75
76
|
Formula parsing, automatic interactions, splines, and polynomial terms are not
|
|
76
77
|
implemented. Construct those columns explicitly before fitting when they are
|
|
@@ -23,6 +23,7 @@ The high-level APIs intentionally have outcome-specific defaults:
|
|
|
23
23
|
| --- | --- |
|
|
24
24
|
| `meta_analysis()` | random-effects inverse variance, REML |
|
|
25
25
|
| `meta_continuous()` | random-effects inverse variance, REML |
|
|
26
|
+
| `meta_correlation()` | random-effects inverse variance, REML |
|
|
26
27
|
| `meta_binary()` | common-effect Mantel-Haenszel |
|
|
27
28
|
| `meta_regression()` | mixed-effects inverse variance, REML |
|
|
28
29
|
|
|
@@ -40,6 +41,7 @@ protocols.
|
|
|
40
41
|
| Binary RR/RD, common effect | Mantel-Haenszel or inverse variance |
|
|
41
42
|
| Binary OR/RR/RD, random effects | Inverse variance |
|
|
42
43
|
| Continuous MD/SMD, common or random | Inverse variance |
|
|
44
|
+
| Fisher's z correlation, common or random | Inverse variance |
|
|
43
45
|
|
|
44
46
|
Mantel-Haenszel and inverse variance are different estimators, not aliases.
|
|
45
47
|
PyMetaAnalysis does not extrapolate its common-effect Mantel-Haenszel weights
|