Repository: scipy/scipy
File: scipy/stats/tests/test_morestats.py (Python)

Code before:
        g1_ = _perturb(g1)
        g2_ = _perturb(g2)
        g3_ = _perturb(g3)
        # Test that center='trimmed' gives the same result as center='mean'
        # when proportiontocut=0.
        Xsq1, pval1 = stats.fligner(g1_, g2_, g3_, center='mean')
        Xsq2, pval2 = stats.fligner(g1_, g2_, g3_, center='trimmed',
                                    proportiontocut=0.0)
        assert_almost_equal(Xsq1, Xsq2)
        assert_almost_equal(pval1, pval2)

    # The following test looks reasonable at first, but fligner() uses the
    # function stats.rankdata(), and in one of the cases in this test,
    # there are ties, while in the other (because of normal rounding
    # errors) there are not.  This difference leads to differences in the
    # third significant digit of W.
    #
    #def test_equal_mean_median(self):
    #    x = np.linspace(-1,1,21)
    #    y = x**3
    #    W1, pval1 = stats.fligner(x, y, center='mean')
    #    W2, pval2 = stats.fligner(x, y, center='median')
    #    assert_almost_equal(W1, W2)
    #    assert_almost_equal(pval1, pval2)

    def test_bad_keyword(self):
        x = np.linspace(-1, 1, 21)
        assert_raises(TypeError, stats.fligner, x, x, portiontocut=0.1)

    def test_bad_center_value(self):
        x = np.linspace(-1, 1, 21)
        assert_raises(ValueError, stats.fligner, x, x, center='trim')

    def test_bad_num_args(self):
        # Too few args raises ValueError.
        assert_raises(ValueError, stats.fligner, [1])

    def test_empty_arg(self):
        x = np.arange(5)
        with pytest.warns(SmallSampleWarning, match=too_small_1d_not_omit):
            res = stats.fligner(x, x**2, [])
            assert_equal(res.statistic, np.nan)
            assert_equal(res.pvalue, np.nan)


def mood_cases_with_ties():
    # Generate random `x` and `y` arrays with ties both between and within the
    # samples. Expected results are (statistic, pvalue) from SAS.
    expected_results = [(-1.76658511464992, .0386488678399305),
                        (-.694031428192304, .2438312498647250),
                        (-1.15093525352151, .1248794365836150)]

Review comment (bug):
If I reverse your patch to `flinger()` we have no tests that fail as a result. Typically we'd want some kind of regression guard, perhaps a regression test clearly labelled that it is just guarding against regression and not getting its expected result from a "gold standard?"

The test below the fold seems to accomplish that, failing in the absence of your patch to `flinger()`.

<details>

```diff
--- a/scipy/stats/tests/test_morestats.py
+++ b/scipy/stats/tests/test_morestats.py
@@ -1123,6 +1123,17 @@ class TestFligner:
         assert_almost_equal(Xsq1, Xsq2)
         assert_almost_equal(pval1, pval2)
 
+    def test_trimmed2(self):
+        x = [1.2, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 100.0]
+        y = [0.0, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 200.0]
+        # Use center='trimmed'
+        Xsq1, pval1 = stats.fligner(x, y, center='trimmed',
+                                    proportiontocut=0.125)
+        expected_X = 0.3903540022781948
+        expected_p = 0.5321133818269028
+        assert_allclose(Xsq1, expected_X)
+        assert_allclose(pval1, expected_p)
```

</details>

Does that make sense?

Of course, there is no substitute for domain expert review and/or gold standards/references, but if you have a good reason for making the change we'd typically want to make sure it doesn't break again.

Code after:
        g1_ = _perturb(g1)
        g2_ = _perturb(g2)
        g3_ = _perturb(g3)
        # Test that center='trimmed' gives the same result as center='mean'
        # when proportiontocut=0.
        Xsq1, pval1 = stats.fligner(g1_, g2_, g3_, center='mean')
        Xsq2, pval2 = stats.fligner(g1_, g2_, g3_, center='trimmed',
                                    proportiontocut=0.0)
        assert_almost_equal(Xsq1, Xsq2)
        assert_almost_equal(pval1, pval2)

    def test_trimmed_nonregression(self):
        # This is a non-regression test
        # Expected results are *not* from an external gold standard,
        # we're just making sure the results remain consistent
        # in the future in case of changes
        args = [g1, g2, g3, g4, g5, g6, g7, g8, g9, g10]
        W, pval = stats.fligner(*args, center="trimmed", proportiontocut=0.25)
        assert_allclose(W, 15.953569890010614, rtol=5e-14)
        assert_allclose(pval, 0.06785752327432863, rtol=5e-14)

    # The following test looks reasonable at first, but fligner() uses the
    # function stats.rankdata(), and in one of the cases in this test,
    # there are ties, while in the other (because of normal rounding
    # errors) there are not.  This difference leads to differences in the
    # third significant digit of W.
    #
    #def test_equal_mean_median(self):
    #    x = np.linspace(-1,1,21)
    #    y = x**3
    #    W1, pval1 = stats.fligner(x, y, center='mean')
    #    W2, pval2 = stats.fligner(x, y, center='median')
    #    assert_almost_equal(W1, W2)
    #    assert_almost_equal(pval1, pval2)

    def test_bad_keyword(self):
        x = np.linspace(-1, 1, 21)
        assert_raises(TypeError, stats.fligner, x, x, portiontocut=0.1)

    def test_bad_center_value(self):
        x = np.linspace(-1, 1, 21)
        assert_raises(ValueError, stats.fligner, x, x, center='trim')

    def test_bad_num_args(self):
        # Too few args raises ValueError.
        assert_raises(ValueError, stats.fligner, [1])

    def test_empty_arg(self):
        x = np.arange(5)
        with pytest.warns(SmallSampleWarning, match=too_small_1d_not_omit):
            res = stats.fligner(x, x**2, [])