円内にランダムな点を(均一に)生成する


212

半径Rの円内に一様にランダムな点を生成する必要があります。

間隔[0 ...2π)で均一にランダムな角度を選択し、間隔(0 ... R)で均一にランダムな半径を選択するだけで、中心に向かってより多くのポイントができ、半径の場合、小さい半径のポイントは、大きい半径のポイントよりも互いに近くなります。

私はここでこれに関するブログエントリを見つけましたが、彼の推論がわかりません。私はそれが正しいと思いますが、彼が(2 / R 2)× rをどこから得るか、そして彼が最終的な解をどのように導出するかを本当に理解したいと思います。


更新:この質問を投稿してから7年後も、平方根アルゴリズムの背後にある数学に関する実際の質問については、満足のいく答えが得られませんでした。それで私は自分で答えを書いて一日過ごしました。私の回答へのリンク


18
拒否サンプリングの欠点は本当に大きな問題ですか?必要な試行回数は4 /π≈1.27であり、k回を超える試行が必要になる確率は(1-π/ 4)^ kです。以下のために、K = 20、これは≈0.00000000000004であり、k = 50のためには、10 ^のオーダーの{ - 34}。あなたはそれらのオッズをいつでも取ることができます。元気です
ShreevatsaR 2011

3
実際には、拒否のサンプリングは終了の保証を提供します。オッズは無限に低く(正確にはゼロ)、アルゴリズムが終了することはありません。
Jared Nielsen

2
私の意見では、棄却サンプリングの欠点の重要性は、棄却を回避するサンプリング方法の使いやすさに比例します。この場合、拒否なしのサンプリングが単純であるため、欠点は重要です。
spex 2014

4
@spex実際には、超越関数評価の必要性を回避するため、拒否手法はより高速です。
pjs 2015

2
(続き)拒絶:0.52sすべてが同じ平均と標準偏差を与えました(3 sig図まで)。予想どおり、拒否のサンプリングは27%の確率で失敗しました(4 / pi-1)。そのため、btillyより27%多く、sigfpeより15%少ない乱数が必要でした。これは、乱数の生成に非常にコストがかかる場合を除いて、拒否サンプリングがおそらく最良のアプローチであるというpjsなどのコメントを裏付けています。
Peter Davidson、

回答:


189

アルキメデスのようにこれに取り組みましょう。

| AB | = | BC |である三角形ABCに点を均一に生成するにはどうすればよいですか?平行四辺形ABCDに拡張して、これを簡単にしましょう。ABCDで均一にポイントを生成するのは簡単です。ABのランダムな点XとBCのYを一様に選び、XBYZが平行四辺形になるようにZを選択します。元の三角形で均一に選択されたポイントを取得するには、ADCに表示されるポイントを折り返し、ACに沿ってABCに戻します。

今、円を考えてみましょう。極限では、Bを原点に、AとCを原点に、互いにほぼゼロに近い、無限に多くの二等辺三角形ABCと考えることができます。角度シータを選択するだけで、これらの三角形の1つを選択できます。したがって、スライバーABCの点を選択して、中心からの距離を生成する必要があります。もう一度、ABCDに拡張します。ここで、Dは円の中心から半径の2倍になっています。

ABCDでランダムなポイントを選択することは、上記の方法を使用すると簡単です。AB上のランダムな点をピックします。BC上のランダムなポイントを均一に選択します。すなわち。中心からの距離を与える[0、R]で乱数xとyのペアを均一に選択します。私たちの三角形は薄いスライバーなので、ABとBCは本質的に平行です。したがって、点Zは単に原点からの距離x + yです。x + y> Rの場合、折り返します。

R = 1の完全なアルゴリズムは次のとおりです。それがかなり簡単であることに同意してください。トリガーを使用しますが、random()拒否のサンプリングとは異なり、かかる時間と必要な呼び出しの数を保証できます。

t = 2*pi*random()
u = random()+random()
r = if u>1 then 2-u else u
[r*cos(t), r*sin(t)]

これはMathematicaにあります。

f[] := Block[{u, t, r},
  u = Random[] + Random[];
  t = Random[] 2 Pi;
  r = If[u > 1, 2 - u, u];
  {r Cos[t], r Sin[t]}
]

