From 4869e1ceda281c72fa526c1584a81e8519c9a499 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Mar 2026 00:08:44 +0000 Subject: [PATCH 1/2] Fix Wilcoxon tie correction: remove incorrect rank multiplication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tieCorrection function incorrectly multiplied the correction term by the rank value (i) when tie group size j > 2. The standard formula for the Wilcoxon tie correction is sum((t^3 - t) / 48) where t is the count of tied observations — the rank plays no role. This bug only affected datasets where at least one tie group had 3 or more equal values; pairs (j=2) were handled correctly by a special case. Closes #347 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/FSharp.Stats/Testing/Wilcoxon.fs | 6 ++---- tests/FSharp.Stats.Tests/Testing.fs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/FSharp.Stats/Testing/Wilcoxon.fs b/src/FSharp.Stats/Testing/Wilcoxon.fs index aafe6f1f2..2432d686e 100644 --- a/src/FSharp.Stats/Testing/Wilcoxon.fs +++ b/src/FSharp.Stats/Testing/Wilcoxon.fs @@ -44,10 +44,8 @@ module WilcoxonTest = |> Array.filter (fun (i,j)-> j>1) |> Array.map (fun (i,j) -> float i,float j) - let tieCorrection (i,j) = - if j = 2.0 then - (j**3. - j) / 48. - else i * ((j**3. - j) / 48.) + let tieCorrection (_,j) = + (j**3. - j) / 48. let tieStatistic = ties diff --git a/tests/FSharp.Stats.Tests/Testing.fs b/tests/FSharp.Stats.Tests/Testing.fs index cf867dd50..1adfd493a 100644 --- a/tests/FSharp.Stats.Tests/Testing.fs +++ b/tests/FSharp.Stats.Tests/Testing.fs @@ -164,6 +164,11 @@ let wilcoxonTestTests = let wilcoxon2 = WilcoxonTest.createWilcoxonTest before after false let wilcoxon3 = WilcoxonTest.createWilcoxonTestFromDifferences differences true let wilcoxon4 = WilcoxonTest.createWilcoxonTestFromDifferences differences false + // ties of size 3 (exposes the rank-multiplication bug): differences [1,1,1,2,-3] + // expected values computed with SciPy: wilcoxon([1,1,1,2,-3], mode='approx', correction=False/True) + let tieDiffs3 = seq{1.;1.;1.;2.;-3.} + let wilcoxon5 = WilcoxonTest.createWilcoxonTestFromDifferences tieDiffs3 false + let wilcoxon6 = WilcoxonTest.createWilcoxonTestFromDifferences tieDiffs3 true testList "Testing.WilcoxonTest" [ testCase "wilcoxonWithCorrection" <| fun () -> @@ -177,7 +182,13 @@ let wilcoxonTestTests = testCase "wilcoxonOneSidedWithCorrection" <| fun () -> Expect.floatClose Accuracy.low wilcoxon1.PValueLeft 0.019102 "pValue should be equal" testCase "wilcoxonOneSidedWithoutCorrection" <| fun () -> - Expect.floatClose Accuracy.low wilcoxon2.PValueRight 0.9823 "pValue should be equal" + Expect.floatClose Accuracy.low wilcoxon2.PValueRight 0.9823 "pValue should be equal" + testCase "wilcoxonTieSize3WithoutCorrection" <| fun () -> + // SciPy: wilcoxon([1,1,1,2,-3], mode='approx', correction=False) => pvalue ≈ 0.492207 + Expect.floatClose Accuracy.low wilcoxon5.PValueTwoTailed 0.4922 "pValue should match SciPy with ties of size 3" + testCase "wilcoxonTieSize3WithCorrection" <| fun () -> + // SciPy: wilcoxon([1,1,1,2,-3], mode='approx', correction=True) => pvalue ≈ 0.582702 + Expect.floatClose Accuracy.low wilcoxon6.PValueTwoTailed 0.5827 "pValue should match SciPy with ties of size 3 and correction" ] From dd09f55fe9036a8515ebd550ca949071bd8ab992 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Mar 2026 00:12:11 +0000 Subject: [PATCH 2/2] ci: trigger checks