Случайные величины треугольного распределения

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

Мне нужно случайное треугольное распределение, и я планировал использовать Python random.triangular. Ниже приведен исходный код (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

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

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

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

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


person Leland Hepworth    schedule 05.08.2020    source источник
comment
См. также: stackoverflow.com/questions/3956478/understanding-randomness   -  person Peter O.    schedule 05.08.2020
comment
Будут ли результаты особого случая значительно менее случайными, потому что они используют 2 последовательных вызова random, а random.triangular использует только один? Больше случайных битов на входе означает, что вывод в целом будет иметь больше случайности, а не меньше.   -  person Severin Pappadeux    schedule 05.08.2020


Ответы (1)


В вашем случае 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, которая может объяснять некоторую разницу в производительности (например, замените эту инструкцию просто режимом = 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()

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

person Peter O.    schedule 05.08.2020