2015-12-29 32 views
1

我想从x中选择一个元素,y中的一个元素(x和y是互斥的)以及x或y中尚未被选中的一个元素。然后我想重复指定次数的过程并将每个试验的结果存储在数据框中。 (注意:我不想试图找到所有可能的组合)有没有办法让我避免for循环或使其更高效?

下面的代码工作但随着试验次数的增加而显着减慢。

x <- 1:4 
y <- 5:8 
z <- c(x, y) #edited - previous code read a, b in place of x, y 
trials <- 5 
sel <- data.frame() 
set.seed(123) 
for (i in 1:trials){ 
    x_sel <- sample(x, 1) 
    y_sel <- sample(y, 1) 
    rem <- z[!(z %in% c(x_sel, y_sel))] 
    z_sel <- sample(rem, 1) 
    sel <- rbind(sel, cbind(x_sel, y_sel, z_sel)) 
} 
+0

在第3行中,你的意思是写'z < - c(x,y)'? –

+0

是的,我的帖子已被编辑以反映更改。我最初使用a,b和c作为向量,但切换到x,y和z以避免与'c()'函数混淆。不幸的是,我错过了第3行和第10行。 – drumminactuary

回答

4

这应该可能会稍微快一些,但我怀疑它是最快的。当然,我认为Rcpp会是最快的。

> set.seed(123) 
> x <- 1:4 
> y <- 5:8 
> z <- c(x, y) 
> trials <- 5 
> 
> xval <- sample(x,size = trials,replace = TRUE) 
> yval <- sample(y,size = trials,replace = TRUE) 
> zval <- mapply(FUN = function(x,y,z) {sample(setdiff(z,c(x,y)),1)}, 
          x = xval, 
          y = yval, 
          MoreArgs = list(z = z)) 
> 
> result <- data.frame(xval = xval, 
             yval = yval, 
             zval = zval) 
> result 
    xval yval zval 
1 2 5 8 
2 4 7 3 
3 2 8 6 
4 4 7 5 
5 4 6 1 

在只有10K的样品,这似乎比是37倍〜更快的for循环(这是因为追加的事情一次一个到sel,没有什么在for循环固有的主要低效)。这与一个更明智的书写for循环之间的区别可能会少得多。

1

我的方法并不高雅,但在大量试验中似乎很有效。为了证明这一点,我创建3个功能:F1 - 你的,F2 - joran的,F3 - 雷

library(microbenchmark) 

f1 <- function() { 
    x <- 1:4 
    y <- 5:8 
    z <- c(x, y) #edited - previous code read a, b in place of x, y 
    trials <- 5000 
    sel <- data.frame() 
    set.seed(123) 
    for (i in 1:trials) { 
     x_sel <- sample(x, 1) 
     y_sel <- sample(y, 1) 
     rem <- z[!(z %in% c(x_sel, y_sel))] 
     z_sel <- sample(rem, 1) 
     sel <- rbind(sel, cbind(x_sel, y_sel, z_sel)) 
    } 
    return(sel) 
} 

f2 <- function() { 
    set.seed(123) 
    x <- 1:4 
    y <- 5:8 
    z <- c(x, y) 
    trials <- 5000 

    xval <- sample(x, size = trials, replace = TRUE) 
    yval <- sample(y, size = trials, replace = TRUE) 
    zval <- 
     mapply(
     FUN = function(x, y, z) { 
      sample(setdiff(z, c(x, y)), 1) 
     }, 
     x = xval, 
     y = yval, 
     MoreArgs = list(z = z) 
    ) 

    result <- data.frame(xval = xval, 
         yval = yval, 
         zval = zval) 
    return(result) 
} 


f3 <- function() { 
    x <- 1:4 
    y <- 5:8 
    z <- c(x, y) #edited - previous code read a, b in place of x, y 
    trials <- 5000 
    set.seed(123) 
    x_sel <- sample(x, trials, replace = TRUE) 
    y_sel <- sample(y, trials, replace = TRUE) 
    z_mac <- matrix(z, 
        nrow = trials, 
        ncol = length(z), 
        byrow = TRUE) 
    take <- z_mac != x_sel & z_mac != y_sel 
    z_sel <- t(matrix(t(z_mac)[t(take)], ncol = trials)) 
    take <- sample(1:ncol(z_sel), size = trials, replace = TRUE) 
    cbind(x_sel, y_sel, z_sel = z_sel[cbind(1:trials, take)]) 
} 


microbenchmark(f1(), f2(), f3(), times = 10L) 

Unit:milliseconds 
expr   min   lq  mean  median   uq   max neval 
f1() 2193.448113 2248.442450 2258.626023 2258.135072 2267.333956 2346.457082 10 
f2() 205.124501 208.672947 213.520267 212.208095 219.397101 222.990083 10 
f3() 2.463567 2.491762 2.570517 2.512588 2.603582 2.827863 10 

我的F3功能率比F2快f1和83倍的速度856倍。当我们考虑oryginal问题(试验= 5),然后

> microbenchmark(f1(), f2(), f3(), times = 10L) 
Unit: microseconds 
expr  min  lq  mean median  uq  max neval 
f1() 1215.924 1268.790 1296.7610 1300.5095 1321.015 1370.998 10 
f2() 587.937 590.500 619.6248 612.9285 638.881 687.261 10 
f3() 68.886 78.819 86.7652 81.2225 91.315 116.947 10 
+0

当我在我的实际数据上实现代码时,其中x有65个元素,y有57个元素(还有其他向量),它比Joran的解决方案稍微长一点。它仍然比我的原始代码更高效。 – drumminactuary

+0

我不知道它有多可能。我重新运行'length(x)= length(y)= 100'和'trials = 5'和'trails = 5000'的代码。 'f3'仍然更快。 (我修正了上面的'f3'的代码:当你第一次看到一个变量时,应该用'x_sel'而不是'x_sel2')。很明显,我的功能不灵活,只能调整为2个变量('x'和'y')。当然,它可以轻松扩展更多的变量,但我不知道效率如何。 – Robert