ListPlot[Table[f[], {10000}], AspectRatio -> Automatic]

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


6
@Karelzarath私は、無限に薄い三角形の一端が他の端よりもまだ広いという直観に反する概念が好きです:-)正しい答えが得られます。
sigfpe 2011

2
@hammar n次元にうまく一般化されているかどうかはわかりません。しかし、3Dでは、アルキメデスによる別の結果を使用できます。「ハットボックス」の定理を使用して、円柱上にポイントを生成し(簡単!)、それを球にマッピングします。それは方向性を与えます。ここrandom()+random()+random()で、より複雑な折りたたみ(つまり、非常に薄い平行六面体から6面体への6方向の折りたたみ)を使用します。これは良い方法だとは思いませんが。
sigfpe

2
random()+ random()と2 * random()の違いを理解するために1分考えました...私はとても愚かです:/
JiminP

3
@Tharwen円内に、半径0.0-0.1よりも半径0.9-1.0でより多くのポイントがあることに注意してください。random()+ random()は、約1.0になる可能性が高い半径を生成しますが、範囲は0.0〜2.0です。折りたたむと、約1.0になり、常に0.0〜1.0の範囲になります。さらに、それはこのコメントの最初の文に必要な比率です。ちょうど半分にすると、0.5マークの周りにさらに多くの数値が生成されますが、それは間違いです。
sigfpe 2012年

2
@Tharwen両方のスキームを使用して乱数を生成し、得られる結果を確認してください。2 * random()は0から2の範囲で均一に分布する数値を与えます。random()+ random()は0から2の範囲の数値を与えますが、(通常)0.0または2.0の近くよりも1.0の近くでより多くの数があります。2つのサイコロを振って合計すると、他のどの数字よりも7が出る可能性が高いということです。
sigfpe 2012年

133

半径Rの円内にランダムな点を生成する方法:

r = R * sqrt(random())
theta = random() * 2 * PI

(仮定するとrandom()、0と1の間の値が均一に与えられます)

これをデカルト座標に変換したい場合は、

x = centerX + r * cos(theta)
y = centerY + r * sin(theta)


なんでsqrt(random())

に至るまでの数学を見てみましょうsqrt(random())。簡単にするために、単位円、つまりR = 1で作業していると仮定します。

ポイント間の平均距離は、中心からどれだけ離れていても同じでなければなりません。これは、たとえば、円周2の円の外周を見ると、円周1の円の外周にあるポイントの数の2倍のポイントを見つける必要があることを意味します。


                

円(2πの円周のでrが)とともに直線的に成長するR、ランダムな点の数と共に直線的に成長する必要があることを、以下、R。言い換えると、望ましい確率密度関数(PDF)は直線的に増加します。PDFの面積は1で、最大半径は1であるため、次のようになります。


                

これで、ランダム値の望ましい密度がどのようになるかがわかります。さて:0と1の間の一様なランダム値だけがある場合、どのようにしてそのようなランダム値を生成しますか?

逆変換サンプリングと呼ばれるトリックを使用します

  1. PDFから、累積分布関数(CDF)を作成します。
  2. これをy = xに沿ってミラーリングする
  3. 結果の関数を0と1の間の均一な値に適用します。

複雑に聞こえますか?直感を伝える小さなサイドトラックを含むブロッククォートを挿入します。

次の分布を持つランダムポイントを生成するとします。

                

あれは

  • 1と2の間の点の1/5
  • ポイントの4/5は、2〜3の間で均一です。

CDFは、名前が示すように、PDFの累積バージョンです。直感的に:PDF(x)はxでのランダム値の数を表します、CDF(x)はxより小さいランダム値の数を表します。

この場合、CDFは次のようになります。

                

これがどのように役立つかを確認するために、均一に分布した高さで左から右に弾丸を発射すると想像してください。弾丸が線に当たると、それらは地面に落ちます:

                

地上の弾丸の密度がどのように私たちの望ましい分布に対応しているかを見てください!もうすぐ着きます!

問題は、この関数では、y軸が出力で、x軸が入力であるということです。「地面から弾丸を真っ直ぐに発射する」ことしかできません!逆関数が必要です!

