如何绘制Q-Q数据图与自定义理论函数

时间:2014-05-24 15:38:11

标签: r gamma

我想对我的数据是否符合特定的分布函数进行直观评估。为此,我使用R生成分位数 - 分位数(Q-Q)图。分布函数非常具体,并没有在概率分布的标准列表中出现,所以我编写了自己的R函数来描述它。它在下面的代码中称为“DistFunc”,由两个伽玛函数的比率组成。

简而言之,我在代码中所做的是从一个文件“DistributionEstimate.txt”中读取我的数据,该文件包含两列。第1列是x值,第2列是y值。变量'a'和'b'是最合适的参数,我之前在另一个程序中使用该分布函数的最小二乘拟合确定了数据。然后我定义DistFunc并尝试使用qqmath函数绘制Q-Q图。

此时出现问题。 R继续给我很多警告,说DistFunc在'gammafn'中返回超出范围的值,并且无法绘制任何内容。这是公平的,因为我知道该函数包含一个接近原点的极点。正如您在代码中看到的那样,我尝试规范化DistFunc以尝试将其转换为概率分布(我认为,这是使用qqmath所需的内容?),但是,这没有用。

你们是否有任何想法如何克服这个问题 - 例如,通过使用不需要规范化的不同绘图功能,或将其转换为伪概率分布,而不会过于严重地影响结果?

我非常感谢任何有用的输入!

install.packages('lattice')
library(lattice)
x<-read.table("C:/DistributionEstimate.txt", colClasses = c(rep("NULL",1),rep("numeric",1)), header = FALSE)
y<-read.table("C:/DistributionEstimate.txt", colClasses = c(rep("numeric",1),rep("NULL",1)), header = FALSE)
x<-sapply(x, as.numeric)
y<-sapply(y, as.numeric)
a<-16359727025.407821410;
b<-198838619.13262583836;
DistFunc <- function(k,ampl=a,stretch=b) {
    fdist<-ampl*gamma(k*stretch-1/2)/gamma(k*stretch+1)
    fnorm<-fdist/sum(fdist)
}
qqmath(DistFunc(x), y, col="blue", envelope=.95, xlab="Quantiles of the best-fit model", ylab="Quantiles of the data")
abline(0,1, col="red", lwd=2)
grid()

1 个答案:

答案 0 :(得分:2)

QQ情节背后的想法是比较被认为是来自某个分布的观察结果,而不是相同大小的样本中您希望从该分布中看到的值。

所以第一个问题是你有xy两个值。 QQ情节是一个单变量的情节。您将一组值与分布匹配。绘制(x,y)对的第二个维度由分布函数计算。

分布函数qqmath预期不是密度函数。它需要一个将分位数转换为分布值的函数。这与在R中工作的q*分布函数系列相同,例如qnromqexp。该函数必须接受0-1范围内的数字,并将其转换为(-Inf,Inf)的分布qnorm(0, Inf) qexp的域中的值。在绘图期间,qqmath会将分位数列表传递给此函数,并将返回预期值列表。然后,它将根据(已排序的)观察值绘制预期值列表。

作为一个例子,我将使用qexp函数作为&#34; custom&#34;分位数函数。 观察

myDist<-function(x) {
    qexp(x, 5)
}

set.seed(15)
x <- rexp(100, 5)
qqmath(~x, distribution=myDist, main="qqmath")

这与

完全相同
exp.x <- myDist(ppoints(length(x)))
xyplot(sort(x)~exp.x, main="xyplot")

qqmath vc xyplot

我认为你遇到的一个问题是DistFunc看起来更像密度,然后是分位数函数。要从密度函数转变为概率,您必须进行整合。这里是帮助函数尝试为任意密度函数创建q-like函数

getq <- function(density, from, to, steps=1000) {
    x <- seq(from=from, to=to, length.out=steps) 
    y <- mapply(function(a,b)integrate(density,a,b)$value, x[-steps], x[-1])
    approxfun(c(0,cumsum(y)),x)
}

第一个参数是单参数密度函数。这将在集成期间使用。然后,fromto参数指定您的值具有非零概率的位置。然后steps是我们将执行集成的点数。然后我们使用approxfun在我们实际计算的点数和最终q函数请求的点之间进行插值。让我们看看它如何以标准密度工作。我们将再次使用指数,速率5,密度

myq <- getq(function(x) dexp(x,5), 0, 4)

请注意,我们创建了一个匿名函数来使用rate参数包装dexp,因此我们的密度只需要一个参数。这里我们只是从0到4,因为到那时我们的概率几乎为1.0。现在我们可以使用此功能,如标准qexp

> qexp(.5,5)
[1] 0.1386294
> myq(.5)
[1] 0.1386388

你看,我们得到了非常相似的答案.5。所以这看似有效。因此,如果您的分位数函数没有一个好的,封闭的形式,这是将密度函数转换为分位数函数的一种快速方法。

我看到的最后一个问题是您的ab值很大。在gamma函数中使用它们将很快导致R无法处理的数字。现在你将一个gamma除以另一个,所以希望它们会稍微取消,但是你通常会使用标准版本进行溢出。因此,诀窍是计算大值是在对数刻度上进行,然后exp()当你完成后返回自然尺度。所以你可能会将你的功能改为

DistFunc <- function(k,ampl=a,stretch=b) {
    fdist <- exp(log(ampl) + lgamma(k*stretch-1/2) - lgamma(k*stretch+1))
    fnorm <- fdist/sum(fdist)
}

请注意lgamma是对数缩放的伽玛函数。但是,使用ab值,即使在大多数情况下看起来还不够。我不确定如何根据您的参数从该函数中使用数字。我也不确定你认为你的发行范围是什么。我找不到一种方法来将它集成到1,就像一个好的密度函数应该。