圆盘内的均匀采样问题,是一个很有意思,也很常被考到的问题。在一个圆形内,均匀采点,怎么保证均匀且随机?
有三种方法:1、正方形采样;2、极坐标采样(错误!);3、圆盘采样
一、正方形采样(Reject Method)
最容易想到的方法就是在正方形内采样,比如要在圆心为原点,半径为1的圆内均匀采样,可以在 x 从 [-1, 1]
,y 从 -[-1, 1]
的正方形内均匀采样,然后把不在圆内的点剔除即可。python代码如下:
import numpy as np
from pylab import *
import matplotlib.pyplot as plt
import random
figure(figsize=(12, 12), dpi = 80)
subplot(1, 1, 1)
# 画圆
theta = np.linspace(0, 2 * np.pi, 800)
x,y = np.cos(theta), np.sin(theta)
plot(x, y, color = 'red', linewidth = 2.0)
# 画随机点
a = []
b = []
for i in range(10000):
a.append(random.uniform(-1, 1))
b.append(random.uniform(-1, 1))
plt.xlim(xmax = 1, xmin = -1)
plt.ylim(ymax = 1, ymin = -1)
scatter(a, b, s = 1.5, color = (0., 0.5, 0.))
show()
代码在正方形内,随机取了 10000 个二维坐标点,然后绘制出点和圆。可以看到随机且均匀,但是很明显的就是效率问题,有大量的点是要被扔掉的,所以不可取。不过此方法虽然效率低,但是可以作为 ground truth。
![](https://i-blog.csdnimg.cn/blog_migrate/d48a197fb12c18c7b76477db771eaa33.png)
二、极坐标采样
还有一种很容易想到但是不对的方法,就是按照极坐标采样,也就是先按照角度在 [0, 2 π 2\pi 2π ] 范围内均匀随机采样一个角度,然后在 [0, 1] 上随机均匀采样一个长度,就可以得到一个点在圆中的位置。代码如下:
# 和上边只有 for 循环内不一样
for i in range(10000):
theta = random.uniform(0, 2 * np.pi)
r = random.uniform(0, 1)
a.append(r * math.cos(theta))
b.append(r * math.sin(theta))
![](https://i-blog.csdnimg.cn/blog_migrate/df385fd4f2de10a05ea43055859e37eb.png)
可以看到很明显的不均匀。所以是不对的!
三、圆盘采样
我们知道圆的面积是 π r 2 \pi r^2 πr2,圆环的面积是 π ( r 1 2 − r 2 2 ) \pi ({r_1}^2 - {r_2}^2) π(r12−r22),在极限情况下,圆环的面积是 π ( ( r 1 + Δ r ) 2 − r 1 2 ) \pi ((r_1 + \Delta r)^2 - {r_1}^2) π((r1+Δr)2−r12),其实就是周长 2 π r 2\pi r 2πr,那么我们可以发现,在角度均匀采样的前提下,同样的 Δ r \Delta r Δr 会因为 r r r 大小的不同而导致面积不同,所以概率密度就不均匀了,我们想要概率密度均匀,那么采样的均匀性应该和面积线性相关,也就是对 r 2 r^2 r2 进行线性均匀采样,这样算出来的阴线长度 r r r 才是对的,这样才能保证,随机采样出来的每一个极小圆盘面积是相同的。
for i in range(10000):
theta = random.uniform(0, 2 * np.pi)
r = math.sqrt(random.uniform(0, 1 ** 2))
a.append(r * math.cos(theta))
b.append(r * math.sin(theta))
![](https://i-blog.csdnimg.cn/blog_migrate/2c153a8f27f57bb30574e6093aaea294.png)