これが、すべてをミラーリングする理由です。xyになり、yxになります。

                

これをCDF -1と呼びます。希望の分布に従って値を取得するには、CDF -1(random())を使用します。

…つまり、PDFが2 xに等しいランダムな半径値を生成することに戻ります。

ステップ1:CDFを作成する:

実数で作業しているため、CDFはPDFの積分として表されます。

CDFx)=∫2 x = x 2

ステップ2:y = xに沿ってCDFをミラーリングします。

数学的にこれは、xyを入れ替えてyを解くことに要約されます。

CDF:      Y = X 2
スワップ:    X = Y 2
解く:    Y =√ X
CDF -1:   Y =√ X

ステップ3:結果の関数を0と1の間の均一な値に適用する

CDF -1(random())=√random()

これは、私たちが導き出したものです:-)


このアルゴリズムは、リング上のポイントを効率的に生成するために使用できます。
Ivan Kovtun

リングに?固定半径のように?私があなたの質問を理解しているかどうかはわかりませんが、固定半径がある場合は、角度をランダム化する必要があります。
aioobe

2
2つの同心円で囲まれた領域-環の代わりに、より単純な単語「リング」を使用しようとしました。この場合、拒否アルゴリズムは効果がなくなり、ファーストトップアルゴリズムを一般化するのは困難です。また、半径が1つのコーナーケースもアルゴリズムでカバーされます。min_radius == max_radiusの場合でも、半径は常にsqrt(random(min_radius ^ 2、max_radius ^ 2))として生成されます。
Ivan Kovtun

1
いいね!明確にするために、あなたが言うときrandom(min_radius², max_radius²)、あなたに平均何か同等の操作を行いrandom() * (max_radius² - min_radius²) + min_radius²、どこrandom()戻り0と1の間の一様な値?
aioobe

はい、まさにそれが私が意味することです:radius = sqrt(random()*(max_radius²-min_radius²)+min_radius²)。
Ivan Kovtun

27

ここに高速でシンプルなソリューションがあります。

範囲(0、1)の2つの乱数、つまりaおよびを選択しbます。もしそうならb < a、それらを交換してください。あなたのポイントは(b*R*cos(2*pi*a/b), b*R*sin(2*pi*a/b))です。

このソリューションは次のように考えることができます。円をとったら、それを切り、それを真っ直ぐにすると、直角三角形になります。その三角形を縮小すると、三角形がから(0, 0)(1, 0)(1, 1)またに戻ってになり(0, 0)ます。これらの変換はすべて、密度を均一に変化させます。あなたがやったことは、三角形のランダムな点を一様に選び、プロセスを逆にして円の点を取得することです。


私は、半径によって座標分割する必要がなかったが、これは、何らかの理由で、それ以外の場合は^ 2 Rの円内だ、私に受け入れ答えよりもはるかに均一な分布を与える
グレッグZaal

3
おかげで、これはJavaのコードです。多分誰かがそれを便利だと思うでしょう:float random1 = MathUtils.random(); float random2 = MathUtils.random(); float randomXPoint = random2 * radius MathUtils.cos(MathUtils.PI2 * random1 / random2); float randomYPoint = random2 * radius MathUtils.sin(MathUtils.PI2 * random1 / random2);
Tony Ceralva、2014年

とても良い!ポイントを一元化する可能性を高めるというアイデアが好きなので、これb < aを達成できるときにスワップしないと!例:JavaScript jsfiddle.net/b0sb5ogL/1
ギルヘルム

私はあなたの解決策は悪いと思います。結果は均一ではありません。このスクリーンショットをチェックしてくださいprntscr.com/fizxgc
bolec_kolec

4
円をカットしてまっすぐにする方法をもう少し説明できますか?
kec 2018年

21

半径の逆二乗に比例する点密度に注意してください。したがって、からピックする代わりに、rから[0, r_max]ピックして[0, r_max^2]、座標を次のように計算します。

x = sqrt(r) * cos(angle)
y = sqrt(r) * sin(angle)

これにより、ディスク上の点分布が均一になります。

http://mathworld.wolfram.com/DiskPointPicking.html


12

