単位円と単位正方形の間の点を効率的に生成


17

ここで定義された青い領域からサンプルを生成します。

ここに画像の説明を入力してください

素朴な解決策は、単位平方で棄却サンプリングを使用することですが、これは(〜21.4%)の効率しか提供しません。1π/4

より効率的にサンプリングできる方法はありますか?


6
ヒント:対称性を使用して、効率をわずかに2倍にします。
枢機

3
ああ、値が(0,0)の場合、これは(1,1)にマッピングできますか?私はそのアイデアが大好きです
-Cam.Davidson.Pilon

@cardinal効率の4倍ではないでしょうか?でサンプリングしてから、x軸、y軸、および原点でミラーリングできます。[0,,1]×[0,,1]
マーティンクレーマー

1
@Martin:4つの対称領域にまたがって重複がありますが、より慎重に対処する必要があります。
枢機

3
@Martin:あなたが説明していることを理解している場合、それは効率をまったく向上せません。(1つのポイントを見つけて、サイズの4倍の領域で他の3つのポイントを知っています。これは可能性に応じて確率1でユニットディスク内に存在するかしないかです。効率化のポイントは生成された各の受け入れ確率を高めることです。おそらく私は密度の高い人ですか?x y (x,y)(x,y)
枢機

回答:


10

1秒間に200万ポイントはできますか?

分布は対称です。完全な円の8分の1の分布を計算し、それを他のオクタントの周りにコピーするだけです。極座標では、値でのランダムな位置の角度累積分布は、三角形から延びる円弧に。これにより、Θ X Y θ 0 0 1 0 1 黄褐色θ 1 0 COS θ θ (r,θ)Θ(X,Y)θ(0,0),(1,0),(1,tanθ)(1,0)(cosθ,sinθ)

FΘ(θ)=Pr(Θθ)12tan(θ)θ2,

その密度は

fΘ(θ)=ddθFΘ(θ)tan2(θ).

たとえば、棄却法(効率)を使用して、この密度からサンプリングできます。8/π254.6479%

動径座標の条件付き密度は、と間の比例します。これは、CDFの簡単な反転でサンプリングできます。Rrdrr=1r=secθ

独立したサンプルを生成する場合、デカルト座標への変換はこのオクタントをサンプリングします。サンプルは独立しているため、座標をランダムに交換すると、必要に応じて最初の象限から独立したランダムサンプルが生成されます。(ランダムスワップでは、スワップする実現の数を決定するために、1つのBinomial変数のみを生成する必要があります。)(ri,θi)(xi,yi)

このような各実現には、平均して、1つの一様変量()に倍の2つの一様変量()と少量の(高速)計算が必要です。だこれ(当然のことながら、2点の座標を持っている、)ポイントごと変量。詳細は以下のコード例にあります。この図は、生成された50万点以上のうち10,000点をプロットしています。(X,Y)R1/(8π2)Θ4/(π4)4.66

図

Rこのシミュレーションを作成し、タイミングを調整したコードを次に示します。

n.sim <- 1e6
x.time <- system.time({
  # Generate trial angles `theta`
  theta <- sqrt(runif(n.sim)) * pi/4
  # Rejection step.
  theta <- theta[runif(n.sim) * 4 * theta <= pi * tan(theta)^2]
  # Generate radial coordinates `r`.
  n <- length(theta)
  r <- sqrt(1 + runif(n) * tan(theta)^2)
  # Convert to Cartesian coordinates.
  # (The products will generate a full circle)
  x <- r * cos(theta) #* c(1,1,-1,-1)
  y <- r * sin(theta) #* c(1,-1,1,-1)
  # Swap approximately half the coordinates.
  k <- rbinom(1, n, 1/2)
  if (k > 0) {
    z <- y[1:k]
    y[1:k] <- x[1:k]
    x[1:k] <- z
  }
})
message(signif(x.time[3] * 1e6/n, 2), " seconds per million points.")
#
# Plot the result to confirm.
#
plot(c(0,1), c(0,1), type="n", bty="n", asp=1, xlab="x", ylab="y")
rect(-1, -1, 1, 1, col="White", border="#00000040")
m <- sample.int(n, min(n, 1e4))
points(x[m],y[m], pch=19, cex=1/2, col="#0000e010")

1
「サンプルは独立しているため、2番目のサンプルごとに座標を体系的に交換すると、必要に応じて最初の象限から独立したランダムサンプルが生成されます。」サンプルごとに座標を体系的に交換すると、非常に依存性の高いサンプルが生成されるように思えます。たとえば、コードでの実装では、同じオクタントから50万個のサンプルが連続して生成されるように思えますか?
A.レックス

7
厳密に言えば、このアプローチは2つのオクタントで同じ数のサンプルを生成するため、(iidポイントに対して)まったく機能しません。したがって、サンプルポイントは依存しています。ここで、各サンプルのオクタントを決定するために、偏りのないコインを反転させると...-
枢機

1
@枢機youあなたは正しいです。それを修正します-生成するランダム変量の数を(漸近的に)増やすことなく!
whuber

2
厳密に言えば(また、最も純粋な理論的な意味でのみ)、有限サンプルの場合、追加の一様なランダム変量は必要ありません。つまり、最初の一様ランダム変量から、最初のビットから反転シーケンスを構築します。次に、生成された最初の座標として剰余(倍)を使用します。n2n
枢機

2
@ Xi'an便利な計算可能な逆行列を取得できませんでした。(効率は)に比例する密度の分布から棄却サンプリングすることにより、わずかに改善できます。逆正弦を計算する必要があるコスト。2sin(θ)2(4π)/(π2)75%
whuber

13

これまでの@ cardinal、@ whuber、@ stephan-kolassaによる他のソリューションよりもシンプル、効率的、および/または計算的に安価なソリューションを提案します。

次の簡単な手順が含まれます。

1)2つの標準均一サンプルを描画します:

