Repository navigation
fix(stats): mean_ci and Cohen's d judge zero variance at the data's own scale - #763
Open
antonwolfy wants to merge 2 commits into
Open
antonwolfy wants to merge 2 commits into
antonwolfy wants to merge 2 commits into
Conversation
…wn scale (intel#640) `_is_degenerate` compares the sd with `1e-9 * max(1.0, abs(mean))`, so any sample with sd under 1e-9 counted as constant whatever its scale: `mean_ci([1e-300, 2e-300, 3e-300])` returned `degenerate` with `lo == hi == mean`, and `_cohens_d(2e-300, 1e-300)` returned None. `mean_ci` and `_cohens_d` now divide the mean and sd by a power of two taken from the data (the largest absolute value, and the larger of the mean and the sd) before the check, through one helper `_is_degenerate_at_scale`. The floor of 1.0 keeps its job of absorbing float noise on a constant sample, relative to the data. The returned mean and bounds are unchanged. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
|
✅ OpenCodeReview: Review complete: 0 finding(s) across 4 selected item(s). CI at Review details
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #763 +/- ##
=======================================
Coverage 95.72% 95.72%
=======================================
Files 415 415
Lines 55363 55365 +2
Branches 9516 9516
=======================================
+ Hits 52994 52996 +2
Misses 1466 1466
Partials 903 903
🚀 New features to boost your workflow:
|
_pow2_scale([0.0]) is 0.5, so a sample of zeros has mean 0 and sd 0 after scaling and _is_degenerate already returns True. Removes the branch and its docstring sentence. Signed-off-by: vchamarthi <123653452+vchamarthi@users.noreply.github.com>
Contributor
|
Pushed 1 commit to
The PR description needs these corrections:
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
_is_degeneratecompares the sd with1e-9 * max(1.0, abs(mean)), so a sample whose sd is under 1e-9 counted as constant whatever its scale (#640). Onmain:mainmean_ci([1e-300, 2e-300, 3e-300], ndigits=None)method: degenerate,lo == hi == meanstudent_t,lo < mean < himean_ci([1e-12, 2e-12, 3e-12], ndigits=None)degeneratestudent_t_cohens_d(2e-300, 1e-300)None(unknown)2.0paired_testof deltas1e-300 ... 4e-300cohens_d: Nonecohens_d: 1.936Option taken: scale before the check, as
point_biserialdoes since #601, rather than a relative-only_is_degenerate. The floor of 1.0 keeps its job of absorbing float noise on a constant sample (a constant shift has sd ~ 3e-15), now relative to the data; dropping it would read a mean near 0 with noise-sized spread as varying.The same cause in the sign-flip tie tolerance (
EPS = 1e-9, absolute) is tracked in #762.Closes #640
Changes
dokimi/dokimi/eval/stats.py: new helper_is_degenerate_at_scale(mean, sd, top)divides the mean and sd by the power of two at or belowtop(exact) and calls_is_degenerate;top == 0(a sample of zeros) is degenerate as before.mean_cipasses the largest absolute value,_cohens_d(signature unchanged) passesmax(abs(d_mean), d_sd). The returned mean and bounds are unchanged._is_degenerateandZERO_VARIANCE_REL_TOLare untouched.dokimi/tests/test_stats_tiny_scale.py: tiny-scale intervals at 1e-300 and 1e-12, scale invariance by a power of two, constant and float-noise samples that stay degenerate,_cohens_dandpaired_teston tiny deltas.dokimi/docs/benchmarking-and-comparison.md: says "constant" for d_z is judged at the deltas' own scale.Risk
A sample whose values differ by less than 1e-9 in absolute terms but are not constant at their own scale now gets a Student-t interval (
method: student_t) frommean_ciand a Cohen's d frompaired_testand the other users of_describe_deltas(arms, interactions), where it gotdegenerate/unknown. A sample that is constant at its own scale (exact repeats, or float-noise spread of 1e-9 relative) staysdegenerate. Deltas that are all float noise around 0, such as[5.5e-17, 0.0, 5.5e-17, 0.0, 0.0](0.3 - 0.2 - 0.1), have a mean and sd of the same tiny size, so they now get a d_z (-0.73 for that vector) instead ofunknown; scaling from the deltas instead of the mean and sd gives the same, since noise is the whole scale there. Samples at the scale of 1 or above are decided as before, including the existingbig/smallpair and the constant-shift test.Testing
On Linux, at
65008c5(onmain7137604):make ci-local: 33 passed, 0 failed, 14 skipped (docker external-catalog smoke, Claude Code fidelity install, matrix legs and release jobs that do not apply on a PR, micromamba, semgrep, fuzz, cli-interface package). 20449 tests passed, 19 skipped; changed-line coverage 100%.mainand passes here: 5 of the 8 new tests fail onmain's code, and the 3 that stay degenerate pass on both.mean_ciback to_is_degenerate(mu, sd)fails the two tiny-scale interval tests and the scale-invariance test;_cohens_dback to_is_degenerate(d_mean, d_sd)failstest_cohens_d_of_tiny_deltas_is_a_numberand thepaired_testtest; the helper returningsd == 0(no noise floor) fails the float-noise test and the constant-shift_cohens_dtest; the helper returningFalsefails those two and the constant-tiny-sample test.Revert
A plain revert restores the absolute floor. Nothing is stored.
Checklist
pytestpassesruff,mypy, and schema checks passAGENTS.md.github/.licenserc.yaml)