このように考えてください。1つの軸が半径で1つが角度の長方形があり、この長方形の内側の半径0に近いポイントを取得した場合、これらはすべて原点に非常に近くなります(円上で互いに近くなります)。ただし、半径Rの近くのポイント。これらはすべて円のエッジの近くにあります(つまり、互いに遠く離れています)。

これにより、この動作が発生する理由がわかります。

そのリンクに由来する係数は、円にマップされた後、半径に依存しないように調整する必要がある長方形の対応する領域の大きさを示します。

編集:つまり、彼があなたが共有するリンクに書いているのは、「累積分布の逆数を計算することで簡単に実行でき、r:が得られる」ということです。

基本的な前提は、目的の確率密度関数の累積分布関数の逆関数によってユニフォームをマッピングすることにより、ユニフォームから目的の分布を持つ変数を作成できることです。どうして?とりあえず当たり前のことですが、これは事実です。

これが、数学の私の直感的な説明です。rに関する密度関数f(r)は、r自体に比例する必要があります。この事実を理解することは、基本的な微積分の本の一部です。極領域要素のセクションを参照してください。他のいくつかのポスターはこれについて言及しています。

したがって、f(r)= C * rと呼びます。

これがほとんどの作業です。ここで、f(r)は確率密度であるため、間隔(0、R)にわたってf(r)を積分することにより、C = 2 / R ^ 2になることが簡単にわかります(これは読者のための練習問題です) 。)

したがって、f(r)= 2 * r / R ^ 2

OK、それであなたはリンクで数式を得る方法です。

次に、最後の部分は(0,1)の一様確率変数uからのものです。この望ましい密度f(r)からの累積分布関数の逆関数でマッピングする必要があります。なぜこれが当てはまるのかを理解するには、おそらくPapoulisのような高度な確率テキストを見つける必要があります(または自分で導出する必要があります)。

f(r)を統合すると、F(r)= r ^ 2 / R ^ 2が得られます

これの逆関数を見つけるには、u = r ^ 2 / R ^ 2を設定してからrを解くと、r = R * sqrt(u)が得られます。

これも完全に直感的に理解できます。u= 0はr = 0にマッピングする必要があります。また、u = 1はr = Rにマッピングする必要があります。また、これは平方根関数によって行われるため、リンクに一致します。


10

単純な解が機能しない理由は、円の中心に近い点ほど確率密度が高くなるためです。つまり、半径r / 2の円は、点が選択される確率r / 2を持ちますが、面積(点の数)pi * r ^ 2/4を持ちます。

したがって、半径確率密度には次の特性が必要です。

特定のr以下の半径を選択する確率は、半径rの円の面積に比例する必要があります。(私たちはポイントに均一な分布を持ちたいので、より大きなエリアはより多くのポイントを意味します)

言い換えると、[0、r]の間の半径を選択する確率は、円の全体の面積のシェアと等しくなるようにします。円の総面積はpi * R ^ 2で、半径rの円の面積はpi * r ^ 2です。したがって、[0、r]の間の半径を選択する確率は、(pi * r ^ 2)/(pi * R ^ 2)= r ^ 2 / R ^ 2になるようにします。

数学が登場:

[0、r]の間の半径を選択する確率は、0からrまでのp(r)drの積分です(これは、小さい半径のすべての確率を追加するためです)。したがって、積分(p(r)dr)= r ^ 2 / R ^ 2が必要です。R ^ 2が定数であることがはっきりとわかるので、積分するとr ^ 2のような値が得られるp(r)を見つけるだけです。答えは明らかにr *定数です。積分(r *定数dr)= r ^ 2/2 *定数。これはr ^ 2 / R ^ 2に等しい必要があるため、定数= 2 / R ^ 2です。したがって、確率分布p(r)= r * 2 / R ^ 2があります。

注:この問題について考えるもう1つのより直感的な方法は、半径raの確率密度の各円に、その円周上にある点の数の比率に等しい確率密度を与えようとしていると想像することです。したがって、半径rの円は、円周上に2 * pi * rの「ポイント」を持ちます。ポイントの総数はpi * R ^ 2です。したがって、(2 * pi * r)/(pi * R ^ 2)= 2 * r / R ^ 2に等しい円ra確率を与える必要があります。これははるかに理解しやすく、より直感的ですが、数学的にはそれほど正確ではありません。


