存储函数的迭代

时间:2012-06-14 20:33:43

标签: r

我不是R的新手但我不熟悉在R中编写函数并尝试编写一个函数,该函数将重复命令一定次数并将每次迭代的结果存储在一个向量中。在这种情况下,我有一个大小为“m”的有序向量(我称之为“甲板”),它被拖曳“n”次。每次进行牌组洗牌时,我都要将原牌组与洗牌牌进行比较,并计算原牌和牌组牌在同一位置的数量。如果有任何匹配,则存储“1”,如果根本没有匹配,则存储“0”

我从理论上知道,没有匹配的百分比应该收敛到1 / e

这是经过几个小时的反复试验后我所拥有的,但它只生成一个带有单个元素的向量。我似乎无法保留比较迭代。在下面的代码中,“w”是存储每个混洗比较的向量。

shuffle = function(m,n){
    deck=1:m
    repeat {        
    x=deck - sample(deck,size=length(deck))
    w=ifelse(length(x[x==0])>0, 1,0)
    if(length(w)==n)
    break
    }
return(w)
}

有什么想法吗?

3 个答案:

答案 0 :(得分:3)

编辑:更有效的功能

shuffle  <- function(m,n) {
  deck <- 1:m
  w <- numeric(n)
  for(i in 1:n){
    x <- sample(deck, m)
    w[i] <- 1*!(sum(deck==x)==0)
  }
  return(w)
}

就像你说的那样

1-sum(shuffle(20,1000))/1000
[1] 0.363
1/exp(1)
[1] 0.3678794

旧版本:

shuffleSlow  <- function(m,n) {
  deck <- 1:m
  w <- numeric(0)
  repeat {        
    x <- sample(deck, length(deck))
    w <- c(w, 1*!(sum(deck==x)==0))
    if(length(w) == n)
      break
  }
  return(w)
}

和有用的比较

> system.time(1-sum(shuffleSlow(30,100000))/100000)
   user  system elapsed 
  52.20    0.36   52.65 
> system.time(1-sum(shuffle(30,100000))/100000)
   user  system elapsed 
   2.95    0.00    2.94 

答案 1 :(得分:3)

您缺少的部分是repeat内部,您应该为该迭代计算输出的单个值并将其分配给输出向量中的特定位置(对应于迭代的位置) )。

或者,replicate函数会为您处理大部分内容:

shuffle <- function(m,n){
    deck <- 1:m
    replicate(n, {newdeck <- sample(deck)
                  anymatches <- as.numeric(any(deck==newdeck))
                  deck <- newdeck
                  anymatches})
}

和一些例子:

> shuffle(5,35)
 [1] 0 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 0 0 1 1 0 1 0 1 1 1 1 1 0 1 1 1 1 1
> shuffle(20,30)
 [1] 0 0 0 0 0 0 0 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 1 0 0 0
> shuffle(52,35)
 [1] 1 1 1 0 1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 0 1 1 1 0 0 1 1 0 1 0 1 1

答案 2 :(得分:3)

您在每次迭代时都会覆盖w,因此您最终只会在最后一次迭代时获得w的值。

如果你知道你想要改变牌组的次数,最好使用for循环而不是repeat循环。

目前尚不清楚您是否希望w包含与deck的实际比较,或仅包含01的向量,表明是否存在不匹配。 ANyway,以下是一些实现这两个方面的例子:

shuffle <- function(deck, n) {
    out <- logical(length = n)
    shuf <- deck
    for(i in seq_len(n)) {
        shuf <- sample(shuf)
        out[i] <- any(shuf == deck)
    }
    out <- as.numeric(out)
    out
}

使用如下并产生:

> set.seed(42)
> deck <- 1:100
> (out <- shuffle(deck, 20))
 [1] 0 1 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1

返回deck和改组牌组之间匹配位置的版本是:

shuffle2 <- function(deck, n) {
    out <- matrix(NA, ncol = n, nrow = length(deck))
    shuf <- deck
    for(i in seq_len(n)) {
        shuf <- sample(shuf)
        out[,i] <- shuf == deck
    }
    out <- out + 0
    out
}

使用如下并产生

> set.seed(42)
> deck <- 1:100
> (out2 <- shuffle2(deck, 20))
       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
  [1,]    0    0    0    0    0    0    0    0    0     0     0
  [2,]    0    0    0    0    0    0    0    0    0     0     0
  [3,]    0    0    0    0    0    0    0    0    0     0     0
  [4,]    0    0    0    0    0    0    0    0    0     0     0
  [5,]    0    0    0    0    0    0    0    0    0     0     0
  [6,]    0    0    0    0    0    0    0    0    0     0     0
  [7,]    0    0    0    0    0    0    0    0    0     0     0
  [8,]    0    0    0    0    0    0    0    0    0     0     0
  [9,]    0    0    0    0    0    0    0    0    0     0     0
 [10,]    0    0    0    1    0    0    0    0    0     0     0
....

很容易处理匹配矩阵以产生任何匹配的向量:

> as.numeric(apply(out2 > 0, 2, any))
 [1] 0 1 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1

shuffle()给出的匹配。

你当然可以将两者结合起来并且都由函数返回:

shuffle3 <- function(deck, n) {
    out <- matrix(NA, ncol = n, nrow = length(deck))
    shuf <- deck
    for(i in seq_len(n)) {
        shuf <- sample(shuf)
        out[,i] <- shuf == deck
    }
    out <- list(matches = out+0,
                summary = as.numeric(apply(out > 0, 2, any)))
    out
}

用作和产生:

> set.seed(42)
> deck <- 1:100
> out3 <- shuffle3(deck, 20)
> str(out3)
List of 2
 $ matches: num [1:100, 1:20] 0 0 0 0 0 0 0 0 0 0 ...
 $ summary: num [1:20] 0 1 1 1 1 0 1 0 0 1 ...
> out3$summary
 [1] 0 1 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1

请注意,无论我使用哪个版本,我都会创建一个对象来保存所需大小的结果,然后在循环中填写该对象。