2012-06-12 39 views
9

我希望能夠創建3個(非負的)隨機數,總和爲1,然後重複一遍又一遍。生成3個總和爲1的隨機數R

基本上我試圖在許多試驗中將東西分成三個隨機部分。

雖然我知道

A = runif(3,0,1)

我在想,我可以使用1-A作爲下一次運行,如果最大,但似乎凌亂。

但這些當然不算一個。任何想法,明智的stackoverflow-ers?從

+2

是否可以在生成後重新規範化隨機數? –

+0

如何生成2個隨機數a和b?那麼a + b + c = 1 => c = 1-(a + b) –

+0

並且如果a和b之和大於1? – mmann1123

回答

9

只是隨機的2個數字(0,1),如果假設其ab然後你有:

rand1 = min(a, b) 
rand2 = abs(a - b) 
rand3 = 1 - max(a, b) 
+0

此外,你必須重複生成第二個數字,如果一個== b ...(應該是非常罕見的情況下) – ddzialak

+0

@user so a = 0.85 ,b = 0.99那麼你得到的數字是:0.85,0.14,0.01(對於我來說這些都是非常好的,從0..1開始的3個隨機數) – ddzialak

+3

由此產生的分佈似乎並不完全無關緊要:http://www.jstor。 org/discover/10.2307/2983572?uid = 2129&uid = 2&uid = 70&uid = 4&sid = 21100849643501 and later paper can be free access http://doc.utwente.nl/70657/1/Sleutel67random.pdf – Christian

4

我想這取決於你想上的數字是什麼分佈,但在這裏是一種方式:只要你想

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 
11

這個問題涉及的問題可能比最初看起來更微妙。查看以下後,你可能要仔細考慮您正在使用這些數字來表示流程:

## 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") 

enter image description here

+0

不錯,我是考慮繪製結果,但你已經做到了。有趣的是,看到這些解決方案顯然沒有一個能夠直觀地理解人們喜歡的東西。同樣有趣的是,在這些情節中,你無法真正看到DDZ根據手段做了正確的事情,而AND甚至沒有做到這一點。 – Christian

6

當你想隨機生成添加到1號(或某些其他值),那麼你應該看看Dirichlet Distribution

有一個在gtools包的rdirichlet功能和運行RSiteSearch('Dirichlet')帶來了不少點擊率是很容易導致你的工具這樣做(和它是不是很難代碼手工無論是簡單的狄氏分佈)。

2

這個問題和提出的不同解決方案讓我很感興趣。我對建議的三種基本算法做了一些測試,並對產生的數字產生了多少平均值。

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版本的分佈情況,或者我在評論中提到的相應論文中的哪些參數集,但也許其他人可以弄清楚。