9

ρ(半径)とφ(方位角)を、円内の任意の点の極座標に対応する2つの確率変数とする。ポイントが均一に分布している場合、ρとφの分布関数は何ですか?

任意のrの場合:0 <r <Rは、半径座標ρがrより小さい確率は、

P [ρ<r] = P [点は半径rの円内にあります] = S1 / S0 =(r / R)2

ここで、S1とS0はそれぞれ半径rとRの円の領域です。したがって、CDFは次のように指定できます。

          0          if r<=0
  CDF =   (r/R)**2   if 0 < r <= R
          1          if r > R

そしてPDF:

PDF = d/dr(CDF) = 2 * (r/R**2) (0 < r <= R).

R = 1ランダム変数sqrt(X)の場合、Xが[0、1)で均一であることに注意してください(P [sqrt(X)<y] = P [x <y ** 2] = y *のため* 2は0 <y <= 1)。

φの分布は0から2 *πまで明らかに均一です。これでランダムな極座標を作成し、三角方程式を使用してそれらを直交座標に変換できます。

x = ρ * cos(φ)
y = ρ * sin(φ)

R = 1のpythonコードを投稿することに抵抗できません。

from matplotlib import pyplot as plt
import numpy as np

rho = np.sqrt(np.random.uniform(0, 1, 5000))
phi = np.random.uniform(0, 2*np.pi, 5000)

x = rho * np.cos(phi)
y = rho * np.sin(phi)

plt.scatter(x, y, s = 4)

あなたが得るでしょう

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


7

それは本当にあなたが「均一にランダム」で何を意味するかに依存します。これは微妙な点であり、あなたはここでwikiページにそれについてもっと読むことができます:http://en.wikipedia.org/wiki/Bertrand_paradox_%28probability%29、同じ問題、「均一ランダム」に異なる解釈を与えています別の答え!

ポイントの選択方法に応じて、ある意味で一様にランダムであっても、分布は変化する可能性があります。

ブログエントリは、次の意味で一様にランダムにしようとしているようです。中心が同じである円の部分円をとると、その領域に点が入る確率は、その領域に比例します。地域。それは、面積が定義されている 2D領域の「均一にランダム」の現在の標準的な解釈に従うことを試みていると思います。点が任意の領域(面積が適切に定義されている)に入る確率は、その領域の面積に比例します。


5
むしろ、ポイントがに入る確率の任意の領域があると仮定-任意の領域は、領域の面積に比例する面積を有します
ShreevatsaR

@Shree:正解です。これは、かっこ内のステートメントで私が意味するものです。私はそれをより明確にします、ありがとう。ところで、ブログに関しては、任意の領域が比例確率を与えるという実際の証拠はなかったので、私はそれをそのように表現することにしました。

6

num半径の円からランダムポイントを生成するPythonコードはrad次のとおりです。

import matplotlib.pyplot as plt
import numpy as np
rad = 10
num = 1000

t = np.random.uniform(0.0, 2.0*np.pi, num)
r = rad * np.sqrt(np.random.uniform(0.0, 1.0, num))
x = r * np.cos(t)
y = r * np.sin(t)

plt.plot(x, y, "ro", ms=1)
plt.axis([-15, 15, -15, 15])
plt.show()

1
なぜr = np.sqrt(np.random.uniform(0.0, rad**2, num))ですか?

4

この場合、極座標を使用することが問題を複雑にする方法であると思います。ランダムな点を長さ2Rの辺を持つ正方形に選択し、(x,y)そのような点を選択すると、はるかに簡単になりますx^2+y^2<=R^2


あなたはx ^ 2 + y ^ 2 <= R ^ 2を意味すると思います。
sigfpe

1
これは拒否のサンプリングです。それは問題ありませんが、計算時間が多少変動することを意味します。
スティーブベネット

すべての正方形は4辺です。
xaxxon 2016

このアルゴリズムは、平方根やsin / cosの計算を伴うものよりも効率的です。正方形の21.5%未満のポイントを拒否します。
Ivan Kovtun

