test_discrete_distns.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. import pytest
  2. from scipy.stats import (betabinom, hypergeom, nhypergeom, bernoulli,
  3. boltzmann, skellam, zipf, zipfian, binom, nbinom,
  4. nchypergeom_fisher, nchypergeom_wallenius, randint)
  5. import numpy as np
  6. from numpy.testing import (
  7. assert_almost_equal, assert_equal, assert_allclose, suppress_warnings
  8. )
  9. from scipy.special import binom as special_binom
  10. from scipy.optimize import root_scalar
  11. from scipy.integrate import quad
  12. # The expected values were computed with Wolfram Alpha, using
  13. # the expression CDF[HypergeometricDistribution[N, n, M], k].
  14. @pytest.mark.parametrize('k, M, n, N, expected, rtol',
  15. [(3, 10, 4, 5,
  16. 0.9761904761904762, 1e-15),
  17. (107, 10000, 3000, 215,
  18. 0.9999999997226765, 1e-15),
  19. (10, 10000, 3000, 215,
  20. 2.681682217692179e-21, 5e-11)])
  21. def test_hypergeom_cdf(k, M, n, N, expected, rtol):
  22. p = hypergeom.cdf(k, M, n, N)
  23. assert_allclose(p, expected, rtol=rtol)
  24. # The expected values were computed with Wolfram Alpha, using
  25. # the expression SurvivalFunction[HypergeometricDistribution[N, n, M], k].
  26. @pytest.mark.parametrize('k, M, n, N, expected, rtol',
  27. [(25, 10000, 3000, 215,
  28. 0.9999999999052958, 1e-15),
  29. (125, 10000, 3000, 215,
  30. 1.4416781705752128e-18, 5e-11)])
  31. def test_hypergeom_sf(k, M, n, N, expected, rtol):
  32. p = hypergeom.sf(k, M, n, N)
  33. assert_allclose(p, expected, rtol=rtol)
  34. def test_hypergeom_logpmf():
  35. # symmetries test
  36. # f(k,N,K,n) = f(n-k,N,N-K,n) = f(K-k,N,K,N-n) = f(k,N,n,K)
  37. k = 5
  38. N = 50
  39. K = 10
  40. n = 5
  41. logpmf1 = hypergeom.logpmf(k, N, K, n)
  42. logpmf2 = hypergeom.logpmf(n - k, N, N - K, n)
  43. logpmf3 = hypergeom.logpmf(K - k, N, K, N - n)
  44. logpmf4 = hypergeom.logpmf(k, N, n, K)
  45. assert_almost_equal(logpmf1, logpmf2, decimal=12)
  46. assert_almost_equal(logpmf1, logpmf3, decimal=12)
  47. assert_almost_equal(logpmf1, logpmf4, decimal=12)
  48. # test related distribution
  49. # Bernoulli distribution if n = 1
  50. k = 1
  51. N = 10
  52. K = 7
  53. n = 1
  54. hypergeom_logpmf = hypergeom.logpmf(k, N, K, n)
  55. bernoulli_logpmf = bernoulli.logpmf(k, K/N)
  56. assert_almost_equal(hypergeom_logpmf, bernoulli_logpmf, decimal=12)
  57. def test_nhypergeom_pmf():
  58. # test with hypergeom
  59. M, n, r = 45, 13, 8
  60. k = 6
  61. NHG = nhypergeom.pmf(k, M, n, r)
  62. HG = hypergeom.pmf(k, M, n, k+r-1) * (M - n - (r-1)) / (M - (k+r-1))
  63. assert_allclose(HG, NHG, rtol=1e-10)
  64. def test_nhypergeom_pmfcdf():
  65. # test pmf and cdf with arbitrary values.
  66. M = 8
  67. n = 3
  68. r = 4
  69. support = np.arange(n+1)
  70. pmf = nhypergeom.pmf(support, M, n, r)
  71. cdf = nhypergeom.cdf(support, M, n, r)
  72. assert_allclose(pmf, [1/14, 3/14, 5/14, 5/14], rtol=1e-13)
  73. assert_allclose(cdf, [1/14, 4/14, 9/14, 1.0], rtol=1e-13)
  74. def test_nhypergeom_r0():
  75. # test with `r = 0`.
  76. M = 10
  77. n = 3
  78. r = 0
  79. pmf = nhypergeom.pmf([[0, 1, 2, 0], [1, 2, 0, 3]], M, n, r)
  80. assert_allclose(pmf, [[1, 0, 0, 1], [0, 0, 1, 0]], rtol=1e-13)
  81. def test_nhypergeom_rvs_shape():
  82. # Check that when given a size with more dimensions than the
  83. # dimensions of the broadcast parameters, rvs returns an array
  84. # with the correct shape.
  85. x = nhypergeom.rvs(22, [7, 8, 9], [[12], [13]], size=(5, 1, 2, 3))
  86. assert x.shape == (5, 1, 2, 3)
  87. def test_nhypergeom_accuracy():
  88. # Check that nhypergeom.rvs post-gh-13431 gives the same values as
  89. # inverse transform sampling
  90. np.random.seed(0)
  91. x = nhypergeom.rvs(22, 7, 11, size=100)
  92. np.random.seed(0)
  93. p = np.random.uniform(size=100)
  94. y = nhypergeom.ppf(p, 22, 7, 11)
  95. assert_equal(x, y)
  96. def test_boltzmann_upper_bound():
  97. k = np.arange(-3, 5)
  98. N = 1
  99. p = boltzmann.pmf(k, 0.123, N)
  100. expected = k == 0
  101. assert_equal(p, expected)
  102. lam = np.log(2)
  103. N = 3
  104. p = boltzmann.pmf(k, lam, N)
  105. expected = [0, 0, 0, 4/7, 2/7, 1/7, 0, 0]
  106. assert_allclose(p, expected, rtol=1e-13)
  107. c = boltzmann.cdf(k, lam, N)
  108. expected = [0, 0, 0, 4/7, 6/7, 1, 1, 1]
  109. assert_allclose(c, expected, rtol=1e-13)
  110. def test_betabinom_a_and_b_unity():
  111. # test limiting case that betabinom(n, 1, 1) is a discrete uniform
  112. # distribution from 0 to n
  113. n = 20
  114. k = np.arange(n + 1)
  115. p = betabinom(n, 1, 1).pmf(k)
  116. expected = np.repeat(1 / (n + 1), n + 1)
  117. assert_almost_equal(p, expected)
  118. def test_betabinom_bernoulli():
  119. # test limiting case that betabinom(1, a, b) = bernoulli(a / (a + b))
  120. a = 2.3
  121. b = 0.63
  122. k = np.arange(2)
  123. p = betabinom(1, a, b).pmf(k)
  124. expected = bernoulli(a / (a + b)).pmf(k)
  125. assert_almost_equal(p, expected)
  126. def test_issue_10317():
  127. alpha, n, p = 0.9, 10, 1
  128. assert_equal(nbinom.interval(confidence=alpha, n=n, p=p), (0, 0))
  129. def test_issue_11134():
  130. alpha, n, p = 0.95, 10, 0
  131. assert_equal(binom.interval(confidence=alpha, n=n, p=p), (0, 0))
  132. def test_issue_7406():
  133. np.random.seed(0)
  134. assert_equal(binom.ppf(np.random.rand(10), 0, 0.5), 0)
  135. # Also check that endpoints (q=0, q=1) are correct
  136. assert_equal(binom.ppf(0, 0, 0.5), -1)
  137. assert_equal(binom.ppf(1, 0, 0.5), 0)
  138. def test_issue_5122():
  139. p = 0
  140. n = np.random.randint(100, size=10)
  141. x = 0
  142. ppf = binom.ppf(x, n, p)
  143. assert_equal(ppf, -1)
  144. x = np.linspace(0.01, 0.99, 10)
  145. ppf = binom.ppf(x, n, p)
  146. assert_equal(ppf, 0)
  147. x = 1
  148. ppf = binom.ppf(x, n, p)
  149. assert_equal(ppf, n)
  150. def test_issue_1603():
  151. assert_equal(binom(1000, np.logspace(-3, -100)).ppf(0.01), 0)
  152. def test_issue_5503():
  153. p = 0.5
  154. x = np.logspace(3, 14, 12)
  155. assert_allclose(binom.cdf(x, 2*x, p), 0.5, atol=1e-2)
  156. @pytest.mark.parametrize('x, n, p, cdf_desired', [
  157. (300, 1000, 3/10, 0.51559351981411995636),
  158. (3000, 10000, 3/10, 0.50493298381929698016),
  159. (30000, 100000, 3/10, 0.50156000591726422864),
  160. (300000, 1000000, 3/10, 0.50049331906666960038),
  161. (3000000, 10000000, 3/10, 0.50015600124585261196),
  162. (30000000, 100000000, 3/10, 0.50004933192735230102),
  163. (30010000, 100000000, 3/10, 0.98545384016570790717),
  164. (29990000, 100000000, 3/10, 0.01455017177985268670),
  165. (29950000, 100000000, 3/10, 5.02250963487432024943e-28),
  166. ])
  167. def test_issue_5503pt2(x, n, p, cdf_desired):
  168. assert_allclose(binom.cdf(x, n, p), cdf_desired)
  169. def test_issue_5503pt3():
  170. # From Wolfram Alpha: CDF[BinomialDistribution[1e12, 1e-12], 2]
  171. assert_allclose(binom.cdf(2, 10**12, 10**-12), 0.91969860292869777384)
  172. def test_issue_6682():
  173. # Reference value from R:
  174. # options(digits=16)
  175. # print(pnbinom(250, 50, 32/63, lower.tail=FALSE))
  176. assert_allclose(nbinom.sf(250, 50, 32./63.), 1.460458510976452e-35)
  177. def test_boost_divide_by_zero_issue_15101():
  178. n = 1000
  179. p = 0.01
  180. k = 996
  181. assert_allclose(binom.pmf(k, n, p), 0.0)
  182. @pytest.mark.filterwarnings('ignore::RuntimeWarning')
  183. def test_skellam_gh11474():
  184. # test issue reported in gh-11474 caused by `cdfchn`
  185. mu = [1, 10, 100, 1000, 5000, 5050, 5100, 5250, 6000]
  186. cdf = skellam.cdf(0, mu, mu)
  187. # generated in R
  188. # library(skellam)
  189. # options(digits = 16)
  190. # mu = c(1, 10, 100, 1000, 5000, 5050, 5100, 5250, 6000)
  191. # pskellam(0, mu, mu, TRUE)
  192. cdf_expected = [0.6542541612768356, 0.5448901559424127, 0.5141135799745580,
  193. 0.5044605891382528, 0.5019947363350450, 0.5019848365953181,
  194. 0.5019750827993392, 0.5019466621805060, 0.5018209330219539]
  195. assert_allclose(cdf, cdf_expected)
  196. class TestZipfian:
  197. def test_zipfian_asymptotic(self):
  198. # test limiting case that zipfian(a, n) -> zipf(a) as n-> oo
  199. a = 6.5
  200. N = 10000000
  201. k = np.arange(1, 21)
  202. assert_allclose(zipfian.pmf(k, a, N), zipf.pmf(k, a))
  203. assert_allclose(zipfian.cdf(k, a, N), zipf.cdf(k, a))
  204. assert_allclose(zipfian.sf(k, a, N), zipf.sf(k, a))
  205. assert_allclose(zipfian.stats(a, N, moments='msvk'),
  206. zipf.stats(a, moments='msvk'))
  207. def test_zipfian_continuity(self):
  208. # test that zipfian(0.999999, n) ~ zipfian(1.000001, n)
  209. # (a = 1 switches between methods of calculating harmonic sum)
  210. alt1, agt1 = 0.99999999, 1.00000001
  211. N = 30
  212. k = np.arange(1, N + 1)
  213. assert_allclose(zipfian.pmf(k, alt1, N), zipfian.pmf(k, agt1, N),
  214. rtol=5e-7)
  215. assert_allclose(zipfian.cdf(k, alt1, N), zipfian.cdf(k, agt1, N),
  216. rtol=5e-7)
  217. assert_allclose(zipfian.sf(k, alt1, N), zipfian.sf(k, agt1, N),
  218. rtol=5e-7)
  219. assert_allclose(zipfian.stats(alt1, N, moments='msvk'),
  220. zipfian.stats(agt1, N, moments='msvk'), rtol=5e-7)
  221. def test_zipfian_R(self):
  222. # test against R VGAM package
  223. # library(VGAM)
  224. # k <- c(13, 16, 1, 4, 4, 8, 10, 19, 5, 7)
  225. # a <- c(1.56712977, 3.72656295, 5.77665117, 9.12168729, 5.79977172,
  226. # 4.92784796, 9.36078764, 4.3739616 , 7.48171872, 4.6824154)
  227. # n <- c(70, 80, 48, 65, 83, 89, 50, 30, 20, 20)
  228. # pmf <- dzipf(k, N = n, shape = a)
  229. # cdf <- pzipf(k, N = n, shape = a)
  230. # print(pmf)
  231. # print(cdf)
  232. np.random.seed(0)
  233. k = np.random.randint(1, 20, size=10)
  234. a = np.random.rand(10)*10 + 1
  235. n = np.random.randint(1, 100, size=10)
  236. pmf = [8.076972e-03, 2.950214e-05, 9.799333e-01, 3.216601e-06,
  237. 3.158895e-04, 3.412497e-05, 4.350472e-10, 2.405773e-06,
  238. 5.860662e-06, 1.053948e-04]
  239. cdf = [0.8964133, 0.9998666, 0.9799333, 0.9999995, 0.9998584,
  240. 0.9999458, 1.0000000, 0.9999920, 0.9999977, 0.9998498]
  241. # skip the first point; zipUC is not accurate for low a, n
  242. assert_allclose(zipfian.pmf(k, a, n)[1:], pmf[1:], rtol=1e-6)
  243. assert_allclose(zipfian.cdf(k, a, n)[1:], cdf[1:], rtol=5e-5)
  244. np.random.seed(0)
  245. naive_tests = np.vstack((np.logspace(-2, 1, 10),
  246. np.random.randint(2, 40, 10))).T
  247. @pytest.mark.parametrize("a, n", naive_tests)
  248. def test_zipfian_naive(self, a, n):
  249. # test against bare-bones implementation
  250. @np.vectorize
  251. def Hns(n, s):
  252. """Naive implementation of harmonic sum"""
  253. return (1/np.arange(1, n+1)**s).sum()
  254. @np.vectorize
  255. def pzip(k, a, n):
  256. """Naive implementation of zipfian pmf"""
  257. if k < 1 or k > n:
  258. return 0.
  259. else:
  260. return 1 / k**a / Hns(n, a)
  261. k = np.arange(n+1)
  262. pmf = pzip(k, a, n)
  263. cdf = np.cumsum(pmf)
  264. mean = np.average(k, weights=pmf)
  265. var = np.average((k - mean)**2, weights=pmf)
  266. std = var**0.5
  267. skew = np.average(((k-mean)/std)**3, weights=pmf)
  268. kurtosis = np.average(((k-mean)/std)**4, weights=pmf) - 3
  269. assert_allclose(zipfian.pmf(k, a, n), pmf)
  270. assert_allclose(zipfian.cdf(k, a, n), cdf)
  271. assert_allclose(zipfian.stats(a, n, moments="mvsk"),
  272. [mean, var, skew, kurtosis])
  273. class TestNCH():
  274. np.random.seed(2) # seeds 0 and 1 had some xl = xu; randint failed
  275. shape = (2, 4, 3)
  276. max_m = 100
  277. m1 = np.random.randint(1, max_m, size=shape) # red balls
  278. m2 = np.random.randint(1, max_m, size=shape) # white balls
  279. N = m1 + m2 # total balls
  280. n = randint.rvs(0, N, size=N.shape) # number of draws
  281. xl = np.maximum(0, n-m2) # lower bound of support
  282. xu = np.minimum(n, m1) # upper bound of support
  283. x = randint.rvs(xl, xu, size=xl.shape)
  284. odds = np.random.rand(*x.shape)*2
  285. # test output is more readable when function names (strings) are passed
  286. @pytest.mark.parametrize('dist_name',
  287. ['nchypergeom_fisher', 'nchypergeom_wallenius'])
  288. def test_nch_hypergeom(self, dist_name):
  289. # Both noncentral hypergeometric distributions reduce to the
  290. # hypergeometric distribution when odds = 1
  291. dists = {'nchypergeom_fisher': nchypergeom_fisher,
  292. 'nchypergeom_wallenius': nchypergeom_wallenius}
  293. dist = dists[dist_name]
  294. x, N, m1, n = self.x, self.N, self.m1, self.n
  295. assert_allclose(dist.pmf(x, N, m1, n, odds=1),
  296. hypergeom.pmf(x, N, m1, n))
  297. def test_nchypergeom_fisher_naive(self):
  298. # test against a very simple implementation
  299. x, N, m1, n, odds = self.x, self.N, self.m1, self.n, self.odds
  300. @np.vectorize
  301. def pmf_mean_var(x, N, m1, n, w):
  302. # simple implementation of nchypergeom_fisher pmf
  303. m2 = N - m1
  304. xl = np.maximum(0, n-m2)
  305. xu = np.minimum(n, m1)
  306. def f(x):
  307. t1 = special_binom(m1, x)
  308. t2 = special_binom(m2, n - x)
  309. return t1 * t2 * w**x
  310. def P(k):
  311. return sum((f(y)*y**k for y in range(xl, xu + 1)))
  312. P0 = P(0)
  313. P1 = P(1)
  314. P2 = P(2)
  315. pmf = f(x) / P0
  316. mean = P1 / P0
  317. var = P2 / P0 - (P1 / P0)**2
  318. return pmf, mean, var
  319. pmf, mean, var = pmf_mean_var(x, N, m1, n, odds)
  320. assert_allclose(nchypergeom_fisher.pmf(x, N, m1, n, odds), pmf)
  321. assert_allclose(nchypergeom_fisher.stats(N, m1, n, odds, moments='m'),
  322. mean)
  323. assert_allclose(nchypergeom_fisher.stats(N, m1, n, odds, moments='v'),
  324. var)
  325. def test_nchypergeom_wallenius_naive(self):
  326. # test against a very simple implementation
  327. np.random.seed(2)
  328. shape = (2, 4, 3)
  329. max_m = 100
  330. m1 = np.random.randint(1, max_m, size=shape)
  331. m2 = np.random.randint(1, max_m, size=shape)
  332. N = m1 + m2
  333. n = randint.rvs(0, N, size=N.shape)
  334. xl = np.maximum(0, n-m2)
  335. xu = np.minimum(n, m1)
  336. x = randint.rvs(xl, xu, size=xl.shape)
  337. w = np.random.rand(*x.shape)*2
  338. def support(N, m1, n, w):
  339. m2 = N - m1
  340. xl = np.maximum(0, n-m2)
  341. xu = np.minimum(n, m1)
  342. return xl, xu
  343. @np.vectorize
  344. def mean(N, m1, n, w):
  345. m2 = N - m1
  346. xl, xu = support(N, m1, n, w)
  347. def fun(u):
  348. return u/m1 + (1 - (n-u)/m2)**w - 1
  349. return root_scalar(fun, bracket=(xl, xu)).root
  350. with suppress_warnings() as sup:
  351. sup.filter(RuntimeWarning,
  352. message="invalid value encountered in mean")
  353. assert_allclose(nchypergeom_wallenius.mean(N, m1, n, w),
  354. mean(N, m1, n, w), rtol=2e-2)
  355. @np.vectorize
  356. def variance(N, m1, n, w):
  357. m2 = N - m1
  358. u = mean(N, m1, n, w)
  359. a = u * (m1 - u)
  360. b = (n-u)*(u + m2 - n)
  361. return N*a*b / ((N-1) * (m1*b + m2*a))
  362. with suppress_warnings() as sup:
  363. sup.filter(RuntimeWarning,
  364. message="invalid value encountered in mean")
  365. assert_allclose(
  366. nchypergeom_wallenius.stats(N, m1, n, w, moments='v'),
  367. variance(N, m1, n, w),
  368. rtol=5e-2
  369. )
  370. @np.vectorize
  371. def pmf(x, N, m1, n, w):
  372. m2 = N - m1
  373. xl, xu = support(N, m1, n, w)
  374. def integrand(t):
  375. D = w*(m1 - x) + (m2 - (n-x))
  376. res = (1-t**(w/D))**x * (1-t**(1/D))**(n-x)
  377. return res
  378. def f(x):
  379. t1 = special_binom(m1, x)
  380. t2 = special_binom(m2, n - x)
  381. the_integral = quad(integrand, 0, 1,
  382. epsrel=1e-16, epsabs=1e-16)
  383. return t1 * t2 * the_integral[0]
  384. return f(x)
  385. pmf0 = pmf(x, N, m1, n, w)
  386. pmf1 = nchypergeom_wallenius.pmf(x, N, m1, n, w)
  387. atol, rtol = 1e-6, 1e-6
  388. i = np.abs(pmf1 - pmf0) < atol + rtol*np.abs(pmf0)
  389. assert i.sum() > np.prod(shape) / 2 # works at least half the time
  390. # for those that fail, discredit the naive implementation
  391. for N, m1, n, w in zip(N[~i], m1[~i], n[~i], w[~i]):
  392. # get the support
  393. m2 = N - m1
  394. xl, xu = support(N, m1, n, w)
  395. x = np.arange(xl, xu + 1)
  396. # calculate sum of pmf over the support
  397. # the naive implementation is very wrong in these cases
  398. assert pmf(x, N, m1, n, w).sum() < .5
  399. assert_allclose(nchypergeom_wallenius.pmf(x, N, m1, n, w).sum(), 1)
  400. def test_wallenius_against_mpmath(self):
  401. # precompute data with mpmath since naive implementation above
  402. # is not reliable. See source code in gh-13330.
  403. M = 50
  404. n = 30
  405. N = 20
  406. odds = 2.25
  407. # Expected results, computed with mpmath.
  408. sup = np.arange(21)
  409. pmf = np.array([3.699003068656875e-20,
  410. 5.89398584245431e-17,
  411. 2.1594437742911123e-14,
  412. 3.221458044649955e-12,
  413. 2.4658279241205077e-10,
  414. 1.0965862603981212e-08,
  415. 3.057890479665704e-07,
  416. 5.622818831643761e-06,
  417. 7.056482841531681e-05,
  418. 0.000618899425358671,
  419. 0.003854172932571669,
  420. 0.01720592676256026,
  421. 0.05528844897093792,
  422. 0.12772363313574242,
  423. 0.21065898367825722,
  424. 0.24465958845359234,
  425. 0.1955114898110033,
  426. 0.10355390084949237,
  427. 0.03414490375225675,
  428. 0.006231989845775931,
  429. 0.0004715577304677075])
  430. mean = 14.808018384813426
  431. var = 2.6085975877923717
  432. # nchypergeom_wallenius.pmf returns 0 for pmf(0) and pmf(1), and pmf(2)
  433. # has only three digits of accuracy (~ 2.1511e-14).
  434. assert_allclose(nchypergeom_wallenius.pmf(sup, M, n, N, odds), pmf,
  435. rtol=1e-13, atol=1e-13)
  436. assert_allclose(nchypergeom_wallenius.mean(M, n, N, odds),
  437. mean, rtol=1e-13)
  438. assert_allclose(nchypergeom_wallenius.var(M, n, N, odds),
  439. var, rtol=1e-11)
  440. @pytest.mark.parametrize('dist_name',
  441. ['nchypergeom_fisher', 'nchypergeom_wallenius'])
  442. def test_rvs_shape(self, dist_name):
  443. # Check that when given a size with more dimensions than the
  444. # dimensions of the broadcast parameters, rvs returns an array
  445. # with the correct shape.
  446. dists = {'nchypergeom_fisher': nchypergeom_fisher,
  447. 'nchypergeom_wallenius': nchypergeom_wallenius}
  448. dist = dists[dist_name]
  449. x = dist.rvs(50, 30, [[10], [20]], [0.5, 1.0, 2.0], size=(5, 1, 2, 3))
  450. assert x.shape == (5, 1, 2, 3)
  451. @pytest.mark.parametrize("mu, q, expected",
  452. [[10, 120, -1.240089881791596e-38],
  453. [1500, 0, -86.61466680572661]])
  454. def test_nbinom_11465(mu, q, expected):
  455. # test nbinom.logcdf at extreme tails
  456. size = 20
  457. n, p = size, size/(size+mu)
  458. # In R:
  459. # options(digits=16)
  460. # pnbinom(mu=10, size=20, q=120, log.p=TRUE)
  461. assert_allclose(nbinom.logcdf(q, n, p), expected)
  462. def test_gh_17146():
  463. # Check that discrete distributions return PMF of zero at non-integral x.
  464. # See gh-17146.
  465. x = np.linspace(0, 1, 11)
  466. p = 0.8
  467. pmf = bernoulli(p).pmf(x)
  468. i = (x % 1 == 0)
  469. assert_allclose(pmf[-1], p)
  470. assert_allclose(pmf[0], 1-p)
  471. assert_equal(pmf[~i], 0)