基于列总和的替换蒙特卡罗模拟

时间:2018-12-08 04:29:00

标签: r simulation montecarlo

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

有3个目标,它们被独立攻击8次。我的问题在于如何处理这样的事实:当发生8次攻击时,其中一列攻击次数不能超过6次。

我想对第2列进行任何攻击,而是从其他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

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

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

谢谢。

1 个答案:

答案 0 :(得分:1)

这是您代码的改进版本:

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返回单个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并不是真正以循环时的速度而闻名。如果您想使事情变得更快,通常需要对代码进行矢量化处理。