0

I would like to use this code, which I found here: Generate N random integers that sum to M in R. I have a example data frame and I would like to use this function for each Value in data frame.

rand_vect <- function(N, M, sd = 1, pos.only = TRUE) {
  vec <- rnorm(N, M/N, sd)
  if (abs(sum(vec)) < 0.01) vec <- vec + 1
  vec <- round(vec / sum(vec) * M)
  deviation <- M - sum(vec)
  for (. in seq_len(abs(deviation))) {
    vec[i] <- vec[i <- sample(N, 1)] + sign(deviation)
  }
  if (pos.only) while (any(vec < 0)) {
    negs <- vec < 0
    pos  <- vec > 0
    vec[negs][i] <- vec[negs][i <- sample(sum(negs), 1)] + 1
    vec[pos][i]  <- vec[pos ][i <- sample(sum(pos ), 1)] - 1
  }
  vec
}


abc <- data.frame(Product = c("A", "B", "C"), 
                  Value =c(33, 23, 12))
Zizou
  • 503
  • 5
  • 18

2 Answers2

2

You can vectorize your function rand_vect for receiving a array of values

vrand_vect <- Vectorize(rand_vect,"M",SIMPLIFY = F)

which gives

res <- vrand_vect(N= 7, M = abc$Value)
> res
[[1]]
[1] 3 5 6 6 4 3 6

[[2]]
[1] 1 3 4 5 3 4 3

[[3]]
[1] 1 2 3 3 1 2 0
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
1

You can use sapply to run rand_vect with N = 7

sapply(abc$Value, rand_vect, N = 7)

#     [,1] [,2] [,3]
#[1,]    4    4    0
#[2,]    5    2    2
#[3,]    5    4    2
#[4,]    4    3    3
#[5,]    5    5    3
#[6,]    6    2    1
#[7,]    4    3    1

This will give 7 random numbers which will sum upto Value.

We can verify it by

colSums(sapply(abc$Value, rand_vect, N = 7))
#[1] 33 23 12
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • What if I wanted to repeat `sapply` e.g twice, but that the result was different? `rep(sapply(abc$Value, rand_vect, N = 7), 2)`? – Zizou Dec 03 '19 at 09:50
  • 1
    Use `replicate`, `replicate(2, sapply(abc$Value, rand_vect, N = 7), simplify = FALSE)` – Ronak Shah Dec 03 '19 at 09:51
  • What if I have more columns with values? Because now it works for one column? – Zizou Dec 03 '19 at 11:07
  • `rand_vect` takes 1 value at a time. If you have more values bring them together using `unlist` like `sapply(unlist(abc[1:2]), rand_vect, N = 7)` or `lapply(abc[1:2], function(x) sapply(x, rand_vect, N = 7))` based on the output you want. – Ronak Shah Dec 03 '19 at 11:30