PageRenderTime 139ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/scipy/stats/_continuous_distns.py

https://github.com/matthew-brett/scipy
Python | 1846 lines | 1802 code | 7 blank | 37 comment | 7 complexity | 790fa5e2faa5ee1f6aa083fd4f08f4ae MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Author: Travis Oliphant 2002-2011 with contributions from
  4. # SciPy Developers 2004-2011
  5. #
  6. import warnings
  7. from collections.abc import Iterable
  8. from functools import wraps
  9. import ctypes
  10. import numpy as np
  11. from scipy._lib.doccer import (extend_notes_in_docstring,
  12. replace_notes_in_docstring)
  13. from scipy._lib._ccallback import LowLevelCallable
  14. from scipy import optimize
  15. from scipy import integrate
  16. from scipy import interpolate
  17. import scipy.special as sc
  18. import scipy.special._ufuncs as scu
  19. from scipy._lib._util import _lazyselect, _lazywhere
  20. from . import _stats
  21. from ._rvs_sampling import rvs_ratio_uniforms
  22. from ._tukeylambda_stats import (tukeylambda_variance as _tlvar,
  23. tukeylambda_kurtosis as _tlkurt)
  24. from ._distn_infrastructure import (
  25. get_distribution_names, _kurtosis, _ncx2_cdf, _ncx2_log_pdf, _ncx2_pdf,
  26. rv_continuous, _skew, _get_fixed_fit_value, _check_shape)
  27. from ._ksstats import kolmogn, kolmognp, kolmogni
  28. from ._constants import (_XMIN, _EULER, _ZETA3,
  29. _SQRT_2_OVER_PI, _LOG_SQRT_2_OVER_PI)
  30. import scipy.stats._boost as _boost
  31. def _remove_optimizer_parameters(kwds):
  32. """
  33. Remove the optimizer-related keyword arguments 'loc', 'scale' and
  34. 'optimizer' from `kwds`. Then check that `kwds` is empty, and
  35. raise `TypeError("Unknown arguments: %s." % kwds)` if it is not.
  36. This function is used in the fit method of distributions that override
  37. the default method and do not use the default optimization code.
  38. `kwds` is modified in-place.
  39. """
  40. kwds.pop('loc', None)
  41. kwds.pop('scale', None)
  42. kwds.pop('optimizer', None)
  43. kwds.pop('method', None)
  44. if kwds:
  45. raise TypeError("Unknown arguments: %s." % kwds)
  46. def _call_super_mom(fun):
  47. # if fit method is overridden only for MLE and doesn't specify what to do
  48. # if method == 'mm', this decorator calls generic implementation
  49. @wraps(fun)
  50. def wrapper(self, *args, **kwds):
  51. method = kwds.get('method', 'mle').lower()
  52. if method == 'mm':
  53. return super(type(self), self).fit(*args, **kwds)
  54. else:
  55. return fun(self, *args, **kwds)
  56. return wrapper
  57. class ksone_gen(rv_continuous):
  58. r"""Kolmogorov-Smirnov one-sided test statistic distribution.
  59. This is the distribution of the one-sided Kolmogorov-Smirnov (KS)
  60. statistics :math:`D_n^+` and :math:`D_n^-`
  61. for a finite sample size ``n`` (the shape parameter).
  62. %(before_notes)s
  63. See Also
  64. --------
  65. kstwobign, kstwo, kstest
  66. Notes
  67. -----
  68. :math:`D_n^+` and :math:`D_n^-` are given by
  69. .. math::
  70. D_n^+ &= \text{sup}_x (F_n(x) - F(x)),\\
  71. D_n^- &= \text{sup}_x (F(x) - F_n(x)),\\
  72. where :math:`F` is a continuous CDF and :math:`F_n` is an empirical CDF.
  73. `ksone` describes the distribution under the null hypothesis of the KS test
  74. that the empirical CDF corresponds to :math:`n` i.i.d. random variates
  75. with CDF :math:`F`.
  76. %(after_notes)s
  77. References
  78. ----------
  79. .. [1] Birnbaum, Z. W. and Tingey, F.H. "One-sided confidence contours
  80. for probability distribution functions", The Annals of Mathematical
  81. Statistics, 22(4), pp 592-596 (1951).
  82. %(example)s
  83. """
  84. def _pdf(self, x, n):
  85. return -scu._smirnovp(n, x)
  86. def _cdf(self, x, n):
  87. return scu._smirnovc(n, x)
  88. def _sf(self, x, n):
  89. return sc.smirnov(n, x)
  90. def _ppf(self, q, n):
  91. return scu._smirnovci(n, q)
  92. def _isf(self, q, n):
  93. return sc.smirnovi(n, q)
  94. ksone = ksone_gen(a=0.0, b=1.0, name='ksone')
  95. class kstwo_gen(rv_continuous):
  96. r"""Kolmogorov-Smirnov two-sided test statistic distribution.
  97. This is the distribution of the two-sided Kolmogorov-Smirnov (KS)
  98. statistic :math:`D_n` for a finite sample size ``n``
  99. (the shape parameter).
  100. %(before_notes)s
  101. See Also
  102. --------
  103. kstwobign, ksone, kstest
  104. Notes
  105. -----
  106. :math:`D_n` is given by
  107. .. math::
  108. D_n = \text{sup}_x |F_n(x) - F(x)|
  109. where :math:`F` is a (continuous) CDF and :math:`F_n` is an empirical CDF.
  110. `kstwo` describes the distribution under the null hypothesis of the KS test
  111. that the empirical CDF corresponds to :math:`n` i.i.d. random variates
  112. with CDF :math:`F`.
  113. %(after_notes)s
  114. References
  115. ----------
  116. .. [1] Simard, R., L'Ecuyer, P. "Computing the Two-Sided
  117. Kolmogorov-Smirnov Distribution", Journal of Statistical Software,
  118. Vol 39, 11, 1-18 (2011).
  119. %(example)s
  120. """
  121. def _get_support(self, n):
  122. return (0.5/(n if not isinstance(n, Iterable) else np.asanyarray(n)),
  123. 1.0)
  124. def _pdf(self, x, n):
  125. return kolmognp(n, x)
  126. def _cdf(self, x, n):
  127. return kolmogn(n, x)
  128. def _sf(self, x, n):
  129. return kolmogn(n, x, cdf=False)
  130. def _ppf(self, q, n):
  131. return kolmogni(n, q, cdf=True)
  132. def _isf(self, q, n):
  133. return kolmogni(n, q, cdf=False)
  134. # Use the pdf, (not the ppf) to compute moments
  135. kstwo = kstwo_gen(momtype=0, a=0.0, b=1.0, name='kstwo')
  136. class kstwobign_gen(rv_continuous):
  137. r"""Limiting distribution of scaled Kolmogorov-Smirnov two-sided test statistic.
  138. This is the asymptotic distribution of the two-sided Kolmogorov-Smirnov
  139. statistic :math:`\sqrt{n} D_n` that measures the maximum absolute
  140. distance of the theoretical (continuous) CDF from the empirical CDF.
  141. (see `kstest`).
  142. %(before_notes)s
  143. See Also
  144. --------
  145. ksone, kstwo, kstest
  146. Notes
  147. -----
  148. :math:`\sqrt{n} D_n` is given by
  149. .. math::
  150. D_n = \text{sup}_x |F_n(x) - F(x)|
  151. where :math:`F` is a continuous CDF and :math:`F_n` is an empirical CDF.
  152. `kstwobign` describes the asymptotic distribution (i.e. the limit of
  153. :math:`\sqrt{n} D_n`) under the null hypothesis of the KS test that the
  154. empirical CDF corresponds to i.i.d. random variates with CDF :math:`F`.
  155. %(after_notes)s
  156. References
  157. ----------
  158. .. [1] Feller, W. "On the Kolmogorov-Smirnov Limit Theorems for Empirical
  159. Distributions", Ann. Math. Statist. Vol 19, 177-189 (1948).
  160. %(example)s
  161. """
  162. def _pdf(self, x):
  163. return -scu._kolmogp(x)
  164. def _cdf(self, x):
  165. return scu._kolmogc(x)
  166. def _sf(self, x):
  167. return sc.kolmogorov(x)
  168. def _ppf(self, q):
  169. return scu._kolmogci(q)
  170. def _isf(self, q):
  171. return sc.kolmogi(q)
  172. kstwobign = kstwobign_gen(a=0.0, name='kstwobign')
  173. ## Normal distribution
  174. # loc = mu, scale = std
  175. # Keep these implementations out of the class definition so they can be reused
  176. # by other distributions.
  177. _norm_pdf_C = np.sqrt(2*np.pi)
  178. _norm_pdf_logC = np.log(_norm_pdf_C)
  179. def _norm_pdf(x):
  180. return np.exp(-x**2/2.0) / _norm_pdf_C
  181. def _norm_logpdf(x):
  182. return -x**2 / 2.0 - _norm_pdf_logC
  183. def _norm_cdf(x):
  184. return sc.ndtr(x)
  185. def _norm_logcdf(x):
  186. return sc.log_ndtr(x)
  187. def _norm_ppf(q):
  188. return sc.ndtri(q)
  189. def _norm_sf(x):
  190. return _norm_cdf(-x)
  191. def _norm_logsf(x):
  192. return _norm_logcdf(-x)
  193. def _norm_isf(q):
  194. return -_norm_ppf(q)
  195. class norm_gen(rv_continuous):
  196. r"""A normal continuous random variable.
  197. The location (``loc``) keyword specifies the mean.
  198. The scale (``scale``) keyword specifies the standard deviation.
  199. %(before_notes)s
  200. Notes
  201. -----
  202. The probability density function for `norm` is:
  203. .. math::
  204. f(x) = \frac{\exp(-x^2/2)}{\sqrt{2\pi}}
  205. for a real number :math:`x`.
  206. %(after_notes)s
  207. %(example)s
  208. """
  209. def _rvs(self, size=None, random_state=None):
  210. return random_state.standard_normal(size)
  211. def _pdf(self, x):
  212. # norm.pdf(x) = exp(-x**2/2)/sqrt(2*pi)
  213. return _norm_pdf(x)
  214. def _logpdf(self, x):
  215. return _norm_logpdf(x)
  216. def _cdf(self, x):
  217. return _norm_cdf(x)
  218. def _logcdf(self, x):
  219. return _norm_logcdf(x)
  220. def _sf(self, x):
  221. return _norm_sf(x)
  222. def _logsf(self, x):
  223. return _norm_logsf(x)
  224. def _ppf(self, q):
  225. return _norm_ppf(q)
  226. def _isf(self, q):
  227. return _norm_isf(q)
  228. def _stats(self):
  229. return 0.0, 1.0, 0.0, 0.0
  230. def _entropy(self):
  231. return 0.5*(np.log(2*np.pi)+1)
  232. @_call_super_mom
  233. @replace_notes_in_docstring(rv_continuous, notes="""\
  234. For the normal distribution, method of moments and maximum likelihood
  235. estimation give identical fits, and explicit formulas for the estimates
  236. are available.
  237. This function uses these explicit formulas for the maximum likelihood
  238. estimation of the normal distribution parameters, so the
  239. `optimizer` and `method` arguments are ignored.\n\n""")
  240. def fit(self, data, **kwds):
  241. floc = kwds.pop('floc', None)
  242. fscale = kwds.pop('fscale', None)
  243. _remove_optimizer_parameters(kwds)
  244. if floc is not None and fscale is not None:
  245. # This check is for consistency with `rv_continuous.fit`.
  246. # Without this check, this function would just return the
  247. # parameters that were given.
  248. raise ValueError("All parameters fixed. There is nothing to "
  249. "optimize.")
  250. data = np.asarray(data)
  251. if not np.isfinite(data).all():
  252. raise RuntimeError("The data contains non-finite values.")
  253. if floc is None:
  254. loc = data.mean()
  255. else:
  256. loc = floc
  257. if fscale is None:
  258. scale = np.sqrt(((data - loc)**2).mean())
  259. else:
  260. scale = fscale
  261. return loc, scale
  262. def _munp(self, n):
  263. """
  264. @returns Moments of standard normal distribution for integer n >= 0
  265. See eq. 16 of https://arxiv.org/abs/1209.4340v2
  266. """
  267. if n % 2 == 0:
  268. return sc.factorial2(n - 1)
  269. else:
  270. return 0.
  271. norm = norm_gen(name='norm')
  272. class alpha_gen(rv_continuous):
  273. r"""An alpha continuous random variable.
  274. %(before_notes)s
  275. Notes
  276. -----
  277. The probability density function for `alpha` ([1]_, [2]_) is:
  278. .. math::
  279. f(x, a) = \frac{1}{x^2 \Phi(a) \sqrt{2\pi}} *
  280. \exp(-\frac{1}{2} (a-1/x)^2)
  281. where :math:`\Phi` is the normal CDF, :math:`x > 0`, and :math:`a > 0`.
  282. `alpha` takes ``a`` as a shape parameter.
  283. %(after_notes)s
  284. References
  285. ----------
  286. .. [1] Johnson, Kotz, and Balakrishnan, "Continuous Univariate
  287. Distributions, Volume 1", Second Edition, John Wiley and Sons,
  288. p. 173 (1994).
  289. .. [2] Anthony A. Salvia, "Reliability applications of the Alpha
  290. Distribution", IEEE Transactions on Reliability, Vol. R-34,
  291. No. 3, pp. 251-252 (1985).
  292. %(example)s
  293. """
  294. _support_mask = rv_continuous._open_support_mask
  295. def _pdf(self, x, a):
  296. # alpha.pdf(x, a) = 1/(x**2*Phi(a)*sqrt(2*pi)) * exp(-1/2 * (a-1/x)**2)
  297. return 1.0/(x**2)/_norm_cdf(a)*_norm_pdf(a-1.0/x)
  298. def _logpdf(self, x, a):
  299. return -2*np.log(x) + _norm_logpdf(a-1.0/x) - np.log(_norm_cdf(a))
  300. def _cdf(self, x, a):
  301. return _norm_cdf(a-1.0/x) / _norm_cdf(a)
  302. def _ppf(self, q, a):
  303. return 1.0/np.asarray(a-sc.ndtri(q*_norm_cdf(a)))
  304. def _stats(self, a):
  305. return [np.inf]*2 + [np.nan]*2
  306. alpha = alpha_gen(a=0.0, name='alpha')
  307. class anglit_gen(rv_continuous):
  308. r"""An anglit continuous random variable.
  309. %(before_notes)s
  310. Notes
  311. -----
  312. The probability density function for `anglit` is:
  313. .. math::
  314. f(x) = \sin(2x + \pi/2) = \cos(2x)
  315. for :math:`-\pi/4 \le x \le \pi/4`.
  316. %(after_notes)s
  317. %(example)s
  318. """
  319. def _pdf(self, x):
  320. # anglit.pdf(x) = sin(2*x + \pi/2) = cos(2*x)
  321. return np.cos(2*x)
  322. def _cdf(self, x):
  323. return np.sin(x+np.pi/4)**2.0
  324. def _ppf(self, q):
  325. return np.arcsin(np.sqrt(q))-np.pi/4
  326. def _stats(self):
  327. return 0.0, np.pi*np.pi/16-0.5, 0.0, -2*(np.pi**4 - 96)/(np.pi*np.pi-8)**2
  328. def _entropy(self):
  329. return 1-np.log(2)
  330. anglit = anglit_gen(a=-np.pi/4, b=np.pi/4, name='anglit')
  331. class arcsine_gen(rv_continuous):
  332. r"""An arcsine continuous random variable.
  333. %(before_notes)s
  334. Notes
  335. -----
  336. The probability density function for `arcsine` is:
  337. .. math::
  338. f(x) = \frac{1}{\pi \sqrt{x (1-x)}}
  339. for :math:`0 < x < 1`.
  340. %(after_notes)s
  341. %(example)s
  342. """
  343. def _pdf(self, x):
  344. # arcsine.pdf(x) = 1/(pi*sqrt(x*(1-x)))
  345. with np.errstate(divide='ignore'):
  346. return 1.0/np.pi/np.sqrt(x*(1-x))
  347. def _cdf(self, x):
  348. return 2.0/np.pi*np.arcsin(np.sqrt(x))
  349. def _ppf(self, q):
  350. return np.sin(np.pi/2.0*q)**2.0
  351. def _stats(self):
  352. mu = 0.5
  353. mu2 = 1.0/8
  354. g1 = 0
  355. g2 = -3.0/2.0
  356. return mu, mu2, g1, g2
  357. def _entropy(self):
  358. return -0.24156447527049044468
  359. arcsine = arcsine_gen(a=0.0, b=1.0, name='arcsine')
  360. class FitDataError(ValueError):
  361. # This exception is raised by, for example, beta_gen.fit when both floc
  362. # and fscale are fixed and there are values in the data not in the open
  363. # interval (floc, floc+fscale).
  364. def __init__(self, distr, lower, upper):
  365. self.args = (
  366. "Invalid values in `data`. Maximum likelihood "
  367. "estimation with {distr!r} requires that {lower!r} < "
  368. "(x - loc)/scale < {upper!r} for each x in `data`.".format(
  369. distr=distr, lower=lower, upper=upper),
  370. )
  371. class FitSolverError(RuntimeError):
  372. # This exception is raised by, for example, beta_gen.fit when
  373. # optimize.fsolve returns with ier != 1.
  374. def __init__(self, mesg):
  375. emsg = "Solver for the MLE equations failed to converge: "
  376. emsg += mesg.replace('\n', '')
  377. self.args = (emsg,)
  378. def _beta_mle_a(a, b, n, s1):
  379. # The zeros of this function give the MLE for `a`, with
  380. # `b`, `n` and `s1` given. `s1` is the sum of the logs of
  381. # the data. `n` is the number of data points.
  382. psiab = sc.psi(a + b)
  383. func = s1 - n * (-psiab + sc.psi(a))
  384. return func
  385. def _beta_mle_ab(theta, n, s1, s2):
  386. # Zeros of this function are critical points of
  387. # the maximum likelihood function. Solving this system
  388. # for theta (which contains a and b) gives the MLE for a and b
  389. # given `n`, `s1` and `s2`. `s1` is the sum of the logs of the data,
  390. # and `s2` is the sum of the logs of 1 - data. `n` is the number
  391. # of data points.
  392. a, b = theta
  393. psiab = sc.psi(a + b)
  394. func = [s1 - n * (-psiab + sc.psi(a)),
  395. s2 - n * (-psiab + sc.psi(b))]
  396. return func
  397. class beta_gen(rv_continuous):
  398. r"""A beta continuous random variable.
  399. %(before_notes)s
  400. Notes
  401. -----
  402. The probability density function for `beta` is:
  403. .. math::
  404. f(x, a, b) = \frac{\Gamma(a+b) x^{a-1} (1-x)^{b-1}}
  405. {\Gamma(a) \Gamma(b)}
  406. for :math:`0 <= x <= 1`, :math:`a > 0`, :math:`b > 0`, where
  407. :math:`\Gamma` is the gamma function (`scipy.special.gamma`).
  408. `beta` takes :math:`a` and :math:`b` as shape parameters.
  409. %(after_notes)s
  410. %(example)s
  411. """
  412. def _rvs(self, a, b, size=None, random_state=None):
  413. return random_state.beta(a, b, size)
  414. def _pdf(self, x, a, b):
  415. # gamma(a+b) * x**(a-1) * (1-x)**(b-1)
  416. # beta.pdf(x, a, b) = ------------------------------------
  417. # gamma(a)*gamma(b)
  418. return _boost._beta_pdf(x, a, b)
  419. def _logpdf(self, x, a, b):
  420. lPx = sc.xlog1py(b - 1.0, -x) + sc.xlogy(a - 1.0, x)
  421. lPx -= sc.betaln(a, b)
  422. return lPx
  423. def _cdf(self, x, a, b):
  424. return _boost._beta_cdf(x, a, b)
  425. def _sf(self, x, a, b):
  426. return _boost._beta_sf(x, a, b)
  427. def _isf(self, x, a, b):
  428. return _boost._beta_isf(x, a, b)
  429. def _ppf(self, q, a, b):
  430. return _boost._beta_ppf(q, a, b)
  431. def _stats(self, a, b):
  432. return(
  433. _boost._beta_mean(a, b),
  434. _boost._beta_variance(a, b),
  435. _boost._beta_skewness(a, b),
  436. _boost._beta_kurtosis_excess(a, b))
  437. def _fitstart(self, data):
  438. g1 = _skew(data)
  439. g2 = _kurtosis(data)
  440. def func(x):
  441. a, b = x
  442. sk = 2*(b-a)*np.sqrt(a + b + 1) / (a + b + 2) / np.sqrt(a*b)
  443. ku = a**3 - a**2*(2*b-1) + b**2*(b+1) - 2*a*b*(b+2)
  444. ku /= a*b*(a+b+2)*(a+b+3)
  445. ku *= 6
  446. return [sk-g1, ku-g2]
  447. a, b = optimize.fsolve(func, (1.0, 1.0))
  448. return super()._fitstart(data, args=(a, b))
  449. @_call_super_mom
  450. @extend_notes_in_docstring(rv_continuous, notes="""\
  451. In the special case where `method="MLE"` and
  452. both `floc` and `fscale` are given, a
  453. `ValueError` is raised if any value `x` in `data` does not satisfy
  454. `floc < x < floc + fscale`.\n\n""")
  455. def fit(self, data, *args, **kwds):
  456. # Override rv_continuous.fit, so we can more efficiently handle the
  457. # case where floc and fscale are given.
  458. floc = kwds.get('floc', None)
  459. fscale = kwds.get('fscale', None)
  460. if floc is None or fscale is None:
  461. # do general fit
  462. return super().fit(data, *args, **kwds)
  463. # We already got these from kwds, so just pop them.
  464. kwds.pop('floc', None)
  465. kwds.pop('fscale', None)
  466. f0 = _get_fixed_fit_value(kwds, ['f0', 'fa', 'fix_a'])
  467. f1 = _get_fixed_fit_value(kwds, ['f1', 'fb', 'fix_b'])
  468. _remove_optimizer_parameters(kwds)
  469. if f0 is not None and f1 is not None:
  470. # This check is for consistency with `rv_continuous.fit`.
  471. raise ValueError("All parameters fixed. There is nothing to "
  472. "optimize.")
  473. # Special case: loc and scale are constrained, so we are fitting
  474. # just the shape parameters. This can be done much more efficiently
  475. # than the method used in `rv_continuous.fit`. (See the subsection
  476. # "Two unknown parameters" in the section "Maximum likelihood" of
  477. # the Wikipedia article on the Beta distribution for the formulas.)
  478. if not np.isfinite(data).all():
  479. raise RuntimeError("The data contains non-finite values.")
  480. # Normalize the data to the interval [0, 1].
  481. data = (np.ravel(data) - floc) / fscale
  482. if np.any(data <= 0) or np.any(data >= 1):
  483. raise FitDataError("beta", lower=floc, upper=floc + fscale)
  484. xbar = data.mean()
  485. if f0 is not None or f1 is not None:
  486. # One of the shape parameters is fixed.
  487. if f0 is not None:
  488. # The shape parameter a is fixed, so swap the parameters
  489. # and flip the data. We always solve for `a`. The result
  490. # will be swapped back before returning.
  491. b = f0
  492. data = 1 - data
  493. xbar = 1 - xbar
  494. else:
  495. b = f1
  496. # Initial guess for a. Use the formula for the mean of the beta
  497. # distribution, E[x] = a / (a + b), to generate a reasonable
  498. # starting point based on the mean of the data and the given
  499. # value of b.
  500. a = b * xbar / (1 - xbar)
  501. # Compute the MLE for `a` by solving _beta_mle_a.
  502. theta, info, ier, mesg = optimize.fsolve(
  503. _beta_mle_a, a,
  504. args=(b, len(data), np.log(data).sum()),
  505. full_output=True
  506. )
  507. if ier != 1:
  508. raise FitSolverError(mesg=mesg)
  509. a = theta[0]
  510. if f0 is not None:
  511. # The shape parameter a was fixed, so swap back the
  512. # parameters.
  513. a, b = b, a
  514. else:
  515. # Neither of the shape parameters is fixed.
  516. # s1 and s2 are used in the extra arguments passed to _beta_mle_ab
  517. # by optimize.fsolve.
  518. s1 = np.log(data).sum()
  519. s2 = sc.log1p(-data).sum()
  520. # Use the "method of moments" to estimate the initial
  521. # guess for a and b.
  522. fac = xbar * (1 - xbar) / data.var(ddof=0) - 1
  523. a = xbar * fac
  524. b = (1 - xbar) * fac
  525. # Compute the MLE for a and b by solving _beta_mle_ab.
  526. theta, info, ier, mesg = optimize.fsolve(
  527. _beta_mle_ab, [a, b],
  528. args=(len(data), s1, s2),
  529. full_output=True
  530. )
  531. if ier != 1:
  532. raise FitSolverError(mesg=mesg)
  533. a, b = theta
  534. return a, b, floc, fscale
  535. beta = beta_gen(a=0.0, b=1.0, name='beta')
  536. class betaprime_gen(rv_continuous):
  537. r"""A beta prime continuous random variable.
  538. %(before_notes)s
  539. Notes
  540. -----
  541. The probability density function for `betaprime` is:
  542. .. math::
  543. f(x, a, b) = \frac{x^{a-1} (1+x)^{-a-b}}{\beta(a, b)}
  544. for :math:`x >= 0`, :math:`a > 0`, :math:`b > 0`, where
  545. :math:`\beta(a, b)` is the beta function (see `scipy.special.beta`).
  546. `betaprime` takes ``a`` and ``b`` as shape parameters.
  547. %(after_notes)s
  548. %(example)s
  549. """
  550. _support_mask = rv_continuous._open_support_mask
  551. def _rvs(self, a, b, size=None, random_state=None):
  552. u1 = gamma.rvs(a, size=size, random_state=random_state)
  553. u2 = gamma.rvs(b, size=size, random_state=random_state)
  554. return u1 / u2
  555. def _pdf(self, x, a, b):
  556. # betaprime.pdf(x, a, b) = x**(a-1) * (1+x)**(-a-b) / beta(a, b)
  557. return np.exp(self._logpdf(x, a, b))
  558. def _logpdf(self, x, a, b):
  559. return sc.xlogy(a - 1.0, x) - sc.xlog1py(a + b, x) - sc.betaln(a, b)
  560. def _cdf(self, x, a, b):
  561. return sc.betainc(a, b, x/(1.+x))
  562. def _munp(self, n, a, b):
  563. if n == 1.0:
  564. return np.where(b > 1,
  565. a/(b-1.0),
  566. np.inf)
  567. elif n == 2.0:
  568. return np.where(b > 2,
  569. a*(a+1.0)/((b-2.0)*(b-1.0)),
  570. np.inf)
  571. elif n == 3.0:
  572. return np.where(b > 3,
  573. a*(a+1.0)*(a+2.0)/((b-3.0)*(b-2.0)*(b-1.0)),
  574. np.inf)
  575. elif n == 4.0:
  576. return np.where(b > 4,
  577. (a*(a + 1.0)*(a + 2.0)*(a + 3.0) /
  578. ((b - 4.0)*(b - 3.0)*(b - 2.0)*(b - 1.0))),
  579. np.inf)
  580. else:
  581. raise NotImplementedError
  582. betaprime = betaprime_gen(a=0.0, name='betaprime')
  583. class bradford_gen(rv_continuous):
  584. r"""A Bradford continuous random variable.
  585. %(before_notes)s
  586. Notes
  587. -----
  588. The probability density function for `bradford` is:
  589. .. math::
  590. f(x, c) = \frac{c}{\log(1+c) (1+cx)}
  591. for :math:`0 <= x <= 1` and :math:`c > 0`.
  592. `bradford` takes ``c`` as a shape parameter for :math:`c`.
  593. %(after_notes)s
  594. %(example)s
  595. """
  596. def _pdf(self, x, c):
  597. # bradford.pdf(x, c) = c / (k * (1+c*x))
  598. return c / (c*x + 1.0) / sc.log1p(c)
  599. def _cdf(self, x, c):
  600. return sc.log1p(c*x) / sc.log1p(c)
  601. def _ppf(self, q, c):
  602. return sc.expm1(q * sc.log1p(c)) / c
  603. def _stats(self, c, moments='mv'):
  604. k = np.log(1.0+c)
  605. mu = (c-k)/(c*k)
  606. mu2 = ((c+2.0)*k-2.0*c)/(2*c*k*k)
  607. g1 = None
  608. g2 = None
  609. if 's' in moments:
  610. g1 = np.sqrt(2)*(12*c*c-9*c*k*(c+2)+2*k*k*(c*(c+3)+3))
  611. g1 /= np.sqrt(c*(c*(k-2)+2*k))*(3*c*(k-2)+6*k)
  612. if 'k' in moments:
  613. g2 = (c**3*(k-3)*(k*(3*k-16)+24)+12*k*c*c*(k-4)*(k-3) +
  614. 6*c*k*k*(3*k-14) + 12*k**3)
  615. g2 /= 3*c*(c*(k-2)+2*k)**2
  616. return mu, mu2, g1, g2
  617. def _entropy(self, c):
  618. k = np.log(1+c)
  619. return k/2.0 - np.log(c/k)
  620. bradford = bradford_gen(a=0.0, b=1.0, name='bradford')
  621. class burr_gen(rv_continuous):
  622. r"""A Burr (Type III) continuous random variable.
  623. %(before_notes)s
  624. See Also
  625. --------
  626. fisk : a special case of either `burr` or `burr12` with ``d=1``
  627. burr12 : Burr Type XII distribution
  628. mielke : Mielke Beta-Kappa / Dagum distribution
  629. Notes
  630. -----
  631. The probability density function for `burr` is:
  632. .. math::
  633. f(x, c, d) = c d x^{-c - 1} / (1 + x^{-c})^{d + 1}
  634. for :math:`x >= 0` and :math:`c, d > 0`.
  635. `burr` takes :math:`c` and :math:`d` as shape parameters.
  636. This is the PDF corresponding to the third CDF given in Burr's list;
  637. specifically, it is equation (11) in Burr's paper [1]_. The distribution
  638. is also commonly referred to as the Dagum distribution [2]_. If the
  639. parameter :math:`c < 1` then the mean of the distribution does not
  640. exist and if :math:`c < 2` the variance does not exist [2]_.
  641. The PDF is finite at the left endpoint :math:`x = 0` if :math:`c * d >= 1`.
  642. %(after_notes)s
  643. References
  644. ----------
  645. .. [1] Burr, I. W. "Cumulative frequency functions", Annals of
  646. Mathematical Statistics, 13(2), pp 215-232 (1942).
  647. .. [2] https://en.wikipedia.org/wiki/Dagum_distribution
  648. .. [3] Kleiber, Christian. "A guide to the Dagum distributions."
  649. Modeling Income Distributions and Lorenz Curves pp 97-117 (2008).
  650. %(example)s
  651. """
  652. # Do not set _support_mask to rv_continuous._open_support_mask
  653. # Whether the left-hand endpoint is suitable for pdf evaluation is dependent
  654. # on the values of c and d: if c*d >= 1, the pdf is finite, otherwise infinite.
  655. def _pdf(self, x, c, d):
  656. # burr.pdf(x, c, d) = c * d * x**(-c-1) * (1+x**(-c))**(-d-1)
  657. output = _lazywhere(x == 0, [x, c, d],
  658. lambda x_, c_, d_: c_ * d_ * (x_**(c_*d_-1)) / (1 + x_**c_),
  659. f2 = lambda x_, c_, d_: (c_ * d_ * (x_ ** (-c_ - 1.0)) /
  660. ((1 + x_ ** (-c_)) ** (d_ + 1.0))))
  661. if output.ndim == 0:
  662. return output[()]
  663. return output
  664. def _logpdf(self, x, c, d):
  665. output = _lazywhere(
  666. x == 0, [x, c, d],
  667. lambda x_, c_, d_: (np.log(c_) + np.log(d_) + sc.xlogy(c_*d_ - 1, x_)
  668. - (d_+1) * sc.log1p(x_**(c_))),
  669. f2 = lambda x_, c_, d_: (np.log(c_) + np.log(d_)
  670. + sc.xlogy(-c_ - 1, x_)
  671. - sc.xlog1py(d_+1, x_**(-c_))))
  672. if output.ndim == 0:
  673. return output[()]
  674. return output
  675. def _cdf(self, x, c, d):
  676. return (1 + x**(-c))**(-d)
  677. def _logcdf(self, x, c, d):
  678. return sc.log1p(x**(-c)) * (-d)
  679. def _sf(self, x, c, d):
  680. return np.exp(self._logsf(x, c, d))
  681. def _logsf(self, x, c, d):
  682. return np.log1p(- (1 + x**(-c))**(-d))
  683. def _ppf(self, q, c, d):
  684. return (q**(-1.0/d) - 1)**(-1.0/c)
  685. def _stats(self, c, d):
  686. nc = np.arange(1, 5).reshape(4,1) / c
  687. #ek is the kth raw moment, e1 is the mean e2-e1**2 variance etc.
  688. e1, e2, e3, e4 = sc.beta(d + nc, 1. - nc) * d
  689. mu = np.where(c > 1.0, e1, np.nan)
  690. mu2_if_c = e2 - mu**2
  691. mu2 = np.where(c > 2.0, mu2_if_c, np.nan)
  692. g1 = _lazywhere(
  693. c > 3.0,
  694. (c, e1, e2, e3, mu2_if_c),
  695. lambda c, e1, e2, e3, mu2_if_c: (e3 - 3*e2*e1 + 2*e1**3) / np.sqrt((mu2_if_c)**3),
  696. fillvalue=np.nan)
  697. g2 = _lazywhere(
  698. c > 4.0,
  699. (c, e1, e2, e3, e4, mu2_if_c),
  700. lambda c, e1, e2, e3, e4, mu2_if_c: (
  701. ((e4 - 4*e3*e1 + 6*e2*e1**2 - 3*e1**4) / mu2_if_c**2) - 3),
  702. fillvalue=np.nan)
  703. if np.ndim(c) == 0:
  704. return mu.item(), mu2.item(), g1.item(), g2.item()
  705. return mu, mu2, g1, g2
  706. def _munp(self, n, c, d):
  707. def __munp(n, c, d):
  708. nc = 1. * n / c
  709. return d * sc.beta(1.0 - nc, d + nc)
  710. n, c, d = np.asarray(n), np.asarray(c), np.asarray(d)
  711. return _lazywhere((c > n) & (n == n) & (d == d), (c, d, n),
  712. lambda c, d, n: __munp(n, c, d),
  713. np.nan)
  714. burr = burr_gen(a=0.0, name='burr')
  715. class burr12_gen(rv_continuous):
  716. r"""A Burr (Type XII) continuous random variable.
  717. %(before_notes)s
  718. See Also
  719. --------
  720. fisk : a special case of either `burr` or `burr12` with ``d=1``
  721. burr : Burr Type III distribution
  722. Notes
  723. -----
  724. The probability density function for `burr` is:
  725. .. math::
  726. f(x, c, d) = c d x^{c-1} / (1 + x^c)^{d + 1}
  727. for :math:`x >= 0` and :math:`c, d > 0`.
  728. `burr12` takes ``c`` and ``d`` as shape parameters for :math:`c`
  729. and :math:`d`.
  730. This is the PDF corresponding to the twelfth CDF given in Burr's list;
  731. specifically, it is equation (20) in Burr's paper [1]_.
  732. %(after_notes)s
  733. The Burr type 12 distribution is also sometimes referred to as
  734. the Singh-Maddala distribution from NIST [2]_.
  735. References
  736. ----------
  737. .. [1] Burr, I. W. "Cumulative frequency functions", Annals of
  738. Mathematical Statistics, 13(2), pp 215-232 (1942).
  739. .. [2] https://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/b12pdf.htm
  740. .. [3] "Burr distribution",
  741. https://en.wikipedia.org/wiki/Burr_distribution
  742. %(example)s
  743. """
  744. def _pdf(self, x, c, d):
  745. # burr12.pdf(x, c, d) = c * d * x**(c-1) * (1+x**(c))**(-d-1)
  746. return np.exp(self._logpdf(x, c, d))
  747. def _logpdf(self, x, c, d):
  748. return np.log(c) + np.log(d) + sc.xlogy(c - 1, x) + sc.xlog1py(-d-1, x**c)
  749. def _cdf(self, x, c, d):
  750. return -sc.expm1(self._logsf(x, c, d))
  751. def _logcdf(self, x, c, d):
  752. return sc.log1p(-(1 + x**c)**(-d))
  753. def _sf(self, x, c, d):
  754. return np.exp(self._logsf(x, c, d))
  755. def _logsf(self, x, c, d):
  756. return sc.xlog1py(-d, x**c)
  757. def _ppf(self, q, c, d):
  758. # The following is an implementation of
  759. # ((1 - q)**(-1.0/d) - 1)**(1.0/c)
  760. # that does a better job handling small values of q.
  761. return sc.expm1(-1/d * sc.log1p(-q))**(1/c)
  762. def _munp(self, n, c, d):
  763. nc = 1. * n / c
  764. return d * sc.beta(1.0 + nc, d - nc)
  765. burr12 = burr12_gen(a=0.0, name='burr12')
  766. class fisk_gen(burr_gen):
  767. r"""A Fisk continuous random variable.
  768. The Fisk distribution is also known as the log-logistic distribution.
  769. %(before_notes)s
  770. See Also
  771. --------
  772. burr
  773. Notes
  774. -----
  775. The probability density function for `fisk` is:
  776. .. math::
  777. f(x, c) = c x^{-c-1} (1 + x^{-c})^{-2}
  778. for :math:`x >= 0` and :math:`c > 0`.
  779. `fisk` takes ``c`` as a shape parameter for :math:`c`.
  780. `fisk` is a special case of `burr` or `burr12` with ``d=1``.
  781. %(after_notes)s
  782. %(example)s
  783. """
  784. def _pdf(self, x, c):
  785. # fisk.pdf(x, c) = c * x**(-c-1) * (1 + x**(-c))**(-2)
  786. return burr._pdf(x, c, 1.0)
  787. def _cdf(self, x, c):
  788. return burr._cdf(x, c, 1.0)
  789. def _sf(self, x, c):
  790. return burr._sf(x, c, 1.0)
  791. def _logpdf(self, x, c):
  792. # fisk.pdf(x, c) = c * x**(-c-1) * (1 + x**(-c))**(-2)
  793. return burr._logpdf(x, c, 1.0)
  794. def _logcdf(self, x, c):
  795. return burr._logcdf(x, c, 1.0)
  796. def _logsf(self, x, c):
  797. return burr._logsf(x, c, 1.0)
  798. def _ppf(self, x, c):
  799. return burr._ppf(x, c, 1.0)
  800. def _munp(self, n, c):
  801. return burr._munp(n, c, 1.0)
  802. def _stats(self, c):
  803. return burr._stats(c, 1.0)
  804. def _entropy(self, c):
  805. return 2 - np.log(c)
  806. fisk = fisk_gen(a=0.0, name='fisk')
  807. class cauchy_gen(rv_continuous):
  808. r"""A Cauchy continuous random variable.
  809. %(before_notes)s
  810. Notes
  811. -----
  812. The probability density function for `cauchy` is
  813. .. math::
  814. f(x) = \frac{1}{\pi (1 + x^2)}
  815. for a real number :math:`x`.
  816. %(after_notes)s
  817. %(example)s
  818. """
  819. def _pdf(self, x):
  820. # cauchy.pdf(x) = 1 / (pi * (1 + x**2))
  821. return 1.0/np.pi/(1.0+x*x)
  822. def _cdf(self, x):
  823. return 0.5 + 1.0/np.pi*np.arctan(x)
  824. def _ppf(self, q):
  825. return np.tan(np.pi*q-np.pi/2.0)
  826. def _sf(self, x):
  827. return 0.5 - 1.0/np.pi*np.arctan(x)
  828. def _isf(self, q):
  829. return np.tan(np.pi/2.0-np.pi*q)
  830. def _stats(self):
  831. return np.nan, np.nan, np.nan, np.nan
  832. def _entropy(self):
  833. return np.log(4*np.pi)
  834. def _fitstart(self, data, args=None):
  835. # Initialize ML guesses using quartiles instead of moments.
  836. p25, p50, p75 = np.percentile(data, [25, 50, 75])
  837. return p50, (p75 - p25)/2
  838. cauchy = cauchy_gen(name='cauchy')
  839. class chi_gen(rv_continuous):
  840. r"""A chi continuous random variable.
  841. %(before_notes)s
  842. Notes
  843. -----
  844. The probability density function for `chi` is:
  845. .. math::
  846. f(x, k) = \frac{1}{2^{k/2-1} \Gamma \left( k/2 \right)}
  847. x^{k-1} \exp \left( -x^2/2 \right)
  848. for :math:`x >= 0` and :math:`k > 0` (degrees of freedom, denoted ``df``
  849. in the implementation). :math:`\Gamma` is the gamma function
  850. (`scipy.special.gamma`).
  851. Special cases of `chi` are:
  852. - ``chi(1, loc, scale)`` is equivalent to `halfnorm`
  853. - ``chi(2, 0, scale)`` is equivalent to `rayleigh`
  854. - ``chi(3, 0, scale)`` is equivalent to `maxwell`
  855. `chi` takes ``df`` as a shape parameter.
  856. %(after_notes)s
  857. %(example)s
  858. """
  859. def _rvs(self, df, size=None, random_state=None):
  860. return np.sqrt(chi2.rvs(df, size=size, random_state=random_state))
  861. def _pdf(self, x, df):
  862. # x**(df-1) * exp(-x**2/2)
  863. # chi.pdf(x, df) = -------------------------
  864. # 2**(df/2-1) * gamma(df/2)
  865. return np.exp(self._logpdf(x, df))
  866. def _logpdf(self, x, df):
  867. l = np.log(2) - .5*np.log(2)*df - sc.gammaln(.5*df)
  868. return l + sc.xlogy(df - 1., x) - .5*x**2
  869. def _cdf(self, x, df):
  870. return sc.gammainc(.5*df, .5*x**2)
  871. def _sf(self, x, df):
  872. return sc.gammaincc(.5*df, .5*x**2)
  873. def _ppf(self, q, df):
  874. return np.sqrt(2*sc.gammaincinv(.5*df, q))
  875. def _isf(self, q, df):
  876. return np.sqrt(2*sc.gammainccinv(.5*df, q))
  877. def _stats(self, df):
  878. mu = np.sqrt(2)*sc.gamma(df/2.0+0.5)/sc.gamma(df/2.0)
  879. mu2 = df - mu*mu
  880. g1 = (2*mu**3.0 + mu*(1-2*df))/np.asarray(np.power(mu2, 1.5))
  881. g2 = 2*df*(1.0-df)-6*mu**4 + 4*mu**2 * (2*df-1)
  882. g2 /= np.asarray(mu2**2.0)
  883. return mu, mu2, g1, g2
  884. chi = chi_gen(a=0.0, name='chi')
  885. class chi2_gen(rv_continuous):
  886. r"""A chi-squared continuous random variable.
  887. For the noncentral chi-square distribution, see `ncx2`.
  888. %(before_notes)s
  889. See Also
  890. --------
  891. ncx2
  892. Notes
  893. -----
  894. The probability density function for `chi2` is:
  895. .. math::
  896. f(x, k) = \frac{1}{2^{k/2} \Gamma \left( k/2 \right)}
  897. x^{k/2-1} \exp \left( -x/2 \right)
  898. for :math:`x > 0` and :math:`k > 0` (degrees of freedom, denoted ``df``
  899. in the implementation).
  900. `chi2` takes ``df`` as a shape parameter.
  901. The chi-squared distribution is a special case of the gamma
  902. distribution, with gamma parameters ``a = df/2``, ``loc = 0`` and
  903. ``scale = 2``.
  904. %(after_notes)s
  905. %(example)s
  906. """
  907. def _rvs(self, df, size=None, random_state=None):
  908. return random_state.chisquare(df, size)
  909. def _pdf(self, x, df):
  910. # chi2.pdf(x, df) = 1 / (2*gamma(df/2)) * (x/2)**(df/2-1) * exp(-x/2)
  911. return np.exp(self._logpdf(x, df))
  912. def _logpdf(self, x, df):
  913. return sc.xlogy(df/2.-1, x) - x/2. - sc.gammaln(df/2.) - (np.log(2)*df)/2.
  914. def _cdf(self, x, df):
  915. return sc.chdtr(df, x)
  916. def _sf(self, x, df):
  917. return sc.chdtrc(df, x)
  918. def _isf(self, p, df):
  919. return sc.chdtri(df, p)
  920. def _ppf(self, p, df):
  921. return 2*sc.gammaincinv(df/2, p)
  922. def _stats(self, df):
  923. mu = df
  924. mu2 = 2*df
  925. g1 = 2*np.sqrt(2.0/df)
  926. g2 = 12.0/df
  927. return mu, mu2, g1, g2
  928. chi2 = chi2_gen(a=0.0, name='chi2')
  929. class cosine_gen(rv_continuous):
  930. r"""A cosine continuous random variable.
  931. %(before_notes)s
  932. Notes
  933. -----
  934. The cosine distribution is an approximation to the normal distribution.
  935. The probability density function for `cosine` is:
  936. .. math::
  937. f(x) = \frac{1}{2\pi} (1+\cos(x))
  938. for :math:`-\pi \le x \le \pi`.
  939. %(after_notes)s
  940. %(example)s
  941. """
  942. def _pdf(self, x):
  943. # cosine.pdf(x) = 1/(2*pi) * (1+cos(x))
  944. return 1.0/2/np.pi*(1+np.cos(x))
  945. def _cdf(self, x):
  946. return scu._cosine_cdf(x)
  947. def _sf(self, x):
  948. return scu._cosine_cdf(-x)
  949. def _ppf(self, p):
  950. return scu._cosine_invcdf(p)
  951. def _isf(self, p):
  952. return -scu._cosine_invcdf(p)
  953. def _stats(self):
  954. return 0.0, np.pi*np.pi/3.0-2.0, 0.0, -6.0*(np.pi**4-90)/(5.0*(np.pi*np.pi-6)**2)
  955. def _entropy(self):
  956. return np.log(4*np.pi)-1.0
  957. cosine = cosine_gen(a=-np.pi, b=np.pi, name='cosine')
  958. class dgamma_gen(rv_continuous):
  959. r"""A double gamma continuous random variable.
  960. %(before_notes)s
  961. Notes
  962. -----
  963. The probability density function for `dgamma` is:
  964. .. math::
  965. f(x, a) = \frac{1}{2\Gamma(a)} |x|^{a-1} \exp(-|x|)
  966. for a real number :math:`x` and :math:`a > 0`. :math:`\Gamma` is the
  967. gamma function (`scipy.special.gamma`).
  968. `dgamma` takes ``a`` as a shape parameter for :math:`a`.
  969. %(after_notes)s
  970. %(example)s
  971. """
  972. def _rvs(self, a, size=None, random_state=None):
  973. u = random_state.uniform(size=size)
  974. gm = gamma.rvs(a, size=size, random_state=random_state)
  975. return gm * np.where(u >= 0.5, 1, -1)
  976. def _pdf(self, x, a):
  977. # dgamma.pdf(x, a) = 1 / (2*gamma(a)) * abs(x)**(a-1) * exp(-abs(x))
  978. ax = abs(x)
  979. return 1.0/(2*sc.gamma(a))*ax**(a-1.0) * np.exp(-ax)
  980. def _logpdf(self, x, a):
  981. ax = abs(x)
  982. return sc.xlogy(a - 1.0, ax) - ax - np.log(2) - sc.gammaln(a)
  983. def _cdf(self, x, a):
  984. fac = 0.5*sc.gammainc(a, abs(x))
  985. return np.where(x > 0, 0.5 + fac, 0.5 - fac)
  986. def _sf(self, x, a):
  987. fac = 0.5*sc.gammainc(a, abs(x))
  988. return np.where(x > 0, 0.5-fac, 0.5+fac)
  989. def _ppf(self, q, a):
  990. fac = sc.gammainccinv(a, 1-abs(2*q-1))
  991. return np.where(q > 0.5, fac, -fac)
  992. def _stats(self, a):
  993. mu2 = a*(a+1.0)
  994. return 0.0, mu2, 0.0, (a+2.0)*(a+3.0)/mu2-3.0
  995. dgamma = dgamma_gen(name='dgamma')
  996. class dweibull_gen(rv_continuous):
  997. r"""A double Weibull continuous random variable.
  998. %(before_notes)s
  999. Notes
  1000. -----
  1001. The probability density function for `dweibull` is given by
  1002. .. math::
  1003. f(x, c) = c / 2 |x|^{c-1} \exp(-|x|^c)
  1004. for a real number :math:`x` and :math:`c > 0`.
  1005. `dweibull` takes ``c`` as a shape parameter for :math:`c`.
  1006. %(after_notes)s
  1007. %(example)s
  1008. """
  1009. def _rvs(self, c, size=None, random_state=None):
  1010. u = random_state.uniform(size=size)
  1011. w = weibull_min.rvs(c, size=size, random_state=random_state)
  1012. return w * (np.where(u >= 0.5, 1, -1))
  1013. def _pdf(self, x, c):
  1014. # dweibull.pdf(x, c) = c / 2 * abs(x)**(c-1) * exp(-abs(x)**c)
  1015. ax = abs(x)
  1016. Px = c / 2.0 * ax**(c-1.0) * np.exp(-ax**c)
  1017. return Px
  1018. def _logpdf(self, x, c):
  1019. ax = abs(x)
  1020. return np.log(c) - np.log(2.0) + sc.xlogy(c - 1.0, ax) - ax**c
  1021. def _cdf(self, x, c):
  1022. Cx1 = 0.5 * np.exp(-abs(x)**c)
  1023. return np.where(x > 0, 1 - Cx1, Cx1)
  1024. def _ppf(self, q, c):
  1025. fac = 2. * np.where(q <= 0.5, q, 1. - q)
  1026. fac = np.power(-np.log(fac), 1.0 / c)
  1027. return np.where(q > 0.5, fac, -fac)
  1028. def _munp(self, n, c):
  1029. return (1 - (n % 2)) * sc.gamma(1.0 + 1.0 * n / c)
  1030. # since we know that all odd moments are zeros, return them at once.
  1031. # returning Nones from _stats makes the public stats call _munp
  1032. # so overall we're saving one or two gamma function evaluations here.
  1033. def _stats(self, c):
  1034. return 0, None, 0, None
  1035. dweibull = dweibull_gen(name='dweibull')
  1036. class expon_gen(rv_continuous):
  1037. r"""An exponential continuous random variable.
  1038. %(before_notes)s
  1039. Notes
  1040. -----
  1041. The probability density function for `expon` is:
  1042. .. math::
  1043. f(x) = \exp(-x)
  1044. for :math:`x \ge 0`.
  1045. %(after_notes)s
  1046. A common parameterization for `expon` is in terms of the rate parameter
  1047. ``lambda``, such that ``pdf = lambda * exp(-lambda * x)``. This
  1048. parameterization corresponds to using ``scale = 1 / lambda``.
  1049. The exponential distribution is a special case of the gamma
  1050. distributions, with gamma shape parameter ``a = 1``.
  1051. %(example)s
  1052. """
  1053. def _rvs(self, size=None, random_state=None):
  1054. return random_state.standard_exponential(size)
  1055. def _pdf(self, x):
  1056. # expon.pdf(x) = exp(-x)
  1057. return np.exp(-x)
  1058. def _logpdf(self, x):
  1059. return -x
  1060. def _cdf(self, x):
  1061. return -sc.expm1(-x)
  1062. def _ppf(self, q):
  1063. return -sc.log1p(-q)
  1064. def _sf(self, x):
  1065. return np.exp(-x)
  1066. def _logsf(self, x):
  1067. return -x
  1068. def _isf(self, q):
  1069. return -np.log(q)
  1070. def _stats(self):
  1071. return 1.0, 1.0, 2.0, 6.0
  1072. def _entropy(self):
  1073. return 1.0
  1074. @_call_super_mom
  1075. @replace_notes_in_docstring(rv_continuous, notes="""\
  1076. When `method='MLE'`,
  1077. this function uses explicit formulas for the maximum likelihood
  1078. estimation of the exponential distribution parameters, so the
  1079. `optimizer`, `loc` and `scale` keyword arguments are
  1080. ignored.\n\n""")
  1081. def fit(self, data, *args, **kwds):
  1082. if len(args) > 0:
  1083. raise TypeError("Too many arguments.")
  1084. floc = kwds.pop('floc', None)
  1085. fscale = kwds.pop('fscale', None)
  1086. _remove_optimizer_parameters(kwds)
  1087. if floc is not None and fscale is not None:
  1088. # This check is for consistency with `rv_continuous.fit`.
  1089. raise ValueError("All parameters fixed. There is nothing to "
  1090. "optimize.")
  1091. data = np.asarray(data)
  1092. if not np.isfinite(data).all():
  1093. raise RuntimeError("The data contains non-finite values.")
  1094. data_min = data.min()
  1095. if floc is None:
  1096. # ML estimate of the location is the minimum of the data.
  1097. loc = data_min
  1098. else:
  1099. loc = floc
  1100. if data_min < loc:
  1101. # There are values that are less than the specified loc.
  1102. raise FitDataError("expon", lower=floc, upper=np.inf)
  1103. if fscale is None:
  1104. # ML estimate of the scale is the shifted mean.
  1105. scale = data.mean() - loc
  1106. else:
  1107. scale = fscale
  1108. # We expect the return values to be floating point, so ensure it
  1109. # by explicitly converting to float.
  1110. return float(loc), float(scale)
  1111. expon = expon_gen(a=0.0, name='expon')
  1112. class exponnorm_gen(rv_continuous):
  1113. r"""An exponentially modified Normal continuous random variable.
  1114. Also known as the exponentially modified Gaussian distribution [1]_.
  1115. %(before_notes)s
  1116. Notes
  1117. -----
  1118. The probability density function for `exponnorm` is:
  1119. .. math::
  1120. f(x, K) = \frac{1}{2K} \exp\left(\frac{1}{2 K^2} - x / K \right)
  1121. \text{erfc}\left(-\frac{x - 1/K}{\sqrt{2}}\right)
  1122. where :math:`x` is a real number and :math:`K > 0`.
  1123. It can be thought of as the sum of a standard normal random variable
  1124. and an independent exponentially distributed random variable with rate
  1125. ``1/K``.
  1126. %(after_notes)s
  1127. An alternative parameterization of this distribution (for example, in
  1128. the Wikpedia article [1]_) involves three parameters, :math:`\mu`,
  1129. :math:`\lambda` and :math:`\sigma`.
  1130. In the present parameterization this corresponds to having ``loc`` and
  1131. ``scale`` equal to :math:`\mu` and :math:`\sigma`, respectively, and
  1132. shape parameter :math:`K = 1/(\sigma\lambda)`.
  1133. .. versionadded:: 0.16.0
  1134. References
  1135. ----------
  1136. .. [1] Exponentially modified Gaussian distribution, Wikipedia,
  1137. https://en.wikipedia.org/wiki/Exponentially_modified_Gaussian_distribution
  1138. %(example)s
  1139. """
  1140. def _rvs(self, K, size=None, random_state=None):
  1141. expval = random_state.standard_exponential(size) * K
  1142. gval = random_state.standard_normal(size)
  1143. return expval + gval
  1144. def _pdf(self, x, K):
  1145. return np.exp(self._logpdf(x, K))
  1146. def _logpdf(self, x, K):
  1147. invK = 1.0 / K
  1148. exparg = invK * (0.5 * invK - x)
  1149. return exparg + _norm_logcdf(x - invK) - np.log(K)
  1150. def _cdf(self, x, K):
  1151. invK = 1.0 / K
  1152. expval = invK * (0.5 * invK - x)
  1153. logprod = expval + _norm_logcdf(x - invK)
  1154. return _norm_cdf(x) - np.exp(logprod)
  1155. def _sf(self, x, K):
  1156. invK = 1.0 / K
  1157. expval = invK * (0.5 * invK - x)
  1158. logprod = expval + _norm_logcdf(x - invK)
  1159. return _norm_cdf(-x) + np.exp(logprod)
  1160. def _stats(self, K):
  1161. K2 = K * K
  1162. opK2 = 1.0 + K2
  1163. skw = 2 * K**3 * opK2**(-1.5)
  1164. krt = 6.0 * K2 * K2 * opK2**(-2)
  1165. return K, opK2, skw, krt
  1166. exponnorm = exponnorm_gen(name='exponnorm')
  1167. class exponweib_gen(rv_continuous):
  1168. r"""An exponentiated Weibull continuous random variable.
  1169. %(before_notes)s
  1170. See Also
  1171. --------
  1172. weibull_min, numpy.random.Generator.weibull
  1173. Notes
  1174. -----
  1175. The probability density function for `exponweib` is:
  1176. .. math::
  1177. f(x, a, c) = a c [1-\exp(-x^c)]^{a-1} \exp(-x^c) x^{c-1}
  1178. and its cumulative distribution function is:
  1179. .. math::
  1180. F(x, a, c) = [1-\exp(-x^c)]^a
  1181. for :math:`x > 0`, :math:`a > 0`, :math:`c > 0`.
  1182. `exponweib` takes :math:`a` and :math:`c` as shape parameters:
  1183. * :math:`a` is the exponentiation parameter,
  1184. with the special case :math:`a=1` corresponding to the
  1185. (non-exponentiated) Weibull distribution `weibull_min`.
  1186. * :math:`c` is the shape parameter of the non-exponentiated Weibull law.
  1187. %(after_notes)s
  1188. References
  1189. ----------
  1190. https://en.wikipedia.org/wiki/Exponentiated_Weibull_distribution
  1191. %(example)s
  1192. """
  1193. def _pdf(self, x, a, c):
  1194. # exponweib.pdf(x, a, c) =
  1195. # a * c * (1-exp(-x**c))**(a-1) * exp(-x**c)*x**(c-1)
  1196. return np.exp(self._logpdf(x, a, c))
  1197. def _logpdf(self, x, a, c):
  1198. negxc = -x**c
  1199. exm1c = -sc.expm1(negxc)
  1200. logp = (np.log(a) + np.log(c) + sc.xlogy(a - 1.0, exm1c) +
  1201. negxc + sc.xlogy(c - 1.0, x))
  1202. return logp
  1203. def _cdf(self, x, a, c):
  1204. exm1c = -sc.expm1(-x**c)
  1205. return exm1c**a
  1206. def _ppf(self, q, a, c):
  1207. return (-sc.log1p(-q**(1.0/a)))**np.asarray(1.0/c)
  1208. exponweib = exponweib_gen(a=0.0, name='exponweib')
  1209. class exponpow_gen(rv_continuous):
  1210. r"""An exponential power continuous random variable.
  1211. %(before_notes)s
  1212. Notes
  1213. -----
  1214. The probability density function for `exponpow` is:
  1215. .. math::
  1216. f(x, b) = b x^{b-1} \exp(1 + x^b - \exp(x^b))
  1217. for :math:`x \ge 0`, :math:`b > 0`. Note that this is a different
  1218. distribution from the exponential power distribution that is also known
  1219. under the names "generalized normal" or "generalized Gaussian".
  1220. `exponpow` takes ``b`` as a shape parameter for :math:`b`.
  1221. %(after_notes)s
  1222. References
  1223. ----------
  1224. http://www.math.wm.edu/~leemis/chart/UDR/PDFs/Exponentialpower.pdf
  1225. %(example)s
  1226. """
  1227. def _pdf(self, x, b):
  1228. # exponpow.pdf(x, b) = b * x**(b-1) * exp(1 + x**b - exp(x**b))
  1229. return np.exp(self._logpdf(x, b))
  1230. def _logpdf(self, x, b):
  1231. xb = x**b
  1232. f = 1 + np.log(b) + sc.xlogy(b - 1.0, x) + xb - np.exp(xb)
  1233. return f
  1234. def _cdf(self, x, b):
  1235. return -sc.expm1(-sc.expm1(x**b))
  1236. def _sf(self, x, b):
  1237. return np.exp(-sc.expm1(x**b))
  1238. def _isf(self, x, b):
  1239. return (sc.log1p(-np.log(x)))**(1./b)
  1240. def _ppf(self, q, b):
  1241. return pow(sc.log1p(-sc.log1p(-q)), 1.0/b)
  1242. exponpow = exponpow_gen(a=0.0, name='exponpow')
  1243. class fatiguelife_gen(rv_continuous):
  1244. r"""A fatigue-life (Birnbaum-Saunders) continuous random variable.
  1245. %(before_notes)s
  1246. Notes
  1247. -----
  1248. The probability density function for `fatiguelife` is:
  1249. .. math::
  1250. f(x, c) = \frac{x+1}{2c\sqrt{2\pi x^3}} \exp(-\frac{(x-1)^2}{2x c^2})
  1251. for :math:`x >= 0` and :math:`c > 0`.
  1252. `fatiguelife` takes ``c`` as a shape parameter for :math:`c`.
  1253. %(after_notes)s
  1254. References
  1255. ----------
  1256. .. [1] "Birnbaum-Saunders distribution",
  1257. https://en.wikipedia.org/wiki/Birnbaum-Saunders_distribution
  1258. %(example)s
  1259. """
  1260. _support_mask = rv_continuous._open_support_mask
  1261. def _rvs(self, c, size=None, random_state=None):
  1262. z = random_state.standard_normal(size)
  1263. x = 0.5*c*z
  1264. x2 = x*x
  1265. t = 1.0 + 2*x2 + 2*x*np.sqrt(1 + x2)
  1266. return t
  1267. def _pdf(self, x, c):
  1268. # fatiguelife.pdf(x, c) =
  1269. # (x+1) / (2*c*sqrt(2*pi*x**3)) * exp(-(x-1)**2/(2*x*c**2))
  1270. return np.exp(self._logpdf(x, c))
  1271. def _logpdf(self, x, c):
  1272. return (np.log(x+1) - (x-1)**2 / (2.0*x*c**2) - np.log(2*c) -
  1273. 0.5*(np.log(2*np.pi) + 3*np.log(x)))
  1274. def _cdf(self, x, c):
  1275. return _norm_cdf(1.0 / c * (np.sqrt(x) - 1.0/np.sqrt(x)))
  1276. def _ppf(self, q, c):
  1277. tmp = c*sc.ndtri(q)
  1278. return 0.25 * (tmp + np.sqrt(tmp**2 + 4))**