5

我正在创建基于 xts 对象的比例表。由于这是一个(不幸的是)需要大约 10^6 个循环的大型程序的一部分,它造成了相当大的瓶颈,我想加快它的速度。

这是我开始的一个例子:

library(quantmod)

test.xts <- xts(sample(seq(1,5, by=.5), 50, replace=T), as.Date(1:50))

system.time(for(i in 1:10000){

  prop.table(table(test.xts))

})

>user  system elapsed 
 19.86    0.00   18.58 

我已经将 xts 更改为矩阵,从而显着提高了速度。我只提到它最初是一个 xts,以防我错过了 xts 的某些东西,这些东西会加快速度,超出我已经看到的将其转换为矩阵的增益。

test.mat <- as.matrix(test.xts)

system.time(for(i in 1:10000){

  prop.table(table(test.mat))

})

>user  system elapsed 
 2.78    0.00    2.90 

但我真的希望它尽可能快,所以我希望其他人有进一步改进的建议。我希望有一个明显的方法我忽略了。

另一条信息是,这些表的输出最终会与不同时间段的类似输出合并,因此维度需要保持命名。(即,我需要能够将时间 1 的“10”值的比例与时间 2 的“10”的比例相匹配)。

任何帮助是极大的赞赏。

4

2 回答 2

5

table()隐含地创建了一个昂贵的因素。在您的情况下,您可以通过使用节省很多(超过 10 倍),tabulate()因为您已经有整数:

a <- tabulate(test.mat)
names(a) <- seq_along(a)
a / sum(a)
   1    2    3    4    5    6    7    8    9   10 
0.16 0.14 0.08 0.14 0.08 0.16 0.02 0.06 0.10 0.06 

时间:

system.time(for(i in 1:10000){
  a <- tabulate(test.mat)
  names(a) <- seq_along(a)
  a/sum(a)
})

 user  system elapsed 
0.208   0.002   0.210 

您的比较时间:

system.time(for(i in 1:10000) prop.table(table(test.mat)))
 user  system elapsed 
3.373   0.028   3.402 
于 2012-05-18T17:49:05.740 回答
3

以 joran 的评论为基础,tabulate()直接使用可以证明更快。它确实有三个值得注意的怪癖:

  1. 它只处理整数并截断小数。
  2. 它默默地忽略所有负值和零。
  3. 它为所有值 1:n 创建一个 bin,即使计数为零

详情请参阅?tabulate

有了这个警告,这里有一个函数可以加快大约 9 倍的速度:

prop2 <- function(x){
  x <- tabulate(x)
  out <- x/sum(x)
  names(out) <- seq_along(out)
  return(out)
}

测试速度:

library(rbenchmark)
test.mat <- as.matrix(test.xts)
f1 <- function() prop.table(table(test.mat))
benchmark(f1(), prop2(test.mat),
           replications = 1000,
           columns = c("test", "relative", "elapsed"),
           order = "relative")
#------
             test relative elapsed
2 prop2(test.mat)      1.0    0.10
1            f1()      9.1    0.91

确认输出相同:

> prop.table(table(test.mat))
test.mat
   1    2    3    4    5    6    7    8    9   10 
0.04 0.02 0.20 0.12 0.08 0.10 0.06 0.14 0.12 0.12 
> prop2(test.mat)
   1    2    3    4    5    6    7    8    9   10 
0.04 0.02 0.20 0.12 0.08 0.10 0.06 0.14 0.12 0.12
于 2012-05-18T17:51:34.693 回答