如何在python中手动生成Q-Q图而不使用反向分布函数

时间:2017-11-05 13:45:25

标签: python math statistics

我有4种不同的分布,我已经适应了观察样本。现在我想比较我的结果并找到最佳解决方案。我知道有很多不同的方法可以做到这一点,但我想使用分位数 - 分位数(q-q)图。

我的4个发行版的公式是:

dist 1

dist 2

dist 3

dist 4

其中K 0 是第二类和第零类的修改贝塞尔函数,Γ是伽马函数。

我的样本风格看起来大致如下:(0.2,0.2,0.2,0.3,0.3,0.4,0.4,0.4,0.4,0.6,0.7 ......),所以我有多个相同的值,它们之间也有差距

我已阅读有关此site的说明,并尝试在python中实现它们。所以,就像在链接中一样:

1)我将数据从最小值分类到最大值。

2)我在区间(0,1)上计算了“n”个均匀间隔点,其中“n”是我的样本大小。

3)这是我无法管理的。

据我所知,我现在应该使用我预先计算的值(那些均匀间隔的值),将它们放在我上面的分布的反函数中,从而计算我的分布的理论分位数。

作为参考,这里是反函数(部分用wolframalpha计算,并且尽可能):

invdist 1

invdist 2

invdist 3

invdist 4

其中W是Lambert W函数,之后括号中的所有内容都是参数。

问题是,显然第一次分布不存在反函数。下一个可能会产生复杂的值(在根目录下是负数,因为b = 0.55,根据拟合),最后两个具有Lambert W-Function(我不安全如何在python中实现它们)。 / p>

所以我的问题是,有没有办法在没有逆分布函数的解析表达式的情况下计算q-q图?

我非常感谢你能给我的任何帮助!

3 个答案:

答案 0 :(得分:2)

更简单,更传统的方法是计算每个模型的对数似然,并选择具有最大对数似然的对数。你不需要cdf或quantile函数,只需要你已经使用的密度函数。

对数似然只是log p(x | model)的总和,其中p(x | model)是给定模型下数据x的概率密度。这里“模型”=通过最大化参数的可能值的对数似然来选择参数的模型。

通过在参数空间中整合对数似然,您可以更加小心,同时还要考虑分配给每个模型的任何先验概率;这将是贝叶斯方法。

听起来你本质上是想通过最小化Kolmogorov-Smirnov(KS)统计来选择模型,尽管它的名字很重,但它很简单 - 它是可能的分位数函数和经验之间的差异位数。这是可辩护的,但我认为比较对数似然更常规,也更简单,因为你只需要pdf。

答案 1 :(得分:1)

碰巧有一种更简单的方法。我花了一两天的时间去挖掘,直到我指向scipy.stats中的正确方法。我在寻找错误的名字!

首先,构建rv_continuous的子类来表示您的一个发行版。我们知道您的发行版的pdf,这就是我们定义的内容。在这种情况下,只有一个参数。如果需要更多内容,只需将它们添加到def语句中,并根据需要在return语句中使用它们。

>>> from scipy import stats
>>> param = 3/2
>>> from math import exp
>>> class NoName(stats.rv_continuous):
...     def _pdf(self, x, param):
...         return param*exp(-param*x)
...     

现在创建一个这个对象的实例,声明它的支持的下端(即r.v.可以假设的最低值),以及调用的参数。

>>> noname = NoName(a=0, shapes='param')

我没有可以使用的实际值示例。我将创建一个伪随机样本。

>>> sample = noname.rvs(size=100, param=param)

对其进行排序,使其成为所谓的“经验性cdf”。

>>> empirical_cdf = sorted(sample)

样本有100个元素,因此生成100个点来对逆cdf或分位数函数进行采样,如您引用的论文所述。

>>> theoretical_points = [(_-0.5)/len(sample) for _ in range(1, 1+len(sample))]

在这些点获取分位数函数值。

>>> theoretical_cdf = [noname.ppf(_, param=param) for _ in theoretical_points]

全部绘制。

>>> from matplotlib import pyplot as plt
>>> plt.plot([0,3.5], [0, 3.5], 'b-')
[<matplotlib.lines.Line2D object at 0x000000000921B400>]
>>> plt.scatter(empirical_cdf, theoretical_cdf)
<matplotlib.collections.PathCollection object at 0x000000000921BD30>
>>> plt.show()

这是结果的Q-Q图。

Q-Q plot

答案 2 :(得分:0)

Darn it ...对不起,我注意了一个光滑的解决方案,以某种方式绕过丢失的逆CDF并直接计算分位数(并避免任何数字方法)。但它也可以通过简单的蛮力来完成。

首先,您必须自己定义分布的分位数(例如,比原始/经验分位数准确十倍)。然后,您需要计算相应的CDF值。然后,您必须逐个将这些值与问题中步骤2中计算的值进行比较。具有最小偏差的CDF值的相应分位数是您正在寻找的。

此解决方案的精度受限于您自己定义的分位数的分辨率。

但也许我错了,有一种更优雅的方式来解决这个问题,那么我很乐意听到它!