Почему runif() не прогнозирует максимальное значение интервала?

Я был ответил на вопрос, заданный в Reddit AskScience и я столкнулся с чем-то странным относительно функциональности runif(). Я пытался выборочно отбирать набор от 1 до 52. Моя первая мысль заключалась в том, чтобы использовать runif():

as.integer(runif(n, min = 1, max = 52))

Однако я обнаружил, что операция никогда не вызывала значения 52. Например:

length(unique(as.integer(runif(1000000, 1, 52))))
[1] 51

В моих целях я просто обратился к sample():

sample(52, n, replace = TRUE)

В документации runif() указано:

runif не генерирует ни одного из экстремальных значений, если max = min или max-min не меньше по сравнению с min, и, в частности, не для аргументов по умолчанию.

Мне интересно, почему runif() действует таким образом. Похоже, что он должен иметь возможность создавать "экстремальные значения" из набора, если он пытается равномерно сгенерировать выборки. Является ли это особенностью и почему?

Ответ 1

Это действительно особенность. C исходный код runif содержит следующий код C:

/* This is true of all builtin generators, but protect against
       user-supplied ones */
    do {u = unif_rand();} while (u <= 0 || u >= 1);
return a + (b - a) * u;

это означает, что unif_rand() может возвращать 0 или 1, но runif() сконструирован таким образом, чтобы пропускать эти (маловероятные) случаи.

Мое предположение заключается в том, что это делается для защиты кода пользователя, который потерпит неудачу в случаях кросс (значения точно на границах диапазона).

Эта функция была реализована Брайаном Рипли 19 сентября 2006 г. (из комментариев кажется, что 0<u<1 автоматически соответствует встроенной функции, в равномерном генераторе, но может быть неверным для пользовательских).

sample(1:52,size=n,replace=TRUE) является идиоматическим (хотя и не обязательно самым эффективным) способом достижения вашей цели.

Ответ 2

as.integer работает как trunc. Он образует целое число, усекая заданное значение в направлении 0. И поскольку значения не могут превышать 52 (см. Ответ Ben), они всегда будут усечены до значения между 1 и 51.

Вы увидите другой результат с помощью floor (или ceiling). Обратите внимание, что вам нужно настроить max runif, добавив 1 (или отрегулируйте min в случае ceiling). Также обратите внимание, что в этом случае, так как оба min и max превышают 0, вы можете заменить floor на trunc или as.integer тоже.

set.seed(42)
x = floor(runif(n = 1000000, min = 1, max = 52 + 1))
plot(prop.table(table(x)), las = 2, cex.axis = 0.75)

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

Ответ 3

as.integer(51.999)

51

Это потому, что работает as.integer.

Если вы хотите извлечь из дискретного распределения, используйте образец. runif не для дискретных распределений.