Skip to content

Commit

Permalink
Merge pull request scipy#12756 from WarrenWeckesser/levy-sf
Browse files Browse the repository at this point in the history
 ENH: stats: Add an sf method to levy for improved precision in the tail.
  • Loading branch information
ev-br authored Aug 23, 2020
2 parents 0be1429 + 1dc184e commit da02c95
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 16 deletions.
3 changes: 3 additions & 0 deletions scipy/stats/_continuous_distns.py
Original file line number Diff line number Diff line change
Expand Up @@ -4067,6 +4067,9 @@ def _cdf(self, x):
# Equivalent to 2*norm.sf(np.sqrt(1/x))
return sc.erfc(np.sqrt(0.5 / x))

def _sf(self, x):
return sc.erf(np.sqrt(0.5 / x))

def _ppf(self, q):
# Equivalent to 1.0/(norm.isf(q/2)**2) or 0.5/(erfcinv(q)**2)
val = -sc.ndtri(q/2)
Expand Down
45 changes: 29 additions & 16 deletions scipy/stats/tests/test_distributions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1797,13 +1797,6 @@ def test_cdf_ppf_next(self):
assert_array_equal(rv.ppf(rv.cdf(rv.xk[:-1]) + 1e-8),
rv.xk[1:])

def test_expect(self):
xk = [1, 2, 4, 6, 7, 11]
pk = [0.1, 0.2, 0.2, 0.2, 0.2, 0.1]
rv = stats.rv_discrete(values=(xk, pk))

assert_allclose(rv.expect(), np.sum(rv.xk * rv.pk), atol=1e-14)

def test_multidimension(self):
xk = np.arange(12).reshape((3, 4))
pk = np.array([[0.1, 0.1, 0.15, 0.05],
Expand Down Expand Up @@ -1843,8 +1836,15 @@ def test_shape_rv_sample(self):
# same shapes => no error
xk, pk = np.arange(6).reshape((3, 2)), np.full((3, 2), 1/6)
assert_equal(stats.rv_discrete(values=(xk, pk)).pmf(0), 1/6)

def test_expect(self):

def test_expect1(self):
xk = [1, 2, 4, 6, 7, 11]
pk = [0.1, 0.2, 0.2, 0.2, 0.2, 0.1]
rv = stats.rv_discrete(values=(xk, pk))

assert_allclose(rv.expect(), np.sum(rv.xk * rv.pk), atol=1e-14)

def test_expect2(self):
# rv_sample should override _expect. Bug report from
# https://stackoverflow.com/questions/63199792
y = [200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0,
Expand All @@ -1857,13 +1857,14 @@ def test_expect(self):
py = [0.0004, 0.0, 0.0033, 0.006500000000000001, 0.0, 0.0,
0.004399999999999999, 0.6862, 0.0, 0.0, 0.0,
0.00019999999999997797, 0.0006000000000000449,
0.024499999999999966, 0.006400000000000072, 0.0043999999999999595,
0.019499999999999962, 0.03770000000000007, 0.01759999999999995,
0.015199999999999991, 0.018100000000000005, 0.04500000000000004,
0.0025999999999999357, 0.0, 0.0041000000000001036,
0.005999999999999894, 0.0042000000000000925,
0.0050000000000000044, 0.0041999999999999815,
0.0004999999999999449, 0.009199999999999986, 0.008200000000000096,
0.024499999999999966, 0.006400000000000072,
0.0043999999999999595, 0.019499999999999962,
0.03770000000000007, 0.01759999999999995, 0.015199999999999991,
0.018100000000000005, 0.04500000000000004, 0.0025999999999999357,
0.0, 0.0041000000000001036, 0.005999999999999894,
0.0042000000000000925, 0.0050000000000000044,
0.0041999999999999815, 0.0004999999999999449,
0.009199999999999986, 0.008200000000000096,
0.0, 0.0, 0.0046999999999999265, 0.0019000000000000128,
0.0006000000000000449, 0.02510000000000001, 0.0,
0.007199999999999984, 0.0, 0.012699999999999934, 0.0, 0.0,
Expand Down Expand Up @@ -3935,6 +3936,18 @@ def test_levy_cdf_ppf():
assert_allclose(xx, x, rtol=1e-13)


def test_levy_sf():
# Large values, far into the tail of the distribution.
x = np.array([1e15, 1e25, 1e35, 1e50])
# Expected values were calculated with mpmath.
expected = np.array([2.5231325220201597e-08,
2.52313252202016e-13,
2.52313252202016e-18,
7.978845608028653e-26])
y = stats.levy.sf(x)
assert_allclose(y, expected, rtol=1e-14)


def test_hypergeom_interval_1802():
# these two had endless loops
assert_equal(stats.hypergeom.interval(.95, 187601, 43192, 757),
Expand Down

0 comments on commit da02c95

Please sign in to comment.