Generating random numbers
Problem
You want to generate random numbers.
Solution
For uniformly distributed (flat) random numbers, use runif()
. By default, its range is from 0 to 1.
runif(1)
# 0.5581546
# Get a vector of 4 numbers
runif(4)
# 0.383330465 0.005814167 0.879704937 0.873534007
# Get a vector of 3 numbers from 0 to 100
runif(3, min=0, max=100)
# 78.09879 85.37001 15.13357
# Get 3 integers from 0 to 100
# Use max=101 because it will never actually equal 101
floor(runif(3, min=0, max=101))
# 40 59 64
# This will do the same thing
sample(1:100, 3, replace=T)
# To generate integers WITHOUT replacement:
sample(1:100, 3, replace=F)
To generate numbers from a normal distribution, use rnorm()
. By default the mean is 0 and the standard deviation is 1.
rnorm(4)
# 1.04043144 -1.02006411 1.97268110 0.02424849
# Use a different mean and standard deviation
rnorm(4, mean=50, sd=10)
# 30.29251 48.75306 51.08491 50.04595
# To check that the distribution looks right, make a histogram of the numbers
x <- rnorm(400, mean=50, sd=10)
hist(x)
Generating repeatable sequences of random numbers
Problem
You want to generate a sequence of random numbers, and then generate that same sequence again later.
Solution
Use set.seed()
, and pass in a number as the seed.
set.seed(423)
runif(3)
# 0.1089715 0.5973455 0.9726307
set.seed(423)
runif(3)
# 0.1089715 0.5973455 0.9726307
Saving the state of the random number generator
Table of contents
- Saving the state of the random number generator
- Problem
- Solution
- Saving and restoring the state of the RNG in functions
- Notes
Problem
You want to save and restore the state of the random number generator
Solution
Save .Random.seed
to another variable.
# For this example, set the random seed
set.seed(423)
runif(3)
# 0.1089715 0.5973455 0.9726307
# Save the seed
oldseed <- .Random.seed
runif(3)
# 0.7973768 0.2278427 0.5189830
# Do some other stuff with RNG here, such as:
# runif(30)
# ...
# Restore the seed
.Random.seed <- oldseed
# Get the same random numbers as before, after saving the seed
runif(3)
# 0.7973768 0.2278427 0.5189830
If no random number generator has been used in your R session, the variable .Random.seed
will not exist. If you cannot be certain that an RNG has been used before attempting to save, the seed, you should check for it before saving and restoring:
oldseed <- NULL
if (exists(".Random.seed")) oldseed <- .Random.seed
# Do some other stuff with RNG here, such as:
# runif(30)
# ...
if (!is.null(oldseed))
.Random.seed <- oldseed
Saving and restoring the state of the RNG in functions
If you attempt to restore the state of the random number generator within a function by using .Random.seed <- x
, it will not work, because this operation changes a local variable named .Random.seed
, instead of the variable in the global envrionment.
Here are two examples. What these functions are supposed to do is generate some random numbers, while leaving the state of the RNG unchanged.
# This is the bad version
bad_rand_restore <- function() {
if (exists(".Random.seed")) oldseed <- .Random.seed
print(runif(3))
if (exists(".Random.seed")) .Random.seed <- oldseed
}
# This is the good version
rand_restore <- function() {
if (exists(".Random.seed")) oldseed <- get(".Random.seed", .GlobalEnv)
print(runif(3))
if (exists(".Random.seed")) assign(".Random.seed", oldseed, .GlobalEnv)
}
# The bad version changes the RNG state, so random numbers keep changing
set.seed(423)
bad_rand_restore()
# 0.1089715 0.5973455 0.9726307
bad_rand_restore()
# 0.7973768 0.2278427 0.5189830
bad_rand_restore()
# 0.6929255 0.8104453 0.1019465
# The good version doesn't alter the RNG state, so random numbers stay the same
set.seed(423)
rand_restore()
# 0.1089715 0.5973455 0.9726307
rand_restore()
# 0.1089715 0.5973455 0.9726307
rand_restore()
# 0.1089715 0.5973455 0.9726307
Notes
.Random.seed
should not be modified by the user.
Rounding numbers
Problem
You want to round numbers.
Solution
A short description of the solution.
x <- seq(-2.5, 2.5, by=.5)
# -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5
# Round to nearest, with .5 values rounded to even number.
round(x)
# -2 -2 -2 -1 0 0 0 1 2 2 2
# Round up
ceiling(x)
# -2 -2 -1 -1 0 0 1 1 2 2 3
# Round down
floor(x)
# -3 -2 -2 -1 -1 0 0 1 1 2 2
# Round toward zero
trunc(x)
# -2 -2 -1 -1 0 0 0 1 1 2 2
It is also possible to round to other values besides one:
x <- c(.001, .07, 1.2, 44.02, 738, 9927)
# 0.001 0.070 1.200 44.020 738.000 9927.000
# Round to one decimal place
round(x, digits=1)
# 0.0 0.1 1.2 44.0 738.0 9927.0
# Round to tens place
round(x, digits=-1)
# 0 0 0 40 740 9930
# Round to nearest 5
round(x/5)*5
# 0 0 0 45 740 9925
# Round to nearest .02
round(x/.02)*.02
# 0.00 0.08 1.20 44.02 738.00 9927.00
Comparing floating point numbers
Problem
Comparing floating point numbers does not always work as you expect. For example:
0.3 == 3*.1
# FALSE
(0.1 + 0.1 + 0.1) - 0.3
# 5.551115e-17
x <- seq(0, 1, by=.1)
# 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
10*x - round(10*x)
# [1] 0.000000e+00 0.000000e+00 0.000000e+00 4.440892e-16 0.000000e+00
# [6] 0.000000e+00 8.881784e-16 8.881784e-16 0.000000e+00 0.000000e+00
#[11] 0.000000e+00
Solution
There is no universal solution, because this issue is inherent to the storage format for non-integer (floating point) numbers, in R and computers in general.