更快的循环binom.test?

时间:2013-03-18 11:33:53

标签: r

我有一个成功的载体,并希望对每个值进行binom.test。有没有比这个循环更快的方法(我有很多):

successes <-rbinom(100, 625, 1/5)
x <-NULL
for (i in 1:100) {
x <-append(x, binom.test(successes[i], 625, 1/5)$p.value)
}

2 个答案:

答案 0 :(得分:9)

您可以使用sapply()为每个成功值计算p.values,而不是for循环。

pp <- sapply(successes, function(x) binom.test(x, 625, 1/5)$p.value)

如果您需要真正加快流程,可以使用包data.table的优势。首先,将successes转换为data.table对象。然后计算每行p.value。

library(data.table)
dt<-data.table(successes)
dt[,pp:=binom.test(successes, 625, 1/5)$p.value,by=successes]

答案 1 :(得分:4)

data.table真的很快,似乎只是工作! successes中的许多值都会重复出来,因此只需对唯一值进行昂贵的binom.test计算,就可以节省时间。

fasterbinom <- function(x, ...) {
    u <- unique(x)
    idx <- match(x, u)
    sapply(u, function(elt, ...) binom.test(elt, ...)$p.value, ...)[idx]
}

对于某些时间,我们有

dtbinom <- function(x, ...) {
    dt <- data.table(x)
    dt[, pp:=binom.test(x, ...)$p.value, by=x]$pp
}

> successes <-rbinom(100000, 625, 1/5)
> identical(fasterbinom(successes, 625, .2), dtbinom(successes, 625, .2))
[1] TRUE
> library(rbenchmark)
> benchmark(fasterbinom(successes, 625, .2), dtbinom(successes, 625, .2))
                              test replications elapsed relative user.self
2     dtbinom(successes, 625, 0.2)          100   4.265    1.019     4.252
1 fasterbinom(successes, 625, 0.2)          100   4.184    1.000     4.124
  sys.self user.child sys.child
2    0.008          0         0
1    0.052          0         0

在这种情况下,比较循环方法

很有意思
f0 <- function(s, ...) {
    x0 <-NULL
    for (i in seq_along(s))
        x0 <-append(x0, binom.test(s[i], ...)$p.value)
    x0
}

f1 <- function(s, ...) {
    x1 <- numeric(length(s))
    for (i in seq_along(s))
        x1[i] <-  binom.test(s[i], ...)$p.value
    x1
}

f2 <- function(s, ...)
    sapply(s, function(x, ...) binom.test(x, ...)$p.value, ...)

f3 <- function(s, ...)
    vapply(s, function(x, ...) binom.test(x, ...)$p.value, numeric(1), ...)

使用f1时,for通常更好的“预分配和填充”策略,f2是一个sapply,可以消除制定不良的可能性for来自用户的{1}}循环,f3sapply的更安全且可能更快的版本,可确保每个结果都是长度为1的数值。

每个函数返回相同的结果

> n <- 1000
> xx <-rbinom(n, 625, 1/5)
> res0 <- f0(xx, 625, .2)
> identical(res0, f1(xx, 625, .2))
[1] TRUE
> identical(res0, f2(xx, 625, .2))
[1] TRUE
> identical(res0, f3(xx, 625, .2))
[1] TRUE

apply - 类似方法比for循环快10%(在这种情况下;当单个元素很大时,f0和f1之间的差异会更加显着)

> benchmark(f0(xx, 625, .2), f1(xx, 625, .2), f2(xx, 625, .2),
+           f3(xx, 625, .2), replications=5)
              test replications elapsed relative user.self sys.self user.child
1 f0(xx, 625, 0.2)            5   2.303    1.100     2.300        0          0
2 f1(xx, 625, 0.2)            5   2.361    1.128     2.356        0          0
3 f2(xx, 625, 0.2)            5   2.093    1.000     2.088        0          0
4 f3(xx, 625, 0.2)            5   2.212    1.057     2.208        0          0
  sys.child
1         0
2         0
3         0
4         0

实际速度来自fasterbinom / dtbinom的发烧友算法。

> identical(res0, fasterbinom(xx, 625, .2))
[1] TRUE
> benchmark(f2(xx, 625, .2), fasterbinom(xx, 625, .2), replications=5)
                       test replications elapsed relative user.self sys.self
1          f2(xx, 625, 0.2)            5   2.146   16.258     2.145        0
2 fasterbinom(xx, 625, 0.2)            5   0.132    1.000     0.132        0
  user.child sys.child
1          0         0
2          0         0