George
George

Reputation: 684

Writing a for loop with the output as a data frame in R

I am currently working my way through the book 'R for Data Science'.

I am trying to solve this exercise question (21.2.1 Q1.4) but have not been able to determine the correct output before starting the for loop.

Write a for loop to: Generate 10 random normals for each of μ= −10, 0, 10 and 100.

Like the previous questions in the book I have been trying to insert into a vector output but for this example, it appears I need the output to be a data frame?

This is my code so far:

values <- c(-10,0,10,100)
output <- vector("double", 10)

for (i in seq_along(values)) {
  output[[i]] <- rnorm(10, mean = values[[i]])
} 

I know the output is wrong but am unsure how to create the format I need here. Any help much appreciated. Thanks!

Upvotes: 0

Views: 22041

Answers (3)

Douglas Zickuhr
Douglas Zickuhr

Reputation: 1

# set the number of rows
rows <- 10

# vector with the values
means <- c(-10,0,10,100)

# generating output matrix
output <- matrix(nrow = rows,
             ncol = 4)

# setting seed and looping through the number of rows
set.seed(222)
for (i in 1:rows){
  output[i,] <- rnorm(length(means),
                  mean=means)
}

#printing the output
output

Upvotes: 0

llrs
llrs

Reputation: 3397

As this is a learning question I will not provide the solution directly.

> values <- c(-10,0,10,100)
> for (i in seq_along(values)) {print(i)} # Checking we iterate by position
[1] 1
[1] 2
[1] 3
[1] 4
> output <- vector("double", 10) 
> output # Checking the place where the output will be
 [1] 0 0 0 0 0 0 0 0 0 0
> for (i in seq_along(values)) { # Testing the full code
+     output[[i]] <- rnorm(10, mean = values[[i]])
+ } 
Error in output[[i]] <- rnorm(10, mean = values[[i]]) : 
  more elements supplied than there are to replace

As you can see the error say there are more elements to put than space (each iteration generates 10 random numbers, (in total 40) and you only have 10 spaces. Consider using a data format that allows to store several values for each iteration. So that:

> output <- ??
> for (i in seq_along(values)) { # Testing the full code
+     output[[i]] <- rnorm(10, mean = values[[i]])
+ } 
> output # Should have length 4 and each element all the 10 values you created in the loop

Upvotes: 1

Roman Luštrik
Roman Luštrik

Reputation: 70653

There are many ways of doing this. Here is one. See inline comments.

set.seed(357) # to make things reproducible, set random seed

N <- 10 # number of loops

xy <- vector("list", N) # create an empty list into which values are to be filled

# run the loop N times and on each loop...
for (i in 1:N) {
  # generate a data.frame with 4 columns, and add a random number into each one
  # random number depends on the mean specified
  xy[[i]] <- data.frame(um10 = rnorm(1, mean = -10),
                        u0 = rnorm(1, mean = 0),
                        u10 = rnorm(1,  mean = 10),
                        u100 = rnorm(1, mean = 100))
}

# result is a list of data.frames with 1 row and 4 columns

# you can bind them together into one data.frame using do.call
# rbind means they will be merged row-wise
xy <- do.call(rbind, xy)

         um10         u0       u10      u100
1  -11.241117 -0.5832050 10.394747 101.50421
2   -9.233200  0.3174604  9.900024 100.22703
3  -10.469015  0.4765213  9.088352  99.65822
4   -9.453259 -0.3272080 10.041090  99.72397
5  -10.593497  0.1764618 10.505760 101.00852
6  -10.935463  0.3845648  9.981747 100.05564
7  -11.447720  0.8477938  9.726617  99.12918
8  -11.373889 -0.3550321  9.806823  99.52711
9   -7.950092  0.5711058 10.162878 101.38218
10  -9.408727  0.5885065  9.471274 100.69328

Another way would be to pre-allocate a matrix, add in values and coerce it to a data.frame.

xy <- matrix(NA, nrow = N, ncol = 4)

for (i in 1:N) {
  xy[i, ] <- rnorm(4, mean = c(-10, 0, 10, 100))
}

# notice that i name the column names post festum
colnames(xy) <- c("um10", "u0", "u10", "u100")
xy <- as.data.frame(xy)

Upvotes: 7

Related Questions