使用“apply”加速模拟

时间:2013-03-05 07:23:33

标签: performance r simulation apply systemtime

我有一个矩阵z(3 x 20000)。将每一行视为随机变量,将每列视为一个模拟。我使用apply命令在R中编写了以下函数,以便在3维中找到经验累积分布函数(EMP.CDF)。这个k变量经验CDF在this pdf的第2页,“多变量ECDF”一节中进行了解释。

EMP.CDF=function(z) {
# z is a matrix (3 x 20000) and each row is a realization of a random variable
q1=z[1,];q2=z[2,];q3=z[3,]
# qi = the realization of the ith random variable, i=1,2,3
# Now I am going to evaluate the empirical cumulative distribution function at
# each column of z
# Given each column, the function should return an empirical
# cumulative probability.

d=apply(z,2, function(x) sum(q1<=x[1] & q2<=x[2] & q3<=x[3])/(length(q1)))
return(d)}

> z=matrix(0,3,20000)
> z[1,]=runif(20000,1,2)
> z[2,]=runif(20000,3,5)
> z[3,]=runif(20000,7,9)

> system.time(EMP.CDF(z))
   user  system elapsed 
   30.18    0.01   30.39 

在上面的代码中k = 3。有什么方法可以矢量化上面的函数来减少系统时间吗?

1 个答案:

答案 0 :(得分:1)

三维累积分布函数是3个变量的函数。 如果你在网格上估计它,它可以表示为一个三维数组, 但它会是不精确和巨大的(你的函数返回一维数组, 所以它不是计算机。)

给定一个点x,只需计算所有坐标均小于x的点的比例。

z <- matrix(runif(60000), 3, 20000)
emp.cdf <- function(z)
  function(x) mean( apply( z <= x, 2, all ) )
emp.cdf(z)( c(.5,.5,.5) )  # Approximately 1/8

以下内容将再现您引用的文档中的图:

n <- 10
z <- matrix(runif(2*n), 2, n)
f <- emp.cdf(z)
g <- function(u,v) f(c(u,v))
persp( outer( sort(z[1,]), sort(z[2,]), Vectorize(g) ) )

x <- seq(0,1,length=100)
persp( outer( x, x, Vectorize(g) ) )

如果要评估初始点的累积概率分布, 您可以使用apply(如果您想在网格上对其进行评估,可以使用expand.grid进行构建)。

n <- 100
z <- matrix(runif(3*n), 3, n)
f <- emp.cdf(z)
p <- apply( z, 2, f )

但是这个算法是二次的:要计算n个概率, 对于每一个,我们检查所有3*n坐标。 对于你的20,000点,这需要一段时间。

您可以使用分而治之的方法 加快计算速度, 但这并不简单: 随意拿起一点, 用它将空间分成8个八分圆, 递归地计算每个八分圆中的点数; 然后,您可以使用生成的tree 计算任何点的概率, 只检查一小部分。

这与预处理步骤没有什么不同 用于计算k-nearest neighbours, 或加快n-body simulations