我希望创建 3 个(非负)总和为 1 的准随机数,并一遍又一遍地重复。
基本上,我试图在多次试验中将某些东西分成三个随机部分。
虽然我知道
a = runif(3,0,1)
我在想我可以1-a
在 next 中用作 max runif
,但它看起来很乱。
但这些当然不等于一个。任何想法,哦,明智的stackoverflow-ers?
这个问题涉及的问题比起初可能明显的要微妙。查看以下内容后,您可能需要仔细考虑使用这些数字表示的过程:
## My initial idea (and commenter Anders Gustafsson's):
## Sample 3 random numbers from [0,1], sum them, and normalize
jobFun <- function(n) {
m <- matrix(runif(3*n,0,1), ncol=3)
m<- sweep(m, 1, rowSums(m), FUN="/")
m
}
## Andrie's solution. Sample 1 number from [0,1], then break upper
## interval in two. (aka "Broken stick" distribution).
andFun <- function(n){
x1 <- runif(n)
x2 <- runif(n)*(1-x1)
matrix(c(x1, x2, 1-(x1+x2)), ncol=3)
}
## ddzialak's solution (vectorized by me)
ddzFun <- function(n) {
a <- runif(n, 0, 1)
b <- runif(n, 0, 1)
rand1 = pmin(a, b)
rand2 = abs(a - b)
rand3 = 1 - pmax(a, b)
cbind(rand1, rand2, rand3)
}
## Simulate 10k triplets using each of the functions above
JOB <- jobFun(10000)
AND <- andFun(10000)
DDZ <- ddzFun(10000)
## Plot the distributions of values
par(mfcol=c(2,2))
hist(JOB, main="JOB")
hist(AND, main="AND")
hist(DDZ, main="DDZ")
只是从 (0, 1) 中随机抽取 2 个数字,如果假设它a
,b
那么你得到:
rand1 = min(a, b)
rand2 = abs(a - b)
rand3 = 1 - max(a, b)
当您想随机生成加 1(或其他值)的数字时,您应该查看Dirichlet Distribution。
包中有一个rdirichlet
函数,gtools
运行RSiteSearch('Dirichlet')
会带来很多点击,可以很容易地引导您找到执行此操作的工具(对于简单的 Dirichlet 发行版,手动编写代码也不难)。
我想这取决于您想要的数字分布,但这是一种方法:
diff(c(0, sort(runif(2)), 1))
用于replicate
获取任意数量的集合:
> x <- replicate(5, diff(c(0, sort(runif(2)), 1)))
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 0.66855903 0.01338052 0.3722026 0.4299087 0.67537181
[2,] 0.32130979 0.69666871 0.2670380 0.3359640 0.25860581
[3,] 0.01013117 0.28995078 0.3607594 0.2341273 0.06602238
> colSums(x)
[1] 1 1 1 1 1
我会简单地从均匀分布中随机选择 3 个数字,然后除以它们的总和。代码如下。
n <- 3
x <- runif(3, 0, 1)
y <- x/sum(x)
sum(y)== 1
n 可以是您喜欢的任何数字。
这个问题和提出的不同解决方案引起了我的兴趣。我对建议的三种基本算法以及它们为生成的数字产生的平均值做了一些测试。
choose_one_and_divide_rest
means: [ 0.49999212 0.24982403 0.25018384]
standard deviations: [ 0.28849948 0.22032758 0.22049302]
time needed to fill array of size 1000000 was 26.874945879 seconds
choose_two_points_and_use_intervals
means: [ 0.33301421 0.33392816 0.33305763]
standard deviations: [ 0.23565652 0.23579615 0.23554689]
time needed to fill array of size 1000000 was 28.8600130081 seconds
choose_three_and_normalize
means: [ 0.33334531 0.33336692 0.33328777]
standard deviations: [ 0.17964206 0.17974085 0.17968462]
time needed to fill array of size 1000000 was 27.4301018715 seconds
时间测量需要谨慎,因为它们可能更多地受到 Python 内存管理的影响,而不是算法本身。我懒得用timeit
. 我在 1GHz Atom 上做了这个,这就解释了为什么花了这么长时间。
无论如何,choose_one_and_divide_rest 是 Andrie 和他/她自己提出的问题 ( AND ) 提出的算法:你在 [0,1] 中选择一个值 a,然后在 [a,1] 中选择一个值,然后看看你剩下的. 它加起来是一个,但仅此而已,第一个分区是其他两个分区的两倍。人们可能已经猜到了...
choose_two_points_and_use_intervals 是 ddzialak ( DDZ ) 接受的答案。它在区间 [0,1] 中取两个点,并使用这些点创建的三个子区间的大小作为三个数字。像魅力一样工作,手段都是1/3。
choose_three_and_normalize 是 Anders Gustafsson 和 Josh O'Brien ( JOB ) 的解决方案。它只是在 [0,1] 中生成三个数字,并将它们归一化为总和 1。在我的 Python 实现中工作得同样好,而且出乎意料地快了一点。方差比第二种解决方案略低。
你有它。不知道这些解决方案对应于什么 beta 分布,也不知道我在评论中提到的相应论文中的哪组参数,但也许其他人可以弄清楚这一点。
最简单的解决方案是Wakefield包probs()函数
probs(3) 将产生三个值的向量,总和为 1
假设你可以 rep(probs(3),x) 其中 x 是“一遍又一遍”
没有戏剧