简体   繁体   English

R 仿真,For循环

[英]R Simulation, For loop

I am solving a R-simulation qn, when the sum of the 2 dice == the round number (ie round 1, round 2...) then add 1 point to the player, else return 0 points.我正在求解一个 R 模拟 qn,当 2 个骰子的总和 == 轮数(即第 1 轮、第 2 轮...)时,给玩家加 1 分,否则返回 0 分。 But I am unfamiliar with R for-loop.但我不熟悉 R for-loop。 Appreciate if anyone could help!感谢是否有人可以提供帮助!

Here is my rough plan, but the code doesn't work out well.这是我的粗略计划,但代码效果不佳。 Eventually, I will want to change the player number and number of iterations easily.最终,我会想轻松地更改玩家人数和迭代次数。

  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
  
  }

This might be helpful这可能会有所帮助

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

In general, if you're coding in R and considering a for loop, there's probably a better way to do it.一般来说,如果您在 R 中进行编码并考虑使用for循环,则可能有更好的方法。 I think this is a case in point.我认为这是一个很好的例子。 Also, whilst Ha Nguyen's solution is correct for the use case you have in your question, it will be dificult to generalise.此外,虽然 Ha Nguyen 的解决方案对于您在问题中遇到的用例是正确的,但很难一概而论。 This is because your data structure is not tidy .这是因为你的数据结构不整齐 It's not tidy because your column names contain data: the numeric suffices indicate which die roll/player/etc the contents relate to.它不整洁,因为您的列名包含数据:数字足以表明内容与哪个骰子/玩家/等相关。 The code is therefore fragile with respect to changes in the number of players, rolls and rounds you are simulating.因此,对于您正在模拟的玩家数量、掷骰数和回合数的变化,该代码是脆弱的。

A tidy solutuon would avoid this issue by using a single column to contain the die roll and have additional columns to indicate the round and player to which the die roll relates.一个整洁的解决方案将通过使用单个列来包含掷骰子并使用额外的列来指示掷骰子所涉及的回合和玩家来避免这个问题。

Here's a posible implementation:这是一个可能的实现:

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

And an example use和一个例子使用

# 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

Player scores are summarised easily:玩家分数很容易总结:

# 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

You could of course include the summary in the simulate function, but I'm not sure what your actual use case is, so I left it out.您当然可以在simulate function 中包含摘要,但我不确定您的实际用例是什么,所以我把它省略了。

The code will handle other numbers of players, rounds and rolls just by changing parameter values:代码将通过更改参数值来处理其他数量的玩家、回合和滚动:

# 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

The tidy solution is more robust than using the for loop and should be noticably faster for "large" datasets.整洁的解决方案比使用for循环更健壮,并且对于“大型”数据集应该明显更快。 It's also more compact and, I believe, easier to understand.它也更紧凑,我相信,更容易理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM