我想对我的数据是否符合特定的分布函数进行直观评估。为此,我使用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()
答案 0 :(得分:2)
QQ情节背后的想法是比较被认为是来自某个分布的观察结果,而不是相同大小的样本中您希望从该分布中看到的值。
所以第一个问题是你有x
和y
两个值。 QQ情节是一个单变量的情节。您将一组值与分布匹配。绘制(x,y)
对的第二个维度由分布函数计算。
分布函数qqmath
预期不是密度函数。它需要一个将分位数转换为分布值的函数。这与在R中工作的q*
分布函数系列相同,例如qnrom
或qexp
。该函数必须接受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")
我认为你遇到的一个问题是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)
}
第一个参数是单参数密度函数。这将在集成期间使用。然后,from
和to
参数指定您的值具有非零概率的位置。然后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。所以这看似有效。因此,如果您的分位数函数没有一个好的,封闭的形式,这是将密度函数转换为分位数函数的一种快速方法。
我看到的最后一个问题是您的a
和b
值很大。在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
是对数缩放的伽玛函数。但是,使用a
和b
值,即使在大多数情况下看起来还不够。我不确定如何根据您的参数从该函数中使用数字。我也不确定你认为你的发行范围是什么。我找不到一种方法来将它集成到1,就像一个好的密度函数应该。