Sitelet https://github.com/statsmodels/statsmodels/pull/10426
Skip to content

BUG: reject negative dispersion in power_equivalence_neginb_2indep - #10426

Merged
bashtage merged 2 commits into
statsmodels:mainfrom
simpleqt:sq/power-equiv-neginb-dispersion
Oct 4, 2026
Merged

bashtage merged 2 commits into
statsmodels:mainfrom
simpleqt:sq/power-equiv-neginb-dispersion

Conversation

@simpleqt

@simpleqt simpleqt commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

power_equivalence_neginb_2indep multiplies its variance terms by the dispersion coefficient but never checks it, so a negative value silently produces a negative power:

from statsmodels.stats.rates import power_equivalence_neginb_2indep

power_equivalence_neginb_2indep(0.1, 0.15, 100, low=0.1, upp=0.3, dispersion=0.01)
# -> 0.0117...   (fine)

power_equivalence_neginb_2indep(0.1, 0.15, 100, low=0.1, upp=0.3, dispersion=-0.01)
# -> -0.00117    (a negative probability, no error)

The sibling rate-power functions (power_poisson_ratio_2indep, power_negbin_ratio_2indep) already validate dispersion; the equivalence-power companion was missing the same guard.

This PR adds it after the existing nobs1/alpha checks:

if dispersion < 0:
    raise ValueError(f"dispersion must be non-negative, got {dispersion}")

dispersion = 0 deliberately stays valid — the docstring documents it as the Poisson limiting case ("The Poisson limiting case corresponds to dispersion=0").

Regression test: test_power_equivalence_neginb_negative_dispersion_raises covers the raise and the finite-power Poisson limit at dispersion=0.

  • There are no similar open PRs about this issue
  • I have added tests to cover the new behavior
  • No documentation update is needed for this change

AI Disclosure

  • AI tools were used.
    Tool(s): ZCode (GLM-based coding agent).
    Used for: locating the missing validation by probing public API behavior, drafting the guard, regression test, and PR description.
    All code was reviewed and tested by the author before submission, who remains responsible for the change.

A negative dispersion coefficient entered the variance term directly
and silently produced a negative power. Reject negative values;
dispersion=0 stays valid as the documented Poisson limiting case.
Copilot AI balanced review requested due to automatic review settings October 4, 2026 15:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@bashtage
bashtage merged commit 8fcd144 into statsmodels:main Oct 4, 2026
9 of 10 checks passed
@bashtage

bashtage commented Oct 4, 2026

Copy link
Copy Markdown
Member

Thanks.

1 similar comment
@bashtage

bashtage commented Oct 4, 2026

Copy link
Copy Markdown
Member

Thanks.

bashtage added a commit that referenced this pull request Oct 5, 2026
The checks added in GH-10379, GH-10386, GH-10388, GH-10392, GH-10393,
GH-10399, GH-10405, GH-10406, GH-10411, GH-10420, GH-10421, GH-10423,
GH-10425, GH-10426 and GH-10431 compare the arguments with scalars,
for example `if not 0 < alpha < 1`, `if low > upp` or `if dispersion < 0`.
These raise "The truth value of an array with more than one element is
ambiguous" for arrays and Series. The functions broadcast over these
arguments and return the same values as the calls for the elements in
0.15.0, for example a confidence interval for several alpha, the power
for several equivalence margins or a table of sample sizes.

Test with np.all and the comparison ufuncs instead, which work for
scalars, lists, arrays and Series, and which also reject NaN. The
error messages are unchanged. A new test checks for 50 arguments that an
array of two valid values gives the same result as the two calls with the
scalars, and that one invalid element (including NaN) is rejected.

Follow-up to GH-10379, GH-10386, GH-10388, GH-10392, GH-10393, GH-10399,
GH-10405, GH-10406, GH-10411, GH-10420, GH-10421, GH-10423, GH-10425,
GH-10426, GH-10431

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
bashtage added a commit that referenced this pull request Oct 5, 2026
The arguments that broadcast are documented as float or int, but arrays
work, and the previous commit keeps them working. Document them as
float or array_like in the functions of the previous commit and in
chisquare_power, which says in its Notes that it works vectorized.

Follow-up to GH-10379, GH-10386, GH-10388, GH-10392, GH-10393, GH-10399,
GH-10405, GH-10406, GH-10411, GH-10420, GH-10421, GH-10423, GH-10425,
GH-10426, GH-10431

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
bashtage added a commit that referenced this pull request Oct 5, 2026
GH-10422 added the check of a negative dispersion to power_poisson_ratio_2indep
and power_negbin_ratio_2indep, and GH-10426 to power_equivalence_neginb_2indep.
power_equivalence_poisson_2indep has the same argument and had no check, so
dispersion=-1 returned nan.

Follow-up to GH-10422
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants