生成总和为固定值的非负(或正)随机整数

时间:2018-09-28 16:33:31

标签: r random

我想将正整数随机分配给G组,这样它们的总和为V

例如,如果G = 3V = 21,则有效结果可能是(7, 7, 7)(10, 6, 5)等。

有直接的方法吗?


编辑者的通知(来自李哲源

如果值不限于整数,则问题很简单,已在Choosing n numbers with fixed sum中解决。

对于整数,有一个先前的问与答:Generate N random integers that sum to M in R,但它看起来更加复杂并且难以遵循。在那里的基于循环的解决方案也不令人满意。

3 个答案:

答案 0 :(得分:3)

非负整数

n为样本大小:

x <- rmultinom(n, V, rep.int(1 / G, G))

是一个G x n矩阵,其中每一列都是一个multinomial样本,总计为V

通过将rep.int(1 / G, G)传递给参数prob,我假设每个组的“成功”概率相同。


正整数

Gregor所述,多项式样本可以包含0。如果不希望这样的样本,则应将其拒绝。结果,我们从截断的多项式分布中采样。

How to generate target number of samples from a distribution under a rejection criterion中,我提出了一种“过采样”方法来实现截短采样的“向量化”。简而言之,知道了接受概率,我们可以估计预期的试验次数M,以查看第一个“成功”(非零)。我们首先对1.25 * M个样本进行抽样,然后在这些样本中至少有一个“成功”。我们随机返回一个作为输出。

以下函数实现了此思想,以生成不为0的截断的多项式样本。

positive_rmultinom <- function (n, V, prob) {
  ## input validation
  G <- length(prob)
  if (G > V) stop("'G > V' causes 0 in a sample for sure!")
  if (any(prob < 0)) stop("'prob' can not contain negative values!")
  ## normalization
  sum_prob <- sum(prob)
  if (sum_prob != 1) prob <- prob / sum_prob
  ## minimal probability
  min_prob <- min(prob)
  ## expected number of trials to get a "success" on the group with min_prob
  M <- round(1.25 * 1 / min_prob)
  ## sampling
  N <- n * M
  x <- rmultinom(N, V, prob)
  keep <- which(colSums(x == 0) == 0)
  x[, sample(keep, n)]
  }

现在让我们尝试

V <- 76
prob <- c(53, 13, 9, 1)

直接使用rmultinom绘制样本有时可能会得到0:

## number of samples that contain 0 in 1000 trials
sum(colSums(rmultinom(1000, V, prob) == 0) > 0)
#[1] 355   ## or some other value greater than 0

但是使用positive_rmultinom不会出现这样的问题:

## number of samples that contain 0 in 1000 trials
sum(colSums(positive_rmultinom(1000, V, prob) == 0) > 0)
#[1] 0

答案 1 :(得分:2)

可能是一种较便宜的方法,但这似乎可行。

G <- 3
V <- 21
m <- data.frame(matrix(rep(1:V,G),V,G))
tmp <- expand.grid(m) # all possibilities
out <- tmp[which(rowSums(tmp) == V),] # pluck those that sum to 'V'
out[sample(1:nrow(out),1),] # randomly select a column

不确定如何处理runif

答案 2 :(得分:0)

我想出了我认为更简单的解决方案。您首先生成从最小到最大范围的随机整数,对它们进行计数,然后制作计数向量(包括零)。

请注意,即使最小值大于零,此解也可能包含零。

希望这能帮助以后解决这个问题的人:)

rand.vect.with.total <- function(min, max, total) {
  # generate random numbers
  x <- sample(min:max, total, replace=TRUE)
  # count numbers
  sum.x <- table(x)
  # convert count to index position
  out = vector()
  for (i in 1:length(min:max)) {
    out[i] <- sum.x[as.character(i)]
  }
  out[is.na(out)] <- 0
  return(out)
}

rand.vect.with.total(0, 3, 5)
# [1] 3 1 1 0

rand.vect.with.total(1, 5, 10)
#[1] 4 1 3 0 2

请注意,我也在此处发布了此内容 Generate N random integers that sum to M in R,但此答案与这两个问题都相关。