3

Javaでのソリューションと配布例(2000点)

public void getRandomPointInCircle() {
    double t = 2 * Math.PI * Math.random();
    double r = Math.sqrt(Math.random());
    double x = r * Math.cos(t);
    double y = r * Math.sin(t);
    System.out.println(x);
    System.out.println(y);
}

分布2000ポイント

以前のソリューションに基づくhttps://stackoverflow.com/a/5838055/5224246 @sigfpe


2

まず、次のようなcdf [x]を生成します

点が円の中心からの距離xより小さい確率。円の半径がRであると仮定します。

明らかにxがゼロの場合、cdf [0] = 0

明らかにxがRの場合、cdf [R] = 1

明らかにx = rの場合、cdf [r] =(Pi r ^ 2)/(Pi R ^ 2)

これは、円の各「小さな領域」が選択される確率が同じであるため、確率は問題の領域に比例します。そして、円の中心からの距離xが与えられた面積はPi r ^ 2です。

したがってcdf [x] = x ^ 2 / R ^ 2は、Piが互いに打ち消し合うためです。

cdf [x] = x ^ 2 / R ^ 2があり、xは0からRになります

したがって、xについて解く

R^2 cdf[x] = x^2

x = R Sqrt[ cdf[x] ]

これで、cdfを0から1までの乱数に置き換えることができます。

x = R Sqrt[ RandomReal[{0,1}] ]

最後に

r = R Sqrt[  RandomReal[{0,1}] ];
theta = 360 deg * RandomReal[{0,1}];
{r,theta}

極座標{0.601168 R、311.915度}を取得します


1

半径とその半径に「近い」ポイントの数との間には線形関係があるため、半径分布を使用する必要があります。これにより、半径に近いデータポイントの数もにr比例しrます。


1

私はこの方法を1回使用しました。これは完全に最適化されていない可能性があります(つまり、点の配列を使用しているため、大きな円には使用できません)が、ランダム分布で十分です。マトリックスの作成をスキップして、必要に応じて直接描画することもできます。その方法は、円の中に収まる長方形のすべての点をランダム化することです。

bool[,] getMatrix(System.Drawing.Rectangle r) {
    bool[,] matrix = new bool[r.Width, r.Height];
    return matrix;
}

void fillMatrix(ref bool[,] matrix, Vector center) {
    double radius = center.X;
    Random r = new Random();
    for (int y = 0; y < matrix.GetLength(0); y++) {
        for (int x = 0; x < matrix.GetLength(1); x++)
        {
            double distance = (center - new Vector(x, y)).Length;
            if (distance < radius) {
                matrix[x, y] = r.NextDouble() > 0.5;
            }
        }
    }

}

private void drawMatrix(Vector centerPoint, double radius, bool[,] matrix) {
    var g = this.CreateGraphics();

    Bitmap pixel = new Bitmap(1,1);
    pixel.SetPixel(0, 0, Color.Black);

    for (int y = 0; y < matrix.GetLength(0); y++)
    {
        for (int x = 0; x < matrix.GetLength(1); x++)
        {
            if (matrix[x, y]) {
                g.DrawImage(pixel, new PointF((float)(centerPoint.X - radius + x), (float)(centerPoint.Y - radius + y)));
            }
        }
    }

    g.Dispose();
}

private void button1_Click(object sender, EventArgs e)
{
    System.Drawing.Rectangle r = new System.Drawing.Rectangle(100,100,200,200);
    double radius = r.Width / 2;
    Vector center = new Vector(r.Left + radius, r.Top + radius);
    Vector normalizedCenter = new Vector(radius, radius);
    bool[,] matrix = getMatrix(r);
    fillMatrix(ref matrix, normalizedCenter);
    drawMatrix(center, radius, matrix);
}

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


3
分布は「ランダムで十分」ではありません。それらは、ランダムの特定の定義に対してランダムであるか、ランダムではないかのいずれかです。答えは斜めです。コードにコメントしたり、コードにたどり着いた方法を説明したりしないでください。斜めの答えは、追跡するのが難しく、信頼するのが困難です。
リチャード14

1

