Monte Carlo 基于列和的替换模拟

Monte Carlo Simulation with Replacement Based On Sum of A Column

我正在尝试使用 Monte Carlo 模拟来模拟电子游戏中不太可能出现的情况。我对编码非常陌生,我认为模拟这将是一个有趣的情况。

有3个目标,他们被独立攻击了8次。我的问题是当有 8 次攻击时,如何处理其中一列不能被攻击超过 6 次的事实。

我想采取任何针对第 2 列的攻击 select 随机攻击其他 2 列之一,但 只有当第 2 列已经被攻击 6 次时.

例如,这是我尝试模拟 5000 次重复。

#determine number of repeats
trial <- 5000

#create matrix with a row for each trial
m <- matrix(0, nrow = trial, ncol = 3)

#The first for loop is for each row
#The second for loop runs each attack independently, sampling 1:3 at random, then adding one to that position of the row.
#The function that is called by ifelse() when m[trial, 2] > 6 = TRUE is the issue.

for (trial in 1:trial){
  for (attack in 1:8) {
    target <- sample(1:3, 1)
    m[trial, target] <- m[trial, target] + 1
    ifelse(m[trial, 2] > 6, #determines if the value of column 2 is greater than 6 after each attack
           function(m){
             m[trial, 2] <- m[trial, 2] - 1 #subtract the value from the second column to return it to 6
             newtarget <- sample(c(1,3), 1) #select either column 1 or 3 as a new target at random
             m[trial, newtarget] <- m[trial, newtarget] + 1 #add 1 to indicate the new target has been selected
             m}, #return the matrix after modification
           m) #do nothing if the value of the second column is <= 6
  }
}

例如,如果我有下面的矩阵:

> matrix(c(2,1,5,7,1,0), nrow = 2, ncol = 3)
     [,1] [,2] [,3]
[1,]    2    5    1
[2,]    1    7    0

我希望函数查看矩阵的第 2 行,从 7 中减去 1,然后将 1 添加到第 1 列或第 3 列以创建 c(2,6,0) 或 c(1, 6,1). 我想了解如何在循环中执行此操作,但也可以在之后执行此操作。

我认为我在使用 function(x)ifelse 时犯了严重的根本性错误。

谢谢。

这是您的代码的改进版本:

set.seed(1)

trial <- 5000

#create matrix with a row for each trial
m <- matrix(0, nrow = trial, ncol = 3)

#The first for loop is for each row
#The second for loop runs each attack independently, sampling 1:3 at random, then adding one to that position of the row.
#The function that is called by ifelse() when m[trial, 2] > 6 = TRUE is the issue.

for (i in 1:trial){
    for (attack in 1:8) {
        target <- sample(1:3, 1)
        m[i, target] <- m[i, target] + 1 
        #determines if the value of column 2 is greater than 6 after each attack
        if(m[i, 2] > 6){ 
            #subtract the value from the second column to return it to 6
            m[i, 2] <- m[i, 2] - 1 
            #select either column 1 or 3 as a new target at random
            newtarget <- sample(c(1,3), 1)
            #add 1 to indicate the new target has been selected
            m[i, newtarget] <- m[i, newtarget] + 1 
            }   
        }   
    }   

# Notice the largest value in column 2 is no greater than 6.
apply(m, 2, max)

set.seed用于使结果可重现(通常只用于测试)。 ifelse 函数与普通的 if-else 控制流有不同的用途。这是一个例子:

x = runif(100)
ifelse(x < 0.5, 0, x)

您会注意到 x 中小于 0.5 的任何元素现在都为零。我将您的代码更改为具有 if 块。请注意 m[i, 2] > 6 returns 单个 TRUEFALSE 而在上面的小示例中, x < 0.5 返回逻辑向量。所以 ifelse 可以采用逻辑向量,但是 if 块要求只有一个逻辑向量。

您使用 function 的方法是正确的,但在本例中没有必要。通常,但并非总是如此,您将定义这样的函数:

f = function(x)
    x^2

但是仅仅返回值并不意味着你想要的改变了:

x = 5
f(5) # 25
x    # still 5

有关此的更多信息,请查找 R 中的函数作用域。

最后,我将循环更改为 i in 1:trial 而不是 trial in 1:trial。您可能不会注意到您的情况有任何问题,但最好使用单独的变量而不是构成循环范围的变量。

希望这对您有所帮助。

P.S。 R 在循环时的速度并不真正出名。如果你想让事情进展得更快,你通常需要向量化你的代码。