# playing Game-A once
set.seed(20)
= 1:6
die = sample(die, size = 4, replace = TRUE)
four_rolls = any(four_rolls)
win win
[1] TRUE
By now you know that Game-A involves rolling a (fair) die four times, and you win if you get at least one six.
You’ve also learned that we can write some code to play this game once, determining the winning status:
# playing Game-A once
set.seed(20)
= 1:6
die = sample(die, size = 4, replace = TRUE)
four_rolls = any(four_rolls)
win win
[1] TRUE
We are ready to write code and use it to play Game-A five times
set.seed(133)
= 1:6
die
= sample(die, size = 4, replace = TRUE)
game_1 = sample(die, size = 4, replace = TRUE)
game_2 = sample(die, size = 4, replace = TRUE)
game_3 = sample(die, size = 4, replace = TRUE)
game_4 = sample(die, size = 4, replace = TRUE)
game_5
# win (or lose)?
= c(
wins "game_1" = any(game_1 == 6),
"game_2" = any(game_2 == 6),
"game_3" = any(game_3 == 6),
"game_4" = any(game_4 == 6),
"game_5" = any(game_5 == 6))
# number of wins
= sum(wins)
total_wins total_wins
[1] 3
# proportion of wins
= sum(wins) / 5
prop_wins prop_wins
[1] 0.6
As you can tell, the above code works, but there is a substantial amount of unnecessary repetition. Imagine copying-pasting the sample()
command if we wanted to play Game-A 50 times, or 100 times, or 1000 times.
for()
loopThe above code generates the following five games (each game with 4 rolls)
To avoid repeating the same commands multiple times, we can take advantage of loops, for example a for()
loop.
Instead of using individual vectors game_1
, game_2
, etc, we are going to use a matrix to store the rolls of all games. One option for this matrix is to initialize it in a way that rows correspond to games, while columns correspond to rolls:
The idea is to have an iterative process in which each iteration is associated to a game. In other words, at each iteration we play a single game, and we store the output of the rolls in the associated row of the matrix. Here’s how.
set.seed(133)
= 1:6
die = 5
number_games
# initialize output matrix (full of zeros)
= matrix(0, nrow = number_games, ncol = 4)
games
# each iteration corresponds to a single game
for (game in 1:number_games) {
= sample(die, size = 4, replace = TRUE)
games[game, ]
}
rownames(games) = paste0("game", 1:number_games)
colnames(games) = paste0("roll", 1:4)
games
roll1 roll2 roll3 roll4
game1 1 6 4 1
game2 5 1 1 6
game3 2 5 5 4
game4 2 6 6 1
game5 4 1 1 1
Observe the calls of rownames()
and colnames()
to assign names to both the rows and the columns of the games
matrix. In turn, the row and column names are created with paste0()
to generate the necessary character vectors.
Now that we have our for()
loop in place, we can easily increase the number of games. For instance, consider 10 games. Taking into account the preceding code chunk, all we have to do is change the value of number_games
from 5 to 10.
set.seed(133)
= 1:6
die = 10
number_games
# initialize output matrix
= matrix(0, nrow = number_games, ncol = 4)
games
for (game in 1:number_games) {
= sample(die, size = 4, replace = TRUE)
games[game, ]
}
rownames(games) = paste0("game", 1:number_games)
colnames(games) = paste0("roll", 1:4)
games
roll1 roll2 roll3 roll4
game1 1 6 4 1
game2 5 1 1 6
game3 2 5 5 4
game4 2 6 6 1
game5 4 1 1 1
game6 4 3 4 2
game7 6 3 1 3
game8 4 2 1 1
game9 1 6 2 1
game10 5 1 6 5
As you can tell, we get a matrix games
with 10 rows and 4 columns.
We still need to determine the status of each game: do we win? or do we lose?
Conceptually, we could write another for()
loop to determine the status of each game: win or lose; something like this
# initialize (logical) vector
= logical(length = number_games)
wins
for (game in 1:number_games) {
= any(games[game, ] == 6)
wins[game]
} wins
[1] TRUE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE TRUE
What are we doing in the preceding loop? Simply put, we are applying the any()
function to every row of matrix games
to see if any of the row elements are equal to six. This is illustrated in the following diagram:
While there is nothing conceptually wrong with the above for()
loop, we can take advantage of other functions in R to help us write code in a more compact way. Let’s learn about this topic in the next chapter.