私は、合計が 1 になる 3 つの (非負の) 準乱数を作成し、何度も繰り返すことを望んでいます。
基本的に、私は多くの試行で何かを 3 つのランダムな部分に分割しようとしています。
自覚しながら
a = runif(3,0,1)
1-a
次はマックスで使えるかなと思っていたのrunif
ですが、むずかしそうです。
しかし、これらはもちろん 1 つにはなりません。賢明なスタックオーバーフローの皆さん、何か考えはありますか?
この質問には、一見すると明らかな問題よりも微妙な問題が含まれます。以下を確認した後、これらの数値を使用して表すプロセスについて慎重に検討する必要がある場合があります。
## 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')
数値にどのような分布が必要かによって異なりますが、1つの方法を次に示します。
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 つの基本的なアルゴリズムと、生成された数値に対してどのような平均値が得られるかについて、少しテストを行いました。
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] で 1 つの値 a を選択し、次に [a,1] で 1 つを選択し、残っているものを調べます。 . 合計すると 1 になりますが、それだけです。最初の区画は、他の 2 つの区画の 2 倍の大きさです。人は多くのことを推測したかもしれません...
choose_two_points_and_use_intervals は、ddzialak ( DDZ ) によって受け入れられた回答です。間隔 [0,1] 内の 2 つのポイントを取り、これらのポイントによって作成される 3 つのサブ間隔のサイズを 3 つの数値として使用します。魔法のように機能し、手段はすべて1/3です。
choose_three_and_normalize は、Anders Gustafsson と Josh O'Brien ( JOB ) によるソリューションです。[0,1] で 3 つの数値を生成し、それらを正規化して合計 1 に戻すだけです。私の Python 実装では、驚くほど速く、同じように機能します。分散は、2 番目の解よりも少し低くなります。
そこにあります。これらのソリューションがどのベータ分布に対応しているか、またはコメントで参照した対応する論文のどのパラメータのセットに対応しているかはわかりませんが、他の誰かがそれを理解できるかもしれません。
最も簡単な解決策は、Wakefieldパッケージのprobs()関数です。
probs(3) は、合計が 1 の 3 つの値のベクトルを生成します。
rep(probs(3),x) ができるとすれば、x は「何度も」です。
ドラマがない