Неполная гамма-функция в питоне?
scipy.special.gammainc не может принимать отрицательные значения для первого аргумента. Есть ли другие реализации, которые могли бы в Python? Я могу сделать ручную интеграцию наверняка, но я хотел бы знать, есть ли хорошие альтернативы, которые уже существуют.
Correct result: 1 - Gamma[-1,1] = 0.85 Use Scipy: scipy.special.gammainc(-1, 1) = 0
3 ответа
Я обычно обращаюсь к mpmath всякий раз, когда мне нужны специальные функции, и я не слишком беспокоюсь о производительности. (Хотя его производительность во многих случаях довольно хорошая в любом случае.)
>>> import mpmath >>> mpmath.gammainc(-1,1) mpf('0.14849550677592205') >>> 1-mpmath.gammainc(-1,1) mpf('0.85150449322407795') >>> mpmath.mp.dps = 50 # arbitrary precision! >>> 1-mpmath.gammainc(-1,1) mpf('0.85150449322407795208164000529866078158523616237514084')
У меня просто была та же проблема, и в итоге я использовал рекуррентные отношения для функции, когда a 2
По-прежнему проблема в 2021 году, и они до сих пор не улучшили ее в scipy. Особенно расстраивает то, что scipy не предоставляет даже нерегулярных версий верхней и нижней неполных функций гаммы. Я также закончил использовать, который использует свой собственный тип данных (здесь mpf для плавающего mpmath — который поддерживает произвольную точность). Чтобы быстро приготовить что-нибудь для верхней и нижней неполной функции гаммы, которая работает с numpy массивы, и это ведет себя так, как и следовало ожидать от вычисления этих интегралов, я пришел к следующему:
import numpy as np from mpmath import gammainc """ In both functinos below a is a float and z is a numpy.array. """ def gammainc_up(a,z): return np.asarray([gammainc(a, zi, regularized=False) for zi in z]).astype(float) def gammainc_low(a,z): return np.asarray([gamainc(a, 0, zi, regularized=False) for zi in z]).astype(float)
Заметим еще раз, что это для функций (уравнения 8.2.1 и 8.2.2 в нерегуляризованныхDLMF ), регуляризованные функции (уравнения 8.2.3 и 8.2.4) могут быть получены в mpmath установив ключевое слово regularized=True .
scipy.special.gamma#
for \(\Re(z) > 0\) and is extended to the rest of the complex plane by analytic continuation. See [dlmf] for more details.
Parameters : z array_like
Real or complex valued argument
out ndarray, optional
Optional output array for the function values
Returns : scalar or ndarray
Values of the gamma function
The gamma function is often referred to as the generalized factorial since \(\Gamma(n + 1) = n!\) for natural numbers \(n\) . More generally it satisfies the recurrence relation \(\Gamma(z + 1) = z \cdot \Gamma(z)\) for complex \(z\) , which, combined with the fact that \(\Gamma(1) = 1\) , implies the above identity for \(z = n\) .
NIST Digital Library of Mathematical Functions https://dlmf.nist.gov/5.2#E1
>>> import numpy as np >>> from scipy.special import gamma, factorial
>>> gamma([0, 0.5, 1, 5]) array([ inf, 1.77245385, 1. , 24. ])
>>> z = 2.5 + 1j >>> gamma(z) (0.77476210455108352+0.70763120437959293j) >>> gamma(z+1), z*gamma(z) # Recurrence property ((1.2292740569981171+2.5438401155000685j), (1.2292740569981158+2.5438401155000658j))
>>> gamma(0.5)**2 # gamma(0.5) = sqrt(pi) 3.1415926535897927
>>> x = np.linspace(-3.5, 5.5, 2251) >>> y = gamma(x)
>>> import matplotlib.pyplot as plt >>> plt.plot(x, y, 'b', alpha=0.6, label='gamma(x)') >>> k = np.arange(1, 7) >>> plt.plot(k, factorial(k-1), 'k*', alpha=0.6, . label='(x-1)!, x = 1, 2, . ') >>> plt.xlim(-3.5, 5.5) >>> plt.ylim(-10, 25) >>> plt.grid() >>> plt.xlabel('x') >>> plt.legend(loc='lower right') >>> plt.show()
scipy.stats.gamma#
As an instance of the rv_continuous class, gamma object inherits from it a collection of generic methods (see below for the full list), and completes them with details specific for this particular distribution.
The probability density function for gamma is:
for \(x \ge 0\) , \(a > 0\) . Here \(\Gamma(a)\) refers to the gamma function.
gamma takes a as a shape parameter for \(a\) .
When \(a\) is an integer, gamma reduces to the Erlang distribution, and when \(a=1\) to the exponential distribution.
Gamma distributions are sometimes parameterized with two variables, with a probability density function of:
Note that this parameterization is equivalent to the above, with scale = 1 / beta .
The probability density above is defined in the “standardized” form. To shift and/or scale the distribution use the loc and scale parameters. Specifically, gamma.pdf(x, a, loc, scale) is identically equivalent to gamma.pdf(y, a) / scale with y = (x — loc) / scale . Note that shifting the location of a distribution does not make it a “noncentral” distribution; noncentral generalizations of some distributions are available in separate classes.
>>> import numpy as np >>> from scipy.stats import gamma >>> import matplotlib.pyplot as plt >>> fig, ax = plt.subplots(1, 1)
Calculate the first four moments:
>>> a = 1.99 >>> mean, var, skew, kurt = gamma.stats(a, moments='mvsk')
Display the probability density function ( pdf ):
>>> x = np.linspace(gamma.ppf(0.01, a), . gamma.ppf(0.99, a), 100) >>> ax.plot(x, gamma.pdf(x, a), . 'r-', lw=5, alpha=0.6, label='gamma pdf')
Alternatively, the distribution object can be called (as a function) to fix the shape, location and scale parameters. This returns a “frozen” RV object holding the given parameters fixed.
Freeze the distribution and display the frozen pdf :
>>> rv = gamma(a) >>> ax.plot(x, rv.pdf(x), 'k-', lw=2, label='frozen pdf')
Check accuracy of cdf and ppf :
>>> vals = gamma.ppf([0.001, 0.5, 0.999], a) >>> np.allclose([0.001, 0.5, 0.999], gamma.cdf(vals, a)) True
And compare the histogram:
>>> ax.hist(r, density=True, bins='auto', histtype='stepfilled', alpha=0.2) >>> ax.set_xlim([x[0], x[-1]]) >>> ax.legend(loc='best', frameon=False) >>> plt.show()
rvs(a, loc=0, scale=1, size=1, random_state=None)
pdf(x, a, loc=0, scale=1)
Probability density function.
logpdf(x, a, loc=0, scale=1)
Log of the probability density function.
cdf(x, a, loc=0, scale=1)
Cumulative distribution function.
logcdf(x, a, loc=0, scale=1)
Log of the cumulative distribution function.
sf(x, a, loc=0, scale=1)
Survival function (also defined as 1 — cdf , but sf is sometimes more accurate).
logsf(x, a, loc=0, scale=1)
Log of the survival function.
ppf(q, a, loc=0, scale=1)
Percent point function (inverse of cdf — percentiles).
isf(q, a, loc=0, scale=1)
Inverse survival function (inverse of sf ).
moment(order, a, loc=0, scale=1)
Non-central moment of the specified order.
stats(a, loc=0, scale=1, moments=’mv’)
Mean(‘m’), variance(‘v’), skew(‘s’), and/or kurtosis(‘k’).
entropy(a, loc=0, scale=1)
(Differential) entropy of the RV.
Parameter estimates for generic data. See scipy.stats.rv_continuous.fit for detailed documentation of the keyword arguments.
expect(func, args=(a,), loc=0, scale=1, lb=None, ub=None, conditional=False, **kwds)
Expected value of a function (of one argument) with respect to the distribution.
median(a, loc=0, scale=1)
Median of the distribution.
mean(a, loc=0, scale=1)
var(a, loc=0, scale=1)
Variance of the distribution.
std(a, loc=0, scale=1)
Standard deviation of the distribution.
interval(confidence, a, loc=0, scale=1)
Confidence interval with equal areas around the median.
неполная гамма-функция в питоне?
что собой представляет scipy.special.gammainc не может принимать отрицательные значения для первого аргумента. Есть ли другие реализации, которые могут быть реализованы в python? Я точно могу выполнить ручную интеграцию, но я хотел бы знать, есть ли уже существующие хорошие альтернативы.
Correct result: 1 - Gamma[-1,1] = 0.85 Use Scipy: scipy.special.gammainc(-1, 1) = 0
3 ответы
я обычно тянусь к математика всякий раз, когда мне нужны специальные функции, и я не слишком беспокоюсь о производительности. (Хотя его производительность во многих случаях в любом случае довольно хороша.)
>>> import mpmath >>> mpmath.gammainc(-1,1) mpf('0.14849550677592205') >>> 1-mpmath.gammainc(-1,1) mpf('0.85150449322407795') >>> mpmath.mp.dps = 50 # arbitrary precision! >>> 1-mpmath.gammainc(-1,1) mpf('0.85150449322407795208164000529866078158523616237514084')
спасибо, я провел краткий поиск в Интернете, но не смог найти автономное решение. Думаю, это один из немногих случаев, когда я устанавливаю дополнительный пакет для одной функции 😉 — nye17
У меня была такая же проблема, и в итоге я использовал рекуррентные отношения для функции, когда a
Также обратите внимание, что scipy-функции gammainc и gammaincc дают регуляризованные формы Gamma(a,x)/Gamma(a)
Все еще проблема в 2021 году, и они до сих пор не улучшили это в scipy. Особенно обидно, что scipy даже не предоставляет нерегулярные версии верхней и нижней неполных гамма-функций. Я также закончил тем, что использовал mpmath , который использует свой собственный тип данных (здесь mpf для mpmath с плавающей запятой, которая поддерживает произвольную точность). Для того, чтобы быстро состряпать что-то для верхней и нижней незавершенной Гамма-функции, работающей с numpy массивы, и это ведет себя так, как можно было бы ожидать от оценки этих интегралов, я пришел к следующему:
import numpy as np from mpmath import gammainc """ In both functinos below a is a float and z is a numpy.array. """ def gammainc_up(a,z): return np.asarray([gammainc(a, zi, regularized=False) for zi in z]).astype(float) def gammainc_low(a,z): return np.asarray([gamainc(a, 0, zi, regularized=False) for zi in z]).astype(float)
Обратите внимание еще раз, это для нерегуляризованных функций (уравнения 8.2.1 и 8.2.2 в DLMF), регуляризованные функции (уравнения 8.2.3 и 8.2.4) могут быть получены в mpmath установив ключевое слово regularized=True .
Неполная гамма-функция в scipy
Я хотел бы вычислить, что вольфрам-альфа называет неполной гамма-функцией (см. здесь):
Альфа-выход вольфрамма: 1.822 . Единственное, что дает мне scipy , похожее на это, — это scipy.special.gammainc , но у него другой определение, чем то, как wolfram alpha определяет их неполную гамма-функцию.
import scipy scipy.special.gammainc(0, 0.1)
Дает мне nan . Поддерживает ли scipy то, что я ищу?
Версия Sympy (верхняя) неполной гаммы sympy.functions.special.gamma_functions.uppergamma имеет то же определение, что и mathematica.
2 ответа
К сожалению, scipys gammaincc не поддерживает значение a=0 . Но вы можете определить свой собственный inc_gamma :
from scipy.special import gamma, gammaincc, exp1 def inc_gamma(a, x): return exp1(x) if a == 0 else gamma(a)*gammaincc(a, x)
Тогда inc_gamma(0, 0.1) даст вам 1.8229239584193906 .
Согласно http: //docs.scipy .org / doc / scipy-0.14.0 / reference / generated / scipy.special.gammainc.html, первый аргумент должен быть положительным, тогда как у вас ноль; вот почему вы получаете NaN.
Тем не менее, предположим, что вместо этого мы попытаемся вычислить Gamma[0.01,0.1] . В этом случае WolframAlpha возвращает 1.80324 :
Согласно http://mathworld.wolfram.com/IncompleteGammaFunction.html, это верхний неполный Гамма-функция, тогда как то, что выводит Scipy, является масштабированной версией того, что WolframAlpha называет нижней неполной гамма-функцией. Используя тождество в уравнении 10, можно увидеть, что в случаях, когда a> 0, вы можете использовать следующее:
from scipy.special import gammainc from scipy.special import gamma gamma(0.01)*(1 - gammainc(0.01,0.1))
Который возвращает 1.8032413569025461 по согласованию с WolframAlpha.
Короче говоря, Gamma[a,x] в WolframAlpha соответствует gamma(a)*(1-gammainc(a,x)) в Scipy при условии, что a>0 .