有效地找到许多任意样本值的经验密度()(如dnorm(),但经验分布)

时间:2015-05-21 20:16:17

标签: r kernel-density probability-density mapply

假设您为sample.density的样本定义了经验密度(x.sample),如下所示:

set.seed(1)
x.sample <- rnorm(100)
sample.density <- density(x.sample)

现在说我们有一个渐变G,我们希望知道它的预期密度

G <- seq(-2,2, length.out=20)

根据经验分布sample.densityG中每个值的密度是多少?

如果我使用for()循环,我可以得到这样的答案:

G.dens <- c()
for(i in 1:length(G)){
    t.G <- G[i]
    G.dens[i] <- sample.density$y[which.min(abs(sample.density$x-t.G))]
}

总体思路是做dnorm()这样的事情,但不是假设x正常分布有指定的均值和sd,我想使用从任意样本中凭经验确定的分布(这不一定是正常的,或者在统计数据包中的任何其他描述良好的分布)。

1 个答案:

答案 0 :(得分:0)

我认为@MrFlick的评论指出了我正确的方向。除了建议的approxfun方法和我的示例for循环方法之外,我还意识到我可以使用mapply。请注意,我对approxfun的使用与使用which.min的其他两种方法的结果不完全匹配,但我并不关心输出的差异太大,尽管其他方法可能是。< / p>

First, reproducing the sample data from the question:
set.seed(1)
x.sample <- rnorm(100)
sample.density <- density(x.sample)
G <- seq(-2,2, length.out=20)

现在,为循环版本创建一个函数

环()

loop <- function(x, ref){
    if(class(ref)!="density"){
        ref <- density(ref)
    }

    ref.y <- ref$y
    ref.x <- ref$x

    G.dens <- c()
    for(i in 1:length(x)){
        t.G <- x[i]
        G.dens[i] <- ref.y[which.min(abs(ref.x-t.G))]
    }

    G.dens
}

接下来,我将使用我提出的使用mapply

的方法

dsample()

dsample <- function(x, ref){

    if(class(ref)!="density"){
        ref <- density(ref)
    }

    XisY <- function(x,y){ # which of several X values most closely matches a single Y value?
        which.min(abs(y-x))
    }

    ref.y <- ref$y
    ref.x <- ref$x

    # ds <- approxfun(ref)

    # ds(x)

    ref.y[mapply(XisY, x, MoreArgs=list(y=ref.x))]
}

最后,按照@MrFlick建议的方法利用approxfun

AF()

af <- function(x, ref){
    if(class(ref)!="density"){
        ref <- density(ref)
    }

    # XisY <- function(x,y){ # which of several X values most closely matches a single Y value?
    #   which.min(abs(y-x))
    # }

    ref.y <- ref$y
    ref.x <- ref$x

    ds <- approxfun(ref)

    ds(x)

    # ref.y[mapply(XisY, x, MoreArgs=list(y=ref.x))]
}

现在比较他们的速度:

microbenchmark(
    loop(G, sample.density),
    dsample(G, sample.density),
    af(G, sample.density)
)
# Unit: microseconds
#                        expr     min       lq     mean  median       uq      max neval
#     loop(G, sample.density) 221.801 286.6675 360.3698 348.065 409.9785  942.071   100
#  dsample(G, sample.density) 252.641 290.7900 359.0432 368.388 417.1510  520.960   100
#       af(G, sample.density) 201.331 227.8740 276.0425 253.339 273.6225 2545.081   100

现在比较G的大小增加速度:

speed.loop <- c()
speed.dsample <- c()
speed.af <- c()
lengths <- seq(20, 5E3, by=200)
for(i in 1:length(lengths)){
    G <- seq(-2,2, length.out=lengths[i])
    bm <- microbenchmark(
        loop(G, sample.density),
        dsample(G, sample.density),
        af(G, sample.density), times=10
    )

    means <- aggregate(bm$time, by=list(bm$expr), FUN=mean)[,"x"]/1E6 # in milliseconds
    speed.loop[i] <- means[1]
    speed.dsample[i] <- means[2]
    speed.af[i] <- means[3]


}

speed.ylim <- range(c(speed.loop, speed.dsample, speed.af))
plot(lengths, (speed.loop), ylim=(speed.ylim), type="l", ylab="Time (milliseconds)", xlab="# Elements in G")
lines(lengths, (speed.dsample), col="red")
lines(lengths, (speed.af), col="blue")

enter image description here