Search code examples
rdataframerep

How to generate the same value per ID (for 1000 IDs in total) with rnorm?


I want to create a data.frame which should contain a parameter value (body surface area, BSA). It should be generated in this data.frame using rnorm() for 1000 IDs. With

BSA<-data.frame(rep(rnorm(n = 1000, mean = 1.81, sd = 0.2)))

I can easily obtain those values for 1000 IDs. However, I want to have not only 1 but 36 observations per ID. How can I generate the same BSA value based on the above-mentioned mean and SD 36 times for one ID and performing this procedure for 1000 IDs in total?

Unfortunately,

data.frame(rep(rnorm(1, 1.81, 0.2), times=36),times = 1000))

does not work, of course.

EDIT: The output should look like this:

1.89
1.89
1.89
1.67
1.67
1.67
1.74
1.74
1.74

That would be three observations per ID in one column.

EDIT2: The code could look like this:

BSA<-data.frame(c(rep(rnorm(1, 1.81, 0.2), times=36), rep(rnorm(1, 1.81, 0.2), times=36)))

This would generate the desired output for two IDs but it's not very feasible to perform this for 1000 IDs.


Solution

  • You could use cbind in principle, and draw one rnorm per each "id".

    n <- 36  ## 36 IDs
    o <- 5  ## 5 observations (change to 1000 in your case)
    
    set.seed(42)
    res <- do.call(rbind.data.frame, lapply(1:n, function(i) 
      cbind(id=i, o=1:o, v=rnorm(1, 1.81, .2))))
    res[1:15, ]
    #    id o        v
    # 1   1 1 2.084192
    # 2   1 2 2.084192
    # 3   1 3 2.084192
    # 4   1 4 2.084192
    # 5   1 5 2.084192
    # 6   2 1 1.697060
    # 7   2 2 1.697060
    # 8   2 3 1.697060
    # 9   2 4 1.697060
    # 10  2 5 1.697060
    # 11  3 1 1.882626
    # 12  3 2 1.882626
    # 13  3 3 1.882626
    # 14  3 4 1.882626
    # 15  3 5 1.882626
    

    Or, if you want a vector, mix rep and replicate, then concatenate the result,

    set.seed(42)
    res2 <- do.call(c, replicate(n, rep(rnorm(1, 1.81, .2), o), simplify=F))
    

    even simpler using the each= argument of rep (thanks to @Onyambu).

    set.seed(42)
    res2 <- rep(rnorm(o, 1.81, .2), each=n)
    
    res2[1:15]
    # [1] 2.084192 2.084192 2.084192 2.084192 2.084192 1.697060
    # [7] 1.697060 1.697060 1.697060 1.697060 1.882626 1.882626
    # [13] 1.882626 1.882626 1.882626
    

    To get a data frame, just do as.data.frame(res2) of course, or something similar.