Could you please elaborate a bit on how you arrived at the answer?
Что ж, основная проблема состоит в том, чтобы получить честный способ выборки неравномерного распределения координаты X.
Из элементарной геометрии площадь части верхнего треугольника с x ‹ x0 равна: (1/2) * (x0 + 1)2 . Поскольку общая площадь этого верхнего треугольника равна 2, отсюда следует, что кумулятивная вероятность P (X ‹ x0) внутри верхнего треугольника равна: P = (1/4) * (x 0 + 1)2.
Итак, инвертируя последнюю формулу, мы имеем: x0 = 2*sqrt(P) - 1
Теперь из теоремы выборки с обратным преобразованием мы знаем, что можем сгенерировать справедливое выборка X путем переинтерпретации P как случайной величины U0, равномерно распределенной между 0 и 1.
В Python это дает нам:
u0 = random.uniform(0.0, 1.0)
x = (2*math.sqrt(u0)) - 1.0
или эквивалентно:
u0 = random.random()
x = (2 * math.sqrt(u0)) - 1.0
Обратите внимание, что это по сути та же математика, что и в отличном ответе @SamMason. Это происходит из общего статистического принципа. Его также можно использовать для доказательства того, что правильная выборка широты на трехмерной сфере задается arcsin(2*u - 1).
Итак, теперь у нас есть x, но нам все еще нужен y. Базовая двумерная плотность является однородной, поэтому для данного x все возможные значения y равнораспределены.
Интервал возможных значений y равен [-x, 1]. Итак, если U1 — еще одна независимая случайная величина, равномерно распределенная между 0 и 1, y можно получить из уравнения:
у = (1+х) * и1 - х
который в Python отображается:
u1 = random.random()
y = (1+x)*u1 - x
В целом код Python можно записать так:
import math
import random
import matplotlib.pyplot as plt
def mySampler():
u0 = random.random()
u1 = random.random()
x = 2*math.sqrt(u0) - 1.0
y = (1+x)*u1 - x
return (x,y)
#--- Main program:
points = (mySampler() for _ in range(10000)) # an iterator object
xx, yy = zip(*points)
plt.scatter(xx, yy, s=0.2)
plt.show()
Графически результат выглядит достаточно хорошо:
Side note: a cheaper, ad hoc solution:
Всегда есть возможность выборки равномерно по всему квадрату и отклонения точек, сумма x+y которых оказывается отрицательной. Но это немного расточительно. Мы можем найти более элегантное решение, заметив, что «плохая» область имеет ту же форму и площадь, что и «хорошая» область.
Поэтому, если мы получим «плохую» точку, вместо того, чтобы просто отклонить ее, мы можем заменить ее точкой, симметричной относительно разделительной линии x+y=0. Это можно сделать с помощью следующего кода Python:
def mySampler2():
x0 = random.uniform(-1.0, 1.0)
y0 = random.uniform(-1.0, 1.0)
s = x0+y0
if (s >= 0):
return (x0, y0) # good point
else:
return (x0-s, y0-s) # symmetric of bad point
Это тоже отлично работает. И это, наверное, самое дешевое решение с точки зрения процессорного времени, так как мы ничего не отбрасываем и нам не нужно вычислять квадратный корень.
person
jpmarinier
schedule
14.07.2021