我想生成N
个随机正整数,总和为M
。我希望在一个相当正态的分布周围选择随机正整数,其均值为M/N
,标准差很小(是否可以将其设置为约束?)。
最后,您如何概括产生N个随机正数(不仅仅是整数)的答案?
我发现了其他相关问题,但无法确定如何将答案应用于此背景: https://stats.stackexchange.com/questions/59096/generate-three-random-numbers-that-sum-to-1-in-r
Generate 3 random number that sum to 1 in R
R - random approximate normal distribution of integers with predefined total
答案 0 :(得分:14)
正常化。
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
}
对于连续版本,只需使用:
rand_vect_cont <- function(N, M, sd = 1) {
vec <- rnorm(N, M/N, sd)
vec / sum(vec) * M
}
rand_vect(3, 50)
# [1] 17 16 17
rand_vect(10, 10, pos.only = FALSE)
# [1] 0 2 3 2 0 0 -1 2 1 1
rand_vect(10, 5, pos.only = TRUE)
# [1] 0 0 0 0 2 0 0 1 2 0
rand_vect_cont(3, 10)
# [1] 2.832636 3.722558 3.444806
rand_vect(10, -1, pos.only = FALSE)
# [1] -1 -1 1 -2 2 1 1 0 -1 -1
答案 1 :(得分:1)
提出了一种算法,以均匀分布的方式生成大于或等于k的N个随机数,其和为S。我希望它在这里有用!
首先,在k和S-k(N-1)之间生成N-1个随机数。按降序排序。然后,对于所有x i ,i <= N-2,应用x&#39; i = x i - x i + 1 + k,x&#39; N-1 = x N-1 (使用两个缓冲区)。第N个数字只是S减去所有获得数量的总和。这具有为所有可能的组合提供相同概率的优点。如果你想要正整数,k = 0(或者可能是1?)。如果您想要实数,请使用与连续RNG相同的方法。如果你的数字是整数,你可能会关心它们是否能够或不能等于k。祝福!
说明:通过取出其中一个数字,允许有效第N个数的值的所有组合在(N-1)空间中表示时形成单形,其位于(N-1)的一个顶点处-cube(随机值范围描述的(N-1) - 立方体)。生成它们之后,我们必须将N立方体中的所有点映射到单形中的点。为此,我使用了一种三角测量方法,它以降序排列所有可能的坐标排列。通过排序值,我们映射所有(N-1)!他们只有一个人。我们还必须通过减去k并将结果除以S-kN来平移和缩放数字向量,使所有坐标位于[0,1]中。让我们将新坐标命名为y i 。
然后我们通过乘以原始基的逆矩阵来应用变换,如下所示:
/ 1 1 1 \ / 1 -1 0 \
B = | 0 1 1 |, B^-1 = | 0 1 -1 |, Y' = B^-1 Y
\ 0 0 1 / \ 0 0 1 /
其中y&#39; i = y i - y i + 1 。当我们重新缩放坐标时,我们得到: x&#39; i = y&#39; i (S - kN)+ k = y i (S - kN) - y < sub> i + 1 (S - kN)+ k =(x i - k) - (x i + 1 - k)+ k = x i - x i + 1 + k,因此上面的公式。这适用于除最后一个元素之外的所有元素。
最后,我们应该考虑这种转换引入概率分布的失真。实际上,请纠正我,如果我错了,应用于第一个单纯形以获得第二个单纯形的变换不应该改变概率分布。这是证据。
随着区域大小趋于零,除以单纯形式的总体积增加,任何点的概率增加都是该点周围局部区域体积的增加。在这种情况下,两个卷是相同的(只需取基矢量的决定因素)。如果区域体积的线性增加总是等于1,则概率分布将是相同的。我们可以将其计算为变换向量V&#39;的导数的转置矩阵的行列式。 = B -1 V相对于V,当然,它是B -1 。
这个行列式的计算是非常简单的,它给出1,这意味着这些点不会以任何方式扭曲,使得其中一些点比其他点更容易出现。
答案 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