Выборка двух случайных величин равномерно в области, где сумма больше нуля

Я пытаюсь понять, как равномерно выбирать две случайные величины в области, где сумма двух больше нуля. Я подумал, что решением может быть выборка для X~U(-1,1), а затем выборка для Y~U(-x,1), где x будет текущей выборкой для X.

Но это привело к распределению, которое выглядит следующим образом.

Это не выглядит равномерно распределенным, поскольку плотность точек в верхнем левом углу выше и продолжает уменьшаться по мере продвижения вправо. Может ли кто-нибудь указать, где ошибка в моих рассуждениях и как это исправить?

Спасибо


person krishna    schedule 13.07.2021    source источник
comment
Из вашего рисунка видно, что в интересующей области х=+0,75 гораздо более вероятно, чем х=-0,75. Следовательно, ваш x не распределен равномерно. Таким образом, вы не должны выбирать x через равномерное распределение. Общим способом выборки правильного распределения для x является обратный метод. Но я не уверен, что здесь хорошо нарушать симметрию между x и y в вашей задаче. Как правило, вы склонны использовать симметрию в задаче.   -  person jpmarinier    schedule 13.07.2021


Ответы (3)


Вам просто нужно убедиться, что плотность x точек отходит от верхнего левого угла соответствующим образом. Я бы также предложил сгенерировать в [0,1], а затем преобразовать в [-1,1].

Например:

import numpy as np

# generate points, sqrt takes care of moving points away from zero
n = 50000
x = np.sqrt(np.random.uniform(size=n))
y = np.random.uniform(1-x)

# transform to -1,1
x = x * 2 - 1
y = y * 2 - 1

их построение дает:

вывод matplotlib

что мне кажется разумным. Обратите внимание, что я раскрасил квадрат [-1,1], чтобы показать, где он должен располагаться.

person Sam Mason    schedule 13.07.2021
comment
Спасибо за ответ! Я пытаюсь относиться к этому как к упражнению, чтобы лучше понять выборку. Не могли бы вы рассказать немного о том, как вы пришли к ответу? - person krishna; 14.07.2021
comment
@krishna, работающий в [0,1], заставляет больше математических функций работать правильно. для использования квадратного корня обратите внимание, что на половине пути по оси x есть половина места по оси y. Я только что нашел cs.cmu.edu/~nasmith /papers/smith+tromble.tr04.pdf что говорит о том, что я, возможно, поступаю неправильно, но приведенный выше сюжет выглядит убедительно и, безусловно, лучше, чем то, что было у вас. - person Sam Mason; 14.07.2021

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()

Графически результат выглядит достаточно хорошо: Результат кода Python

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
comment
намного лучше, чем мое махающее рукой объяснение! Кроме того, зеркальное отображение отклоненных семплов — это аккуратно, раньше я всегда жестко отбрасывал варианты. использование sqrt может быть быстрее из-за отсутствия непредсказуемой ветки, но опять же вы можете изменить сэмплер отклонения, чтобы он был более удобным для предсказателя ветвления - person Sam Mason; 15.07.2021

После Создание случайных местоположений в треугольном домене

Код для равномерной выборки в любом треугольнике, Python 3.9.4, Win 10 x64

import math
import random

import matplotlib.pyplot as plt

def trisample(A, B, C):
    """
    Given three vertices A, B, C,
    sample point uniformly in the triangle
    """
    r1 = random.random()
    r2 = random.random()

    s1 = math.sqrt(r1)

    x = A[0] * (1.0 - s1) + B[0] * (1.0 - r2) * s1 + C[0] * r2 * s1
    y = A[1] * (1.0 - s1) + B[1] * (1.0 - r2) * s1 + C[1] * r2 * s1

    return (x, y)

random.seed(312345)
A = (1, 0)
B = (1, 1)
C = (0, 1)
points = [trisample(A, B, C) for _ in range(10000)]

xx, yy = zip(*points)
plt.scatter(xx, yy, s=0.2)
plt.show()

введите здесь описание изображения

person Severin Pappadeux    schedule 13.07.2021