PyMetaAnalysis 0.6.0__tar.gz → 0.7.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.7.0}/CHANGELOG.md +46 -7
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/CITATION.cff +2 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/PKG-INFO +5 -3
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/README.md +4 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/benchmarks/README.md +5 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/benchmarks/benchmark_core.py +8 -0
- pymetaanalysis-0.7.0/docs/adr/0007-fisher-z-correlation.md +66 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/citation.md +1 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/getting-started.md +5 -3
- pymetaanalysis-0.7.0/docs/guides/correlation-outcomes.md +150 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/input-data.md +3 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/meta-regression.md +5 -4
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/method-selection.md +2 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/plotting.md +3 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/r-interoperability.md +11 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/sensitivity-analysis.md +2 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/zero-events.md +16 -7
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/index.md +11 -9
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/limitations.md +13 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/methods/statistical-methods.md +28 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/reference/api.md +56 -8
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/reference/report-schema.md +10 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/reference/results.md +11 -4
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/validation.md +6 -2
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/mkdocs.yml +2 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/__init__.py +2 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/_version.py +1 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/binary_api.py +25 -9
- pymetaanalysis-0.7.0/src/meta_analyze/correlation_api.py +317 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/design_matrix.py +22 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/effect_sizes/__init__.py +8 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/effect_sizes/binary.py +3 -4
- pymetaanalysis-0.7.0/src/meta_analyze/effect_sizes/correlation.py +215 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/estimators/mantel_haenszel.py +3 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/estimators/peto.py +10 -5
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/heterogeneity.py +8 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/plotting/_utils.py +3 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/reporting.py +7 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/results.py +2 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/sensitivity.py +26 -4
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/subgroups.py +4 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/README.md +12 -1
- pymetaanalysis-0.7.0/tests/reference/correlation_input.csv +9 -0
- pymetaanalysis-0.7.0/tests/reference/correlation_metafor.json +27 -0
- pymetaanalysis-0.7.0/tests/reference/generate_correlation_metafor.R +59 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generate_generic_metafor.R +10 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generate_workflow_metafor.R +29 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generic_metafor.json +7 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/workflow_metafor.json +14 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_binary.py +79 -2
- pymetaanalysis-0.7.0/tests/test_correlation.py +288 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_funnel_plot.py +20 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_meta_regression.py +42 -13
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_plotting.py +24 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_properties.py +62 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_r_references.py +55 -1
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_release_readiness.py +1 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_sensitivity.py +24 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_subgroups.py +15 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/.github/workflows/ci.yml +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/.github/workflows/pages.yml +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/.github/workflows/release.yml +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/.gitignore +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/CONTRIBUTING.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/LICENSE +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/SECURITY.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/adr/0001-optional-matplotlib.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/adr/0002-statistical-policy.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/adr/0003-meta-regression-prediction-intervals.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/adr/0004-hartung-knapp-prediction-intervals.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/adr/0005-mantel-haenszel-risk-difference.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/adr/0006-peto-odds-ratio.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/development.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/binary-outcomes.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/continuous-outcomes.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/generic-effects.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/guides/provenance-reporting.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/installation.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/releasing.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/docs/stylesheets/extra.css +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/examples/README.md +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/examples/meta_regression.ipynb +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/examples/quickstart.ipynb +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/pyproject.toml +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/api.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/config.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/continuous_api.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/data.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/effect_sizes/continuous.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/estimators/__init__.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/estimators/inverse_variance.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/estimators/meta_regression.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/estimators/tau2.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/exceptions.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/plotting/__init__.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/plotting/forest.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/plotting/funnel.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/plotting/regression.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/plotting/subgroup_forest.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/provenance.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/py.typed +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/regression_api.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/regression_collinearity.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/regression_contrasts.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/regression_results.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/src/meta_analyze/regression_sensitivity.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/binary_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/binary_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/binary_sparse_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/continuous_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/continuous_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generate_binary_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generate_continuous_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generate_meta_regression_collinearity_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generate_meta_regression_contrasts_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generate_meta_regression_influence_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generate_meta_regression_metafor.R +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/generic_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/meta_regression_boundary_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/meta_regression_collinearity_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/meta_regression_contrasts_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/meta_regression_influence_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/meta_regression_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/meta_regression_metafor.json +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/reference/workflow_input.csv +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_api.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_continuous.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_documentation.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_estimators.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_numerical_stability.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_reference_results.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_regression_collinearity.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_regression_contrasts.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_regression_influence.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_regression_plotting.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_regression_sensitivity.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tests/test_reporting.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tools/check_release.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tools/execute_notebooks.py +0 -0
- {pymetaanalysis-0.6.0 → pymetaanalysis-0.7.0}/tools/inspect_distribution.py +0 -0
|
@@ -6,6 +6,37 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 0.7.0 - 2026-09-02
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `meta_correlation()` for independent study-level correlations using Fisher's
|
|
14
|
+
r-to-z transformation (`ZCOR`), `1 / (n - 3)` sampling variances, common- or
|
|
15
|
+
REML/PM/DL random-effects inverse-variance pooling, back-transformed result
|
|
16
|
+
displays, subgroup and sensitivity workflows, plotting, provenance, reports,
|
|
17
|
+
and independent R `metafor` references.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- integer-valued floating-point categorical moderators now match declared
|
|
22
|
+
integer levels while booleans remain distinct, supporting pandas columns
|
|
23
|
+
promoted to floating point by missing values;
|
|
24
|
+
- MH pooling corrections now use `None` as the context-sensitive scope default;
|
|
25
|
+
explicitly supplying either MH-only option to IV or Peto pooling raises an
|
|
26
|
+
error, and non-MH method metadata no longer records unused MH settings;
|
|
27
|
+
- estimator documentation now makes the pooled-mean-only Q-profile contract,
|
|
28
|
+
the prefiltered `fit_peto()` input contract, and sparse MH RD boundary policy
|
|
29
|
+
explicit;
|
|
30
|
+
- fixed-version `metafor` references now cover a two-study Hartung-Knapp
|
|
31
|
+
interval and Q-profile intervals reached through random-effects subgroups.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- normal-inference subgroup tests reuse each fitted standard error directly,
|
|
36
|
+
avoiding an unnecessary recomputation and last-bit numerical drift.
|
|
37
|
+
- Peto observed-minus-expected arithmetic now uses a treatment/control-symmetric
|
|
38
|
+
formulation, preventing avoidable last-bit drift for highly imbalanced arms.
|
|
39
|
+
|
|
9
40
|
## 0.6.0 - 2026-08-13
|
|
10
41
|
|
|
11
42
|
### Added
|
|
@@ -43,6 +74,21 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
43
74
|
Mantel-Haenszel pooling correction; iterative failure paths have direct
|
|
44
75
|
regression tests.
|
|
45
76
|
|
|
77
|
+
### Breaking changes
|
|
78
|
+
|
|
79
|
+
- explicitly supplying `tau2_method` to a common-effect model, including the
|
|
80
|
+
former default spelling `"REML"`, now raises an error instead of being
|
|
81
|
+
ignored; explicitly inapplicable SMD variance settings follow the same rule;
|
|
82
|
+
- cumulative analysis now rejects a string `order` selector when the name is
|
|
83
|
+
present in both source data and the calculated study table, instead of
|
|
84
|
+
silently preferring the source-data column;
|
|
85
|
+
- `LeaveOneOutResult.results` now preserves failed refits as `None`, and its
|
|
86
|
+
table adds `refit_success`, `error_type`, and `error_message` columns;
|
|
87
|
+
- pooled-result `prediction_interval_method` metadata now uses `null` when an
|
|
88
|
+
interval is unavailable and `"HK-PR"` for Hartung-Knapp intervals. Report
|
|
89
|
+
schema 1.2 remains unchanged because the field itself was already present;
|
|
90
|
+
consumers must handle the documented value set.
|
|
91
|
+
|
|
46
92
|
### Fixed
|
|
47
93
|
|
|
48
94
|
- inverse-variance means, heterogeneity statistics, and pooling and
|
|
@@ -71,9 +117,6 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
71
117
|
analysis;
|
|
72
118
|
- tagged releases now rerun the full branch-coverage test suite before
|
|
73
119
|
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
120
|
- duplicate study labels now add a row-position warning while preserving
|
|
78
121
|
`row_id` as the unique audit key;
|
|
79
122
|
- report JSON now serializes `pd.NaT` study labels as `null` rather than the
|
|
@@ -81,8 +124,6 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
81
124
|
- Meta-regression with `missing="drop"` now determines complete-row exclusions
|
|
82
125
|
before validating moderator values, so invalid values in already excluded
|
|
83
126
|
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
127
|
- empty inputs now report that at least one study row is required, and binary
|
|
87
128
|
zero-cell errors identify when `correction_scope="none"` disables an
|
|
88
129
|
otherwise positive correction.
|
|
@@ -94,8 +135,6 @@ Changes planned for the next release accumulate under `Unreleased`.
|
|
|
94
135
|
errors;
|
|
95
136
|
- the Mantel-Haenszel estimator now rejects empty and zero-total strata before
|
|
96
137
|
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
138
|
- categorical moderator encoding no longer conflates booleans, integers, and
|
|
100
139
|
floating-point values through Python's cross-type numeric equality;
|
|
101
140
|
- 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.7.0
|
|
12
|
+
date-released: 2026-09-02
|
|
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.7.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
|
|
@@ -235,7 +237,7 @@ The complete documentation is published at
|
|
|
235
237
|
- [Installation](https://zhaoboding.github.io/PyMetaAnalysis/installation/)
|
|
236
238
|
- [Getting started](https://zhaoboding.github.io/PyMetaAnalysis/getting-started/)
|
|
237
239
|
- [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/),
|
|
240
|
+
- [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
241
|
- [Meta-regression](https://zhaoboding.github.io/PyMetaAnalysis/guides/meta-regression/)
|
|
240
242
|
- [Choosing methods](https://zhaoboding.github.io/PyMetaAnalysis/guides/method-selection/) and [statistical formulas](https://zhaoboding.github.io/PyMetaAnalysis/methods/statistical-methods/)
|
|
241
243
|
- [Sensitivity analysis](https://zhaoboding.github.io/PyMetaAnalysis/guides/sensitivity-analysis/) and [plotting](https://zhaoboding.github.io/PyMetaAnalysis/guides/plotting/)
|
|
@@ -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
|
|
@@ -185,7 +187,7 @@ The complete documentation is published at
|
|
|
185
187
|
- [Installation](https://zhaoboding.github.io/PyMetaAnalysis/installation/)
|
|
186
188
|
- [Getting started](https://zhaoboding.github.io/PyMetaAnalysis/getting-started/)
|
|
187
189
|
- [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/),
|
|
190
|
+
- [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
191
|
- [Meta-regression](https://zhaoboding.github.io/PyMetaAnalysis/guides/meta-regression/)
|
|
190
192
|
- [Choosing methods](https://zhaoboding.github.io/PyMetaAnalysis/guides/method-selection/) and [statistical formulas](https://zhaoboding.github.io/PyMetaAnalysis/methods/statistical-methods/)
|
|
191
193
|
- [Sensitivity analysis](https://zhaoboding.github.io/PyMetaAnalysis/guides/sensitivity-analysis/) and [plotting](https://zhaoboding.github.io/PyMetaAnalysis/guides/plotting/)
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -50,7 +50,9 @@ fig.tight_layout()
|
|
|
50
50
|
| `log_scale` | Override the default logarithmic ratio axis |
|
|
51
51
|
|
|
52
52
|
OR and RR are modeled on a log scale but displayed as ratios on a logarithmic
|
|
53
|
-
axis by default.
|
|
53
|
+
axis by default. `ZCOR` is modeled on Fisher's z scale, back-transformed to
|
|
54
|
+
correlations, and displayed on a linear axis. Other measures use an identity
|
|
55
|
+
display scale and linear axis.
|
|
54
56
|
When overriding `log_scale=True`, all displayed effects and the null value must
|
|
55
57
|
be strictly positive.
|
|
56
58
|
|
|
@@ -18,6 +18,7 @@ fixtures used by this project.
|
|
|
18
18
|
| Binary 2x2 tables, Mantel-Haenszel | `meta_binary(..., method="MH")` | `rma.mh()` | `metabin(..., method="MH")` |
|
|
19
19
|
| Binary 2x2 tables, Peto OR | `meta_binary(..., measure="OR", method="Peto")` | `rma.peto()` | `metabin(..., sm="OR", method="Peto")` |
|
|
20
20
|
| Continuous group summaries | `meta_continuous()` | `escalc()` then `rma.uni()` | `metacont()` |
|
|
21
|
+
| Correlations and sample sizes | `meta_correlation()` | `escalc(measure="ZCOR")` then `rma.uni()` | `metacor(sm="ZCOR")` |
|
|
21
22
|
| Subgroups | `subgroup=` on a high-level call | separate fits or a moderator model | `subgroup=` |
|
|
22
23
|
| Leave-one-out | `result.leave_one_out()` | `leave1out()` for supported fits | `metainf()` |
|
|
23
24
|
| Meta-regression influence | `regression.influence()` | `influence()`, `rstudent()`, `cooks.distance()`, `dfbetas()` | — |
|
|
@@ -42,6 +43,7 @@ provenance behavior consistent.
|
|
|
42
43
|
| Control total | `n_control` | `n2i` | `n.c` |
|
|
43
44
|
| Treatment mean/SD | `mean_treat`, `sd_treat` | `m1i`, `sd1i` | `mean.e`, `sd.e` |
|
|
44
45
|
| Control mean/SD | `mean_control`, `sd_control` | `m2i`, `sd2i` | `mean.c`, `sd.c` |
|
|
46
|
+
| Correlation/sample size | `correlation`, `n` | `ri`, `ni` | `cor`, `n` |
|
|
45
47
|
|
|
46
48
|
PyMetaAnalysis accepts DataFrame column names or aligned one-dimensional
|
|
47
49
|
array-like values. When `study=` is omitted for a DataFrame, its index supplies
|
|
@@ -56,11 +58,14 @@ the display labels.
|
|
|
56
58
|
| `"RD"` | Risk difference | `"RD"` | `"RD"` | identity |
|
|
57
59
|
| `"MD"` | Mean difference | `"MD"` | `"MD"` | identity |
|
|
58
60
|
| `"SMD"` | Exact-corrected Hedges' g | `"SMD"` with the documented correction | `"SMD"` with exact Hedges correction | identity |
|
|
61
|
+
| `"ZCOR"` | Fisher's z-transformed correlation | `"ZCOR"` | `"ZCOR"` | Fisher's z |
|
|
59
62
|
|
|
60
|
-
For OR and RR, `estimate` and `ci` remain on the log model scale
|
|
61
|
-
`display_estimate` and `display_ci` provide exponentiated ratios.
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
For OR and RR, `estimate` and `ci` remain on the log model scale;
|
|
64
|
+
`display_estimate` and `display_ci` provide exponentiated ratios. For `ZCOR`,
|
|
65
|
+
the model attributes remain Fisher's z values and the display attributes apply
|
|
66
|
+
`tanh` to return correlations. This is similar to choosing transformed or
|
|
67
|
+
untransformed printing in R, but both scales remain explicit attributes in
|
|
68
|
+
Python.
|
|
64
69
|
|
|
65
70
|
## Models, pooling, and heterogeneity
|
|
66
71
|
|
|
@@ -68,7 +73,7 @@ remain explicit attributes in Python.
|
|
|
68
73
|
| --- | --- | --- | --- |
|
|
69
74
|
| `model="common"` | `rma.uni(..., method="EE")` | `common=TRUE, random=FALSE` | Inverse-variance common-effect fit |
|
|
70
75
|
| `model="random"` | random-effects `rma.uni()` | `random=TRUE` | Requires a tau-squared policy |
|
|
71
|
-
| `method="IV"` | inverse-variance weighting | `method="Inverse"` | Binary API only; generic and
|
|
76
|
+
| `method="IV"` | inverse-variance weighting | `method="Inverse"` | Binary API only; generic, continuous, and correlation fits are IV |
|
|
72
77
|
| `method="MH"` | `rma.mh()` | `method="MH"` | Common-effect OR/RR/RD |
|
|
73
78
|
| `method="Peto"` | `rma.peto()` | `method="Peto"` | Common-effect OR; raw pooling tables and O-minus-E heterogeneity |
|
|
74
79
|
| `tau2_method=None` (resolved as `"REML"`) | `method="REML"` | `method.tau="REML"` | PyMetaAnalysis random-effects default |
|
|
@@ -217,3 +222,4 @@ as numerically equivalent.
|
|
|
217
222
|
- [`meta::metagen`](https://search.r-project.org/CRAN/refmans/meta/html/metagen.html)
|
|
218
223
|
- [`meta::metabin`](https://search.r-project.org/CRAN/refmans/meta/html/metabin.html)
|
|
219
224
|
- [`meta::metacont`](https://search.r-project.org/CRAN/refmans/meta/html/metacont.html)
|
|
225
|
+
- [`meta::metacor`](https://search.r-project.org/CRAN/refmans/meta/html/metacor.html)
|
|
@@ -164,8 +164,8 @@ Every refit reuses the original result's:
|
|
|
164
164
|
- tau-squared and confidence-interval methods;
|
|
165
165
|
- confidence level, absolute tolerance, and iteration limit;
|
|
166
166
|
- missing-data policy;
|
|
167
|
-
- binary continuity corrections and RD zero-variance policy,
|
|
168
|
-
effect-size convention.
|
|
167
|
+
- binary continuity corrections and RD zero-variance policy, the continuous
|
|
168
|
+
effect-size convention, or the Fisher's z correlation convention.
|
|
169
169
|
|
|
170
170
|
Meta-regression refits additionally reuse the intercept choice, inference
|
|
171
171
|
method, moderator order, and complete explicit categorical level definitions.
|
|
@@ -76,20 +76,25 @@ default:
|
|
|
76
76
|
|
|
77
77
|
```python
|
|
78
78
|
mh_continuity_correction = None
|
|
79
|
-
mh_correction_scope = "only_zero_studies"
|
|
79
|
+
mh_correction_scope = None # resolves to "only_zero_studies" for MH
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
`continuity_correction` still controls the study-level effects used for display
|
|
83
83
|
and heterogeneity. It does not silently alter the pooled Mantel-Haenszel
|
|
84
84
|
estimator. If an exact pooled estimator is undefined, choose an explicit
|
|
85
85
|
positive `mh_continuity_correction` and report that decision.
|
|
86
|
+
Both MH-specific options are rejected when explicitly supplied to IV or Peto
|
|
87
|
+
pooling, where they would otherwise have no effect.
|
|
86
88
|
|
|
87
89
|
For MH RD, `rd_zero_variance="exclude"` removes zero-variance boundary rows
|
|
88
90
|
before every synthesis calculation. With the default `"correct"` policy, the
|
|
89
91
|
raw table still enters the MH point estimate unless an explicit
|
|
90
92
|
`mh_continuity_correction` is supplied. If the Sato-Greenland-Robins variance
|
|
91
93
|
is non-positive, the uncorrected fit raises instead of silently changing the
|
|
92
|
-
tables; a positive MH correction is an explicit protocol choice.
|
|
94
|
+
tables; a positive MH correction is an explicit protocol choice. Some other
|
|
95
|
+
implementations, including `metafor`, can report a degenerate zero or near-zero
|
|
96
|
+
standard error for such boundary data. PyMetaAnalysis rejects that result by
|
|
97
|
+
the policy recorded in ADR 0005.
|
|
93
98
|
|
|
94
99
|
## Peto pooling always uses raw tables
|
|
95
100
|
|
|
@@ -103,6 +108,10 @@ pooling-correction option.
|
|
|
103
108
|
Double-zero and double-all studies have zero Peto information and are excluded
|
|
104
109
|
before pooling, Q, I-squared, H-squared, and weights. The result retains the
|
|
105
110
|
same structured exclusion reasons used for other relative-effect analyses.
|
|
111
|
+
This means `fit_peto()` expects already-filtered tables. It also differs from
|
|
112
|
+
the pooling side of `metafor::rma.peto()` under its default `drop00` handling,
|
|
113
|
+
which can retain zero-information rows when calculating `k` and Q degrees of
|
|
114
|
+
freedom even though those rows contribute no Peto information.
|
|
106
115
|
Peto's lack of a single-zero pooling correction does not make it universally
|
|
107
116
|
preferable: its rare-outcome, balanced-arm, and modest-effect assumptions must
|
|
108
117
|
still be considered.
|
|
@@ -123,10 +132,10 @@ columns = [
|
|
|
123
132
|
result.study_results[columns]
|
|
124
133
|
```
|
|
125
134
|
|
|
126
|
-
|
|
127
|
-
`dict(result.method.options)`.
|
|
128
|
-
zero-variance policy and affected
|
|
129
|
-
|
|
130
|
-
fitting.
|
|
135
|
+
Applicable resolved correction values and scopes also appear in
|
|
136
|
+
`dict(result.method.options)`. MH-specific keys are present only for MH fits.
|
|
137
|
+
RD analyses additionally record the resolved zero-variance policy and affected
|
|
138
|
+
row IDs in provenance. This makes it possible to distinguish a corrected
|
|
139
|
+
analysis from an exact or exclusion-based one after fitting.
|
|
131
140
|
Peto analyses additionally record `peto_pooling_tables="raw"` and
|
|
132
141
|
`peto_heterogeneity="O-minus-E"`.
|