円の領域要素は、dA = rdr * dphiです。その余分な因子rは、ランダムにarとphiを選択するというあなたのアイデアを破壊しました。phiはフラットに分布していますが、rはフラットではありませんが、1 / rでフラットです(つまり、「雄牛の目」よりも境界にぶつかる可能性が高くなります)。

したがって、円全体に均等に分布する点を生成するには、フラット分布からphiを選択し、1 / r分布からrを選択します。

あるいは、Mehrdadによって提案されたモンテカルロ法を使用します。

編集

1 / rでランダムなrフラットを選択するには、間隔[1 / R、無限大]からランダムなxを選択し、r = 1 / xを計算します。次に、rは1 / rでフラットに分散されます。

ランダムなファイを計算するには、区間[0、1]からランダムなxを選び、ファイ= 2 * pi * xを計算します。


「1 / r分布」からrを正確に選択するにはどうすればよいですか?
aioobe 2011

0

この質問がすべての答えが既に出されている新しい解決策にまだオープンであるかどうかはわかりませんが、私はたまたま自分自身とまったく同じ質問に直面しました。自分で解決策を「推論」しようとしたところ、解決策が見つかりました。これは、すでにここで提案されているものと同じものかもしれませんが、とにかくここにあります:

円の表面の2つの要素が等しいためには、drが等しいと仮定して、dtheta1 / dtheta2 = r2 / r1が必要です。その要素の確率の表現をP(r、theta)= P {r1 <r <r1 + dr、theta1 <theta <theta + dtheta1} = f(r、theta)* dr * dtheta1として記述し、2つを設定する(r1とr2の)確率が等しい場合、(rとthetaが独立していると仮定して)f(r1)/ r1 = f(r2)/ r2 =定数に到達すると、f(r)= c * rが得られます。そして残りは、定数cを決定することは、PDFであるf(r)の条件から続きます。


dtheta1 / dtheta2 = r2 / r1で開始する興味深いアプローチ。どのようにしてその方程式を思いついたのですか?
aioobe 2013年

他の人が言及したように(たとえば、ホンク)、円の表面の微分要素はr dr dtheta として与えられるため、r1 = r2と仮定すると、dr1 * dtheta1 = dr2 * dtheta2となり、残りは次のようになります。 。
arsaKasra

0

プログラマソリューション:

  • ビットマップ(ブール値の行列)を作成します。好きなだけ大きくできます。
  • そのビットマップに円を描きます。
  • 円のポイントのルックアップテーブルを作成します。
  • このルックアップテーブルでランダムなインデックスを選択します。
const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;

bool matrix[MATRIX_SIZE][MATRIX_SIZE] = {0};

struct Point { int x; int y; };

Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];

void init()
{
  int numberOfOnBits = 0;

  for (int x = 0 ; x < MATRIX_SIZE ; ++x)
  {
    for (int y = 0 ; y < MATRIX_SIZE ; ++y)
    {
      if (x * x + y * y < RADIUS * RADIUS) 
      {
        matrix[x][y] = true;

        loopUpTable[numberOfOnBits].x = x;
        loopUpTable[numberOfOnBits].y = y;

        ++numberOfOnBits;

      } // if
    } // for
  } // for
} // ()

Point choose()
{
  int randomIndex = randomInt(numberOfBits);

  return loopUpTable[randomIndex];
} // ()

ビットマップは、ロジックの説明にのみ必要です。これはビットマップなしのコードです:

const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;

struct Point { int x; int y; };

Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];

void init()
{
  int numberOfOnBits = 0;

  for (int x = 0 ; x < MATRIX_SIZE ; ++x)
  {
    for (int y = 0 ; y < MATRIX_SIZE ; ++y)
    {
      if (x * x + y * y < RADIUS * RADIUS) 
      {
        loopUpTable[numberOfOnBits].x = x;
        loopUpTable[numberOfOnBits].y = y;

        ++numberOfOnBits;
      } // if
    } // for
  } // for
} // ()

Point choose()
{
  int randomIndex = randomInt(numberOfBits);

  return loopUpTable[randomIndex];
} // ()

0

正確な「(2 / R2)×r」についてはまだわかりませんが、明らかなのは、所定の単位「dr」で分配する必要があるポイントの数です。つまり、rの増加はrではなくr2に比例します。

