Python(Scipy):查找高斯分布的尺度参数(标准偏差)

时间:2016-03-22 15:49:19

标签: python-2.7 scipy statistics

在概率密度函数(PDF)中计算值的概率密度是很常见的。想象一下,我们有一个高斯分布,均值= 40,标准差为5,现在想得到值为32的概率密度。我们会这样:

In [1]: import scipy.stats as stats
In [2]: print stats.norm.pdf(32, loc=40, scale=5)
Out [2]: 0.022

- >概率密度为2.2%。

但现在,让我们考虑反问题。我有平均值,我的概率密度值为0.05,我希望得到标准偏差(即比例参数)。

我可以实现的是一种数值方法:在逐步增加scale-parameter的情况下多次创建stats.norm.pdf,并使结果尽可能接近结果。

在我的情况下,我将值30指定为5%标记。所以我需要解决这个“等式”:

stats.norm.pdf(30, loc=40, scale=X) = 0.05

有一个名为“ppf”的scipy函数,它是PDF的反函数,因此它将返回特定概率密度的值,但我还没有找到一个函数来返回 scale参数

实现迭代会花费太多时间(创建和计算)。我的脚本将是巨大的,所以我应该节省计算时间。在这种情况下,lambda函数能帮助吗?我大致知道它在做什么,但到目前为止我还没有使用它。关于这个的任何想法?

谢谢!

2 个答案:

答案 0 :(得分:2)

normal probability density函数f

提供

enter image description here

我们希望为f解决x。让我们问sympy它是否可以解决这个等式:

import sympy as sy
from sympy.abc import x, y, sigma

expr = (1/(sy.sqrt(2*sy.pi)*sigma) * sy.exp(-x**2/(2*sigma**2))) - y
ans = sy.solve(expr, sigma)[0]
print(ans)
# sqrt(2)*exp(LambertW(-2*pi*x**2*y**2)/2)/(2*sqrt(pi)*y)

所以看来有LambertW functionW的封闭式解决方案,满足

z = W(z) * exp(W(z))

适用于所有复数值z

我们可以使用sympy来查找给定xy的数值结果,但是 也许用数字工作会更快 scipy.special.lambertw

import numpy as np
import scipy.special as special

def sigma_func(x, y):
    results = set([np.real_if_close(
        np.sqrt(2)*np.exp(special.lambertw(-2*np.pi*x**2*y**2, k=k)/2)
        /(2*np.sqrt(np.pi)*y)).item() for k in (0, -1)])
    results = [s for s in results if np.isreal(s)]
    return results

通常,LambertW函数返回复数值,但我们只是 对sigma的实值解决方案感兴趣。 Per the docs, 在special.lambertwk=0时,k=1有两个部分真实的分支。所以 上面的代码检查返回的值(对于那两个分支)是否真实,以及 返回任何真实解决方案的列表(如果存在)。如果没有真正的解决方案, 然后返回一个空列表。如果pdf值y不是,则会发生这种情况 达到西格玛的任何实际价值(对于x的给定值。)

你可以像这样使用它:

x = 30.0
loc = 40.0
y = 0.02
s = sigma_func(loc-x, y)
print(s)
# [16.65817044316178, 6.830458938511113]

import scipy.stats as stats
for si in s:
    assert np.allclose(stats.norm.pdf(x, loc=loc, scale=si), y)

在您给出的示例y = 0.025中,sigma没有解决方案:

import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt

x = 30.0
loc = 40.0
y = 0.025
s = np.linspace(5, 20, 100)
plt.plot(s, stats.norm.pdf(x, loc=loc, scale=s))
plt.hlines(y, 4, 20, color='red')  # the horizontal line y = 0.025
plt.ylabel('pdf')
plt.xlabel('sigma')
plt.show()

enter image description here

所以sigma_func(40-30, 0.025)返回一个空列表:

In [93]: sigma_func(40-30, 0.025)
Out [93]: []

上面的图是典型的,当y太大时,零 解决方案,在曲线的最大值(让我们称之为y_max)中有一个 溶液

In [199]: y_max = np.nextafter(np.sqrt(1/(np.exp(1)*2*np.pi*(10)**2)), -np.inf)

In [200]: y_max
Out[200]: 0.024197072451914336

In [201]: sigma_func(40-30, y_max)
Out[201]: [9.9999999776424]

并且对于小于y_max的y,有两种解决方案。

答案 1 :(得分:0)

这将是两个解决方案,因为普通PDF是围绕均值对称的。 就目前而言,你有一个单变量方程可以解决。 它不会有封闭式解决方案,所以你可以使用例如scipy.optimize.fsolve解决它。

编辑:请参阅@ unutbu关于Lambert W函数的封闭式解决方案的答案。