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.
Files changed (155) hide show
  1. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/CHANGELOG.md +66 -7
  2. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/CITATION.cff +2 -2
  3. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/PKG-INFO +16 -5
  4. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/README.md +15 -4
  5. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/benchmarks/README.md +5 -5
  6. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/benchmarks/benchmark_core.py +8 -0
  7. pymetaanalysis-0.8.0/docs/adr/0007-fisher-z-correlation.md +66 -0
  8. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/citation.md +1 -1
  9. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/getting-started.md +30 -4
  10. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/binary-outcomes.md +21 -0
  11. pymetaanalysis-0.8.0/docs/guides/correlation-outcomes.md +150 -0
  12. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/input-data.md +3 -2
  13. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/meta-regression.md +5 -4
  14. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/method-selection.md +2 -0
  15. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/plotting.md +49 -4
  16. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/r-interoperability.md +77 -5
  17. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/sensitivity-analysis.md +2 -2
  18. pymetaanalysis-0.8.0/docs/guides/small-study-effects.md +257 -0
  19. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/zero-events.md +16 -7
  20. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/index.md +14 -11
  21. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/limitations.md +34 -6
  22. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/methods/statistical-methods.md +137 -0
  23. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/reference/api.md +99 -11
  24. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/reference/report-schema.md +10 -1
  25. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/reference/results.md +83 -5
  26. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/validation.md +34 -8
  27. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/mkdocs.yml +3 -0
  28. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/__init__.py +6 -0
  29. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/_version.py +1 -1
  30. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/binary_api.py +25 -9
  31. pymetaanalysis-0.8.0/src/meta_analyze/correlation_api.py +317 -0
  32. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/design_matrix.py +22 -5
  33. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/effect_sizes/__init__.py +8 -0
  34. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/effect_sizes/binary.py +3 -4
  35. pymetaanalysis-0.8.0/src/meta_analyze/effect_sizes/correlation.py +215 -0
  36. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/mantel_haenszel.py +3 -1
  37. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/peto.py +10 -5
  38. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/heterogeneity.py +8 -1
  39. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/_utils.py +3 -0
  40. pymetaanalysis-0.8.0/src/meta_analyze/plotting/funnel.py +444 -0
  41. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/reporting.py +7 -0
  42. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/results.py +51 -2
  43. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/sensitivity.py +26 -4
  44. pymetaanalysis-0.8.0/src/meta_analyze/small_study_effects.py +961 -0
  45. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/subgroups.py +4 -1
  46. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/README.md +34 -10
  47. pymetaanalysis-0.8.0/tests/reference/correlation_input.csv +9 -0
  48. pymetaanalysis-0.8.0/tests/reference/correlation_metafor.json +27 -0
  49. pymetaanalysis-0.8.0/tests/reference/generate_correlation_metafor.R +59 -0
  50. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_generic_metafor.R +10 -0
  51. pymetaanalysis-0.8.0/tests/reference/generate_harbord_small_study_effects_meta.R +73 -0
  52. pymetaanalysis-0.8.0/tests/reference/generate_peters_small_study_effects_meta.R +71 -0
  53. pymetaanalysis-0.8.0/tests/reference/generate_small_study_effects_metafor.R +56 -0
  54. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_workflow_metafor.R +29 -0
  55. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generic_metafor.json +7 -0
  56. pymetaanalysis-0.8.0/tests/reference/harbord_small_study_effects_meta.json +24 -0
  57. pymetaanalysis-0.8.0/tests/reference/peters_small_study_effects_input.csv +13 -0
  58. pymetaanalysis-0.8.0/tests/reference/peters_small_study_effects_meta.json +25 -0
  59. pymetaanalysis-0.8.0/tests/reference/small_study_effects_input.csv +13 -0
  60. pymetaanalysis-0.8.0/tests/reference/small_study_effects_metafor.json +20 -0
  61. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/workflow_metafor.json +14 -0
  62. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_binary.py +79 -2
  63. pymetaanalysis-0.8.0/tests/test_correlation.py +288 -0
  64. pymetaanalysis-0.8.0/tests/test_funnel_plot.py +499 -0
  65. pymetaanalysis-0.8.0/tests/test_harbord_small_study_effects.py +330 -0
  66. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_meta_regression.py +42 -13
  67. pymetaanalysis-0.8.0/tests/test_peters_small_study_effects.py +301 -0
  68. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_plotting.py +24 -0
  69. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_properties.py +62 -0
  70. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_r_references.py +79 -2
  71. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_release_readiness.py +1 -0
  72. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_sensitivity.py +24 -0
  73. pymetaanalysis-0.8.0/tests/test_small_study_effects.py +264 -0
  74. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_subgroups.py +15 -0
  75. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tools/check_release.py +30 -0
  76. pymetaanalysis-0.6.0/src/meta_analyze/plotting/funnel.py +0 -168
  77. pymetaanalysis-0.6.0/tests/test_funnel_plot.py +0 -198
  78. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/.github/workflows/ci.yml +0 -0
  79. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/.github/workflows/pages.yml +0 -0
  80. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/.github/workflows/release.yml +0 -0
  81. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/.gitignore +0 -0
  82. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/CONTRIBUTING.md +0 -0
  83. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/LICENSE +0 -0
  84. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/SECURITY.md +0 -0
  85. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0001-optional-matplotlib.md +0 -0
  86. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0002-statistical-policy.md +0 -0
  87. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0003-meta-regression-prediction-intervals.md +0 -0
  88. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0004-hartung-knapp-prediction-intervals.md +0 -0
  89. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0005-mantel-haenszel-risk-difference.md +0 -0
  90. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/adr/0006-peto-odds-ratio.md +0 -0
  91. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/development.md +0 -0
  92. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/continuous-outcomes.md +0 -0
  93. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/generic-effects.md +0 -0
  94. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/guides/provenance-reporting.md +0 -0
  95. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/installation.md +0 -0
  96. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/releasing.md +0 -0
  97. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/docs/stylesheets/extra.css +0 -0
  98. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/examples/README.md +0 -0
  99. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/examples/meta_regression.ipynb +0 -0
  100. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/examples/quickstart.ipynb +0 -0
  101. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/pyproject.toml +0 -0
  102. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/api.py +0 -0
  103. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/config.py +0 -0
  104. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/continuous_api.py +0 -0
  105. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/data.py +0 -0
  106. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/effect_sizes/continuous.py +0 -0
  107. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/__init__.py +0 -0
  108. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/inverse_variance.py +0 -0
  109. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/meta_regression.py +0 -0
  110. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/estimators/tau2.py +0 -0
  111. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/exceptions.py +0 -0
  112. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/__init__.py +0 -0
  113. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/forest.py +0 -0
  114. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/regression.py +0 -0
  115. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/plotting/subgroup_forest.py +0 -0
  116. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/provenance.py +0 -0
  117. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/py.typed +0 -0
  118. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_api.py +0 -0
  119. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_collinearity.py +0 -0
  120. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_contrasts.py +0 -0
  121. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_results.py +0 -0
  122. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/src/meta_analyze/regression_sensitivity.py +0 -0
  123. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/binary_input.csv +0 -0
  124. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/binary_metafor.json +0 -0
  125. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/binary_sparse_input.csv +0 -0
  126. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/continuous_input.csv +0 -0
  127. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/continuous_metafor.json +0 -0
  128. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_binary_metafor.R +0 -0
  129. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_continuous_metafor.R +0 -0
  130. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_meta_regression_collinearity_metafor.R +0 -0
  131. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_meta_regression_contrasts_metafor.R +0 -0
  132. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_meta_regression_influence_metafor.R +0 -0
  133. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generate_meta_regression_metafor.R +0 -0
  134. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/generic_input.csv +0 -0
  135. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_boundary_input.csv +0 -0
  136. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_collinearity_metafor.json +0 -0
  137. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_contrasts_metafor.json +0 -0
  138. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_influence_metafor.json +0 -0
  139. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_input.csv +0 -0
  140. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/meta_regression_metafor.json +0 -0
  141. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/reference/workflow_input.csv +0 -0
  142. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_api.py +0 -0
  143. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_continuous.py +0 -0
  144. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_documentation.py +0 -0
  145. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_estimators.py +0 -0
  146. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_numerical_stability.py +0 -0
  147. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_reference_results.py +0 -0
  148. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_collinearity.py +0 -0
  149. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_contrasts.py +0 -0
  150. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_influence.py +0 -0
  151. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_plotting.py +0 -0
  152. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_regression_sensitivity.py +0 -0
  153. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tests/test_reporting.py +0 -0
  154. {pymetaanalysis-0.6.0 → pymetaanalysis-0.8.0}/tools/execute_notebooks.py +0 -0
  155. {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.6.0
12
- date-released: 2026-08-13
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.6.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, not proof of publication bias.
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/), and [continuous](https://zhaoboding.github.io/PyMetaAnalysis/guides/continuous-outcomes/) guides
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, not proof of publication bias.
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/), and [continuous](https://zhaoboding.github.io/PyMetaAnalysis/guides/continuous-outcomes/) guides
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, and
4
- multivariable Meta-regression random-effects fits using deterministic synthetic
5
- data. Correctness remains the primary performance requirement; this benchmark
6
- is intended to reveal large regressions, not to enforce a fragile wall-clock
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
- PyMetaAnalysis contributors. PyMetaAnalysis (version <version>):
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, so their audit-friendly numeric attributes remain logarithmic.
124
- Use display properties for ratios:
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 continuous APIs.
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 continuous APIs preserve their raw input columns in
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 preserves scalar kinds: Python and NumPy integers are
71
- equivalent, for example, but booleans do not match integer levels and
72
- floating-point values do not match integer levels. Declare levels using the
73
- same scalar kind as the observed moderator values.
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