我想将正整数随机分配给G
组,这样它们的总和为V
。
例如,如果G = 3
和V = 21
,则有效结果可能是(7, 7, 7)
,(10, 6, 5)
等。
有直接的方法吗?
编辑者的通知(来自李哲源)
如果值不限于整数,则问题很简单,已在Choosing n numbers with fixed sum中解决。
对于整数,有一个先前的问与答:Generate N random integers that sum to M in R,但它看起来更加复杂并且难以遵循。在那里的基于循环的解决方案也不令人满意。
答案 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,但此答案与这两个问题都相关。