【问题标题】:R Simulation, For loopR 模拟,For 循环
【发布时间】:2021-02-28 07:48:19
【问题描述】:

我正在求解一个 R 模拟 qn,当 2 个骰子的总和 == 轮数(即第 1 轮,第 2 轮...)时,给玩家加 1 分,否则返回 0 分。但我不熟悉R for-loop。如果有人可以提供帮助,不胜感激!

这是我的粗略计划,但代码效果不佳。最终,我想轻松更改玩家数量和迭代次数。

  iteration <- function(iter) {

  n <- 12
  
  # Number of players
  player <- 2
  player.score <- rep(NA, 2)
  player.score
  
  # Roll 1st dice
  Result.1 <- sample(1:6,1)
  
  # Roll 2nd dice
  Result.2 <- sample(1:6, 1)
  
  result <- matrix(0L, ncol=5, nrow=n)
  colnames(result) <- c('Round#', "Result.1", "Result.2", "Total", "Win?")
  
  for(i in 1:player) {
  
  result[, 'Round#'] <- seq(1:n)  

  result[, 'Result.1'] <- sample(Result.1)
  
  result[, 'Result.2'] <- sample(Result.2)
  
  result[, 'Total'] <- rowSums(result[, 2:3])

  result[, 'Win?'] <- ifelse(result[, 'Total'] == result[, 'Round#'], 1, 0)
  result
  
  total.score <- sum(result[, "Win?"])
  player.score[i] <- total.score
  
  }

【问题讨论】:

    标签: r for-loop simulation


    【解决方案1】:

    这可能会有所帮助

    set.seed(12)
    
    # Set number of players and number of iterations 
    n_player = 3
    n_trial = 5
    
    # Empty matrix to store scores of all players 
    player_score = matrix(nrow=n_trial, ncol=n_player)
    
    # For each player, run n iterations  
    for (p in 1:n_player) {
      for (i in 1:n_trial) {
        dice_1 = sample(1:6,1)
        dice_2 = sample(1:6,1)
        if (dice_1 + dice_2 == i) {
          score = 1
        } else {
          score = 0
        }
        player_score[i, p] = score
      }
    }
    
    player_score
         [,1] [,2] [,3]
    [1,]    0    0    0
    [2,]    0    0    0
    [3,]    1    0    0
    [4,]    0    0    0
    [5,]    0    1    0
    
    total_score = colSums(player_score) 
    total_score
    [1] 1 1 0
    

    【讨论】:

    • 嗨,理想情况下它应该返回一个看起来像这样的向量 --> 0 0 0 1 0 0 1;其中1代表数量相同的实例,0代表数量不同的实例。这样我就可以对其进行求和并比较不同玩家的得分。很抱歉含糊其辞!
    【解决方案2】:

    一般来说,如果您正在使用 R 进行编码并考虑使用 for 循环,那么可能有更好的方法来执行此操作。我认为这是一个很好的例子。此外,虽然 Ha Nguyen 的解决方案对于您在问题中遇到的用例是正确的,但很难一概而论。这是因为你的数据结构不是tidy。它不整洁,因为您的列名包含数据:数字足以表明内容与哪个骰子/玩家/等相关。因此,在您模拟的玩家数量、掷骰数和回合数的变化方面,该代码是脆弱的。

    一个整洁的解决方案可以避免这个问题,方法是使用单个列来包含掷骰子,并使用额外的列来指示掷骰子所涉及的回合和玩家。

    这是一个可能的实现:

    library(tidyverse)
    
    simulate <- function(nPlayers=2, nRolls=2, nRounds=12) {
      # Generate tidy data
      data <- tibble() %>% 
                expand(
                  Round=c(1:nRounds),
                  Player=c(1:nPlayers),
                  Roll=c(1:nRolls)
                ) %>% 
                mutate(Result=ceiling(runif(nrow(.), max=6)))
      # Calculate each player's score in each round
      totalsByRound <- data %>%
                         group_by(Round, Player) %>% 
                         summarise(Score=sum(Result), .groups="drop")
      # Determine winner for each round
      winners <- totalsByRound %>% 
                   group_by(Round) %>% 
                   slice_max(Score) %>% 
                   rename(
                     Winner=Player,
                     WinningScore=Score
                   ) %>% 
                   # n() calculates group size with grouped data, so n() > 1 indicates a tie
                   filter(n() == 1)
      # Convert to wide format ease of presentation
      totalsByRound <- totalsByRound %>% 
                         pivot_wider(
                           names_from=Player,
                           values_from=Score,
                           names_prefix="Player"
                         ) %>% 
                         left_join(winners, by="Round")
      return(totalsByRound)
    }
    

    还有一个例子使用

    # For repoducibility
    set.seed(1234)
    
    # Do the simulation
    results <- simulate()
    results
    
    # A tibble: 12 x 5
       Round Player1 Player2 Winner WinningScore
       <int>   <dbl>   <dbl>  <int>        <dbl>
     1     1       5       8      2            8
     2     2      10       3      1           10
     3     3       8       9      2            9
     4     4       8       8     NA           NA
     5     5       4       4     NA           NA
     6     6       4       2      1            4
     7     7       7      10      2           10
     8     8       6       5      1            6
     9     9       6       7      2            7
    10    10       4      11      2           11
    11    11       8       6      1            8
    12    12       6       8      2            8
    

    玩家分数很容易总结:

    # Summarise results
    results %>% 
      group_by(Winner) %>% 
      summarise(RoundsWon=n(), .groups="drop")
    
    # A tibble: 3 x 2
      Winner RoundsWon
       <int>     <int>
    1      1         4
    2      2         6
    3     NA         2
    

    您当然可以在 simulate 函数中包含摘要,但我不确定您的实际用例是什么,所以我省略了。

    代码将通过更改参数值来处理其他数量的玩家、回合和滚动:

    # Demo for different parameters
    simulate(nPlayers=4, nRolls=3, nRounds=100)
    # A tibble: 100 x 7
       Round Player1 Player2 Player3 Player4 Winner WinningScore
       <int>   <dbl>   <dbl>   <dbl>   <dbl>  <int>        <dbl>
     1     1       8      11       8      13      4           13
     2     2       9       8       7      11      4           11
     3     3       7       8      13       8      3           13
     4     4      11       9       8       6      1           11
     5     5       5      10       5       4      2           10
     6     6       9       8      14       8      3           14
     7     7      17      11       9      12      1           17
     8     8      10      13      14      11      3           14
     9     9      12      14       6      14     NA           NA
    10    10      13      11       6       8      1           13
    # … with 90 more rows
    

    整洁的解决方案比使用for 循环更健壮,并且对于“大型”数据集应该明显更快。它也更紧凑,而且我相信更容易理解。

    【讨论】:

    • 嗨 Limey,感谢您的帮助,结果看起来棒极了,而且绝对比我所做的更容易理解。只是澄清一下,这里这行代码的目的是什么? “mutate(Result=ceiling(runif(nrow(.), max=6)))”,为什么max设置为6?
    • 它的用途与您的sample(1:6, 1) 相同:它生成掷骰子。 runif 从 Uniform(min, max) 分布中生成随机(浮点)数。 min 默认为零。 nrow(.) 定义要生成多少个数字:当前数据帧的每一行一个。 . 表示“当前数据帧。ceiling() 将 [0, 6) 范围内的浮点数转换为 1 到 6 之间的整数。如果您认为我的回答值得,请点击勾选接受它左上角。
    猜你喜欢
    • 1970-01-01
    • 2021-03-04
    • 2021-08-30
    • 2019-09-07
    • 1970-01-01
    • 2021-02-15
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    相关资源
    最近更新 更多