0

我对 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)
}

有什么想法吗?

4

3 回答 3

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 
于 2012-06-14T20:54:03.083 回答
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
于 2012-06-14T20:54:51.957 回答
3

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

如果您知道要洗牌多少次,那么使用for循环比使用循环更好repeat

目前尚不清楚您是否要包含与s 和s 的向量w的实际比较,deck或者仅包含表示是否存在匹配项的向量。无论如何,这里有几个实现这两个的例子:01

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

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

于 2012-06-14T21:00:14.187 回答