Вы должны сгенерировать равномерно распределенные углы phi
и взять sqrt
равномерно сгенерированного радиуса r
(который учитывает, что мы хотим произвести равномерную выборку в области , см. Пояснение ниже ), чтобы обеспечить равномерную выборку точек на полукруге.
import numpy as np
import matplotlib.pyplot as plt
# sample
size = 10000
R = 1
phi = np.random.random(size=size) * np.pi
r = np.sqrt(np.random.random(size=size)) * R
# transform
x = r * np.cos(phi)
y = r * np.sin(phi)
# plot
f = plt.figure(figsize=(12,12))
a = f.add_subplot(111)
a.scatter(x, y, marker='.')
a.set_aspect('equal')
plt.show()
Объяснение
Чтобы сформировать равномерно распределенные точки на (полукруге) окружности, мы должны убедиться, что каждая бесконечно малая область или сегмент "поражены" с одинаковой вероятностью. Мы можем просто выбрать phi
из равномерного случайного распределения [0, 1)
, умноженного на np.pi
(т. Е. [0, pi)
), поскольку все углы должны иметь одинаковую вероятность для выборки. Но если мы выберем r
из равномерного случайного распределения в [0, 1)
, мы создадим слишком много точек при малых радиусах и недостаточно при больших радиусах, поскольку область увеличивается как r**2
. Чтобы принять этот факт во внимание, мы должны соответствующим образом сместить наши выборочные радиусы, и в этом случае мы можем применить смещение, просто взяв квадратный корень (np.sqrt
), чтобы применить правильное взвешивание к выборочным значениям радиуса, и принять с учетом большей площади наружных колец.
Здесь гораздо лучше и более подробное объяснение: https://stackoverflow.com/a/50746409/1170207
Сравнение производительности с методами выборки отбраковки
Поскольку этот метод в основном является методом инверсионной выборки, мы сравниваем его
производительность по алгоритму выборки отклонения.
import numpy as np
x, y = np.random.random(size=(2,10000))
%timeit r, phi = np.sqrt(x), y
# 19 µs ± 33.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit m = x**2 + y**2 <= 1; xx, yy = x[m], y[m]
# 81.5 µs ± 271 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
С помощью метода отбраковки выборки мы также не можем гарантировать, что мы нарисуем определенное количество вариантов, поэтому мы должны повторять процесс до тех пор, пока у нас не получится. Это не может быть векторизовано так хорошо, если мы не примем выборку слишком большого количества значений и не отбросим дополнительные.