この方法を確認してください...ある角度シータのポイント数とrの間のポイント数(0.1rから0.2r)、つまり標準生成を使用する場合、rの割合とrの間のポイント数(0.6rから0.7r)は等しくなります。 2つの間隔の差はわずか0.1rであるためです。しかし、ポイント(0.6rから0.7r)の間にカバーされるエリアは、0.1rから0.2rの間にカバーされるエリアよりもはるかに大きいので、等しい数のポイントは、より広いエリアにまばらに配置されます。ランダムポイントを生成するには、線形ではなく2次である必要があります(与えられた単位「dr」に分布する必要があるポイントの数、つまりrの増加はr2ではなくr2に比例するため)。この場合は、二次関数、デルタがあるため(0。


あなたはここでピタゴラスの定理を参照する最初のものです。あなたの説明を支持して、これを1つか2つの数字で拡大していただければ幸いです。今のところ、私はフォローするのに苦労しています:-(
aioobe

@aioobe私は答えを言い換えようとしましたが、必要に応じて図を追加できます:)
cheesefest

線形に展開できない理由を理解しています。ここで私が理解していないのは、ピタゴラスまたは罪/コスとの関係です。たぶん、ここで図が役に立ちます。
aioobe 2017年

ピタゴラスは、私のミスで、それを忘れていますが、関数の二次的な性質を理解願っていてください、正確な(2 / R2)×rは証明必要があり、私はこのためにどんな証拠を思い付くことができません
cheesefest

0

このような楽しい問題。
軸の原点からの距離が増加するにつれて点が選択される確率の根拠は、上記で何度も説明されています。U [0,1]の根を取ることでそれを説明します。Python 3の正のrの一般的な解決策を次に示します。

import numpy
import math
import matplotlib.pyplot as plt

def sq_point_in_circle(r):
    """
    Generate a random point in an r radius circle 
    centered around the start of the axis
    """

    t = 2*math.pi*numpy.random.uniform()
    R = (numpy.random.uniform(0,1) ** 0.5) * r

    return(R*math.cos(t), R*math.sin(t))

R = 200 # Radius
N = 1000 # Samples

points = numpy.array([sq_point_in_circle(R) for i in range(N)])
plt.scatter(points[:, 0], points[:,1])

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


0

直感も使えます。

円の面積は pi*r^2

ために r=1

これにより、の面積が得られpiます。円内の点fを均一に分散させるある種の関数があると仮定しましょうN=10。ここの比率は10 / pi

次に、面積とポイント数を2倍にします

r=2N=20

これはの面積を示し、4pi比率は現在20/4piまたは10/2piです。半径が大きくなるほど比率は小さくなり、その成長は二次であり、N線形にスケーリングするためです。

これを修正するには、次のようにします。

x = r^2
sqrt(x) = r

このような極座標でベクトルを生成する場合

length = random_0_1();
angle = random_0_2pi();

より多くのポイントが中心の周りに着陸します。

length = sqrt(random_0_1());
angle = random_0_2pi();

length は均一に分散されなくなりましたが、ベクトルは均一に分散されます。


-1

1)-1から1の間のランダムなXを選択します。

var X:Number = Math.random() * 2 - 1;

2)円の公式を使用して、Xと半径が1の場合のYの最大値と最小値を計算します。

var YMin:Number = -Math.sqrt(1 - X * X);
var YMax:Number = Math.sqrt(1 - X * X);

3)両極端の間でランダムなYを選択します。

var Y:Number = Math.random() * (YMax - YMin) + YMin;

4)最終的な値に位置と半径の値を組み込みます。

var finalX:Number = X * radius + pos.x;
var finalY:Number = Y * radois + pos.y;

2
均一でない-p([-1、Y])= p([0、Y])であり、1つしかない場合、[-1、0]の確率は[0、0]よりもはるかに高くなります。 [-1、Y]の選択肢と[0、Y]の選択肢が多数あります。
アマダン

このソリューションでは、円の左側と右側にあるポイントが優先されます。xがゼロに近い点は、十分に表現されていません。まったく均一な分布ではありません。
Dawood ibnカリーム2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.