u1Unif(0,1)u2Unif(0,1).

2a)次のせん断変換をポイント (右下の三角形の点は左上の三角形に反映され、「un- 2b)に反映」: min{u1,u2},max{u1,u2}

[xy]=[11]+[2212210][min{u1,u2}max{u1,u2}].

2b)場合、と交換します。xyu1>u2

3)単位円内にある場合(受け入れ率は約72%)、つまり、場合、サンプルを拒否します

x2+y2<1.

このアルゴリズムの背後にある直感を図に示します。 ここに画像の説明を入力してください

ステップ2aおよび2bは、単一のステップにマージできます。

2)せん断変換を適用し、

x=1+22min(u1,u2)u2y=1+22min(u1,u2)u1

次のコードは、上記のアルゴリズムを実装しています(@whuberのコードを使用してテストします)。

n.sim <- 1e6
x.time <- system.time({
    # Draw two standard uniform samples
    u_1 <- runif(n.sim)
    u_2 <- runif(n.sim)
    # Apply shear transformation and swap
    tmp <- 1 + sqrt(2)/2 * pmin(u_1, u_2)
    x <- tmp - u_2
    y <- tmp - u_1
    # Reject if inside circle
    accept <- x^2 + y^2 > 1
    x <- x[accept]
    y <- y[accept]
    n <- length(x)
})
message(signif(x.time[3] * 1e6/n, 2), " seconds per million points.")
#
# Plot the result to confirm.
#
plot(c(0,1), c(0,1), type="n", bty="n", asp=1, xlab="x", ylab="y")
rect(-1, -1, 1, 1, col="White", border="#00000040")
m <- sample.int(n, min(n, 1e4))
points(x[m],y[m], pch=19, cex=1/2, col="#0000e010")

いくつかの簡単なテストでは、次の結果が得られます。

アルゴリズム/stats//a/258349。ベストオブ3:100万ポイントあたり0.33秒。

このアルゴリズム。ベストオブ3:100万ポイントあたり0.18秒。


3
+1非常によくできました!思慮深く、賢く、シンプルなソリューションを共有していただきありがとうございます。
whuber

いい案!私は単位sqからこの部分へのマッピングを考えていましたが、不完全なマッピングとその後の拒絶スキームについては考えませんでした。心を広げてくれてありがとう!
Cam.Davidson.Pilon

7

まあ、より効率的に行うことができますが、あなたがより速く探していないことを願っています。

アイデアは、最初に値をサンプリングし、各値の上にある青い垂直スライスの長さに比例した密度でサンプリングすることです。xx

f(x)=11x2.

Wolframはそれを統合するのに役立ちます

0xf(y)dy=12x1x2+x12arcsinx.

したがって、累積分布関数はこの式になり、1に積分するようにスケーリングされます(つまり、で除算されます)。F01f(y)dy

ここで、値を生成するために、から間に均一に分布する乱数選択します。[検索ように。つまり、CDFを反転する必要があります(逆変換サンプリング)。これは実行できますが、簡単ではありません。速くもありません。xt01xF(x)=t

最後に、与えられた場合、と間に均一に分布するランダムを選択します。xy1x21

以下はRコードです。値のグリッドでCDFを事前評価していることに注意してください。その場合でも、かなりの時間がかかります。x

考えを入れれば、CDFの反転をかなり高速化できるでしょう。その後、再び、思考が痛い。私は個人的に私が持っていた場合を除き、より速く、はるかに少ないエラーが発生しやすい棄却サンプリングのために行くだろう、非常に良い理由がありません。

epsilon <- 1e-6
xx <- seq(0,1,by=epsilon)
x.cdf <- function(x) x-(x*sqrt(1-x^2)+asin(x))/2
xx.cdf <- x.cdf(xx)/x.cdf(1)

nn <- 1e4
rr <- matrix(nrow=nn,ncol=2)
set.seed(1)
pb <- winProgressBar(max=nn)
for ( ii in 1:nn ) {
    setWinProgressBar(pb,ii,paste(ii,"of",nn))
    x <- max(xx[xx.cdf<runif(1)])
    y <- runif(1,sqrt(1-x^2),1)
    rr[ii,] <- c(x,y)
}
close(pb)

plot(rr,pch=19,cex=.3,xlab="",ylab="")

ランダム


チェビシェフ多項式を使用してCDFを近似すると、評価速度が向上するかどうか疑問に思います。
シコラックスは、モニカを復活させる

@Sycorax、修正なしではない; たとえばエンドポイントでの代数的特異点のchebfun処理を参照してください。
JMは、統計学者ではありません
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.