Tri angular Распределение случайных величин - PullRequest
2 голосов
/ 05 августа 2020

Сначала немного предыстории моей ситуации:

Мне нужно случайное распределение tri angular, и я планировал использовать Python random.tri angular. Ниже приводится исходный код (Python 3.6.2): ​​

    def triangular(self, low=0.0, high=1.0, mode=None):
    """Triangular distribution.

    Continuous distribution bounded by given lower and upper limits,
    and having a given mode value in-between.

    http://en.wikipedia.org/wiki/Triangular_distribution

    """
    u = self.random()
    try:
        c = 0.5 if mode is None else (mode - low) / (high - low)
    except ZeroDivisionError:
        return low
    if u > c:
        u = 1.0 - u
        c = 1.0 - c
        low, high = high, low
    return low + (high - low) * (u * c) ** 0.5

Я просмотрел указанную вики-страницу и обнаружил, что в моем желаемом использовании был особый случай , который упрощает вещи, и может быть реализована с помощью следующей функции:

def random_absolute_difference():
    return abs(random.random() - random.random())

Выполнение некоторых быстрых расчетов времени показывает значительное ускорение с упрощенной версией (эта операция будет повторяться гораздо больше миллиона раз при каждом запуске моего кода):

>>> import timeit
>>> timeit.Timer('random.triangular(mode=0)','import random').timeit()
0.5533245000001443
>>> timeit.Timer('abs(random.random()-random.random())','import random').timeit()
0.16867640000009487

Итак, теперь вопрос: я знаю, что модуль random python использует только псевдослучайность, а random.tri angular использует одно случайное число, в то время как код особого случая использует 2 случайных числа. Будут ли результаты особого случая значительно менее случайными, потому что они используют 2 последовательных вызова random, а random.tri angular использует только один? Есть ли какие-либо другие непредвиденные побочные эффекты от использования упрощенного кода?

Изменить: в отношении этого решения другого вопроса я создал графики гистограмм для обоих дистрибутивов, показывая, что они сопоставимы :

Случайное тройное angular распределение: Random Triangular Distribution

Special case simplified distribution: Упрощенное распространение в особых случаях

1 Ответ

1 голос
/ 05 августа 2020

В вашем случае triangular сводится к следующему выражению:

1 + (0 - 1) * ((1.0 - u) * (1.0 - c)) ** 0.5

, а затем до:

1 - 1 * ((1.0 - u) * 1.0) ** 0.5

, а затем до:

1 - (1.0 - u) ** 0.5

И с моими таймингами это последнее выражение работает намного быстрее, чем random.triangular(mode=0), и имеет сопоставимую скорость с abs(random.random()-random.random()). Обратите внимание, что triangular содержит оператор try / except, который может объяснить некоторые различия в производительности (например, замените этот оператор просто «mode = 0» и посмотрите).

import timeit
timeit.Timer('random.triangular(mode=0)','import random').timeit()
timeit.Timer('1 - (1.0 - random.random()) ** 0.5','import random').timeit()
timeit.Timer('abs(random.random()-random.random())','import random').timeit()

Однако я не вижу причины, по которой использование двух случайных чисел вместо одного приведет к «менее случайному» tri angular -распределенному числу - до тех пор, пока два метода производят одинаковое распределение. Фактически, использование двух случайных чисел даст вам большее разнообразие tri angular -распределенных чисел, чем одно только одно, поскольку для этой цели доступно больше битов случайности. (Если вы хотите проверить правильность двух методов, вы можете сделать это с помощью теста Колмогорова-Смирнова вместе с CDF распределения tri angular, поскольку распределение tri angular является непрерывным. Этот тест реализован, например, в SciPy под scipy.stats.kstest. Если несколько запусков теста возвращают значение p, очень близкое к 0, это строго указывает на то, что числа взяты из неправильного распределения.)

...