Подтвердить что ты не робот

Фиксация set.seed для всего сеанса

Я использую R для создания модели на основе агента с процессом monte carlo. Это означает, что у меня есть много функций, которые используют какой-то случайный движок. Чтобы получить воспроизводимые результаты, я должен исправить семена. Но, насколько я понимаю, я должен установить семя перед каждой случайной ничью или выборкой. Это настоящая боль в шее. Есть ли способ исправить семя?

set.seed(123)
print(sample(1:10,3))
# [1] 3 8 4
print(sample(1:10,3))
# [1]  9 10  1
set.seed(123)
print(sample(1:10,3))
# [1] 3 8 4
4b9b3361

Ответ 1

В зависимости от ваших конкретных потребностей существует несколько вариантов. Я подозреваю, что первый вариант, самый простой - недостаточно, но мои второй и третий варианты могут быть более уместными, а третий вариант наиболее автоматизирован.

Вариант 1

Если вы заранее знаете, что функция, использующая/создающая случайные числа, всегда будет отображать один и тот же номер, и вы не переупорядочиваете вызовы функций или не вставляете новый вызов между существующими, тогда все, что вам нужно, это установить семя один раз. В самом деле, вы, вероятно, не хотите, чтобы сбрасывать семя, поскольку вы будете продолжать получать одинаковый набор случайных чисел для каждого вызова функции.

Например:

> set.seed(1)
> sample(10)
 [1]  3  4  5  7  2  8  9  6 10  1
> sample(10)
 [1]  3  2  6 10  5  7  8  4  1  9
> 
> ## second time round
> set.seed(1)
> sample(10)
 [1]  3  4  5  7  2  8  9  6 10  1
> sample(10)
 [1]  3  2  6 10  5  7  8  4  1  9

Вариант 2

Если вы действительно хотите удостовериться, что функция использует одно и то же семя, и вы только хотите установить его один раз, передайте семя в качестве аргумента:

foo <- function(...., seed) {
  ## set the seed
  if (!missing(seed)) 
    set.seed(seed) 
  ## do other stuff
  ....
}

my.seed <- 42
bar <- foo(...., seed = my.seed)
fbar <- foo(...., seed = my.seed)

(где .... означает другие аргументы вашей функции, это псевдокод).

Вариант 3

Если вы хотите автоматизировать это еще больше, вы можете злоупотреблять механизмом options, что прекрасно, если вы просто делаете это в script (для пакета вы должны использовать свой собственный объект опций). Тогда ваша функция может искать эту опцию. Например.

foo <- function() {
  if (!is.null(seed <- getOption("myseed")))
    set.seed(seed)
  sample(10)
}

Тогда при использовании мы имеем:

> getOption("myseed")
NULL
> foo()
 [1]  1  2  9  4  8  7 10  6  3  5
> foo()
 [1]  6  2  3  5  7  8  1  4 10  9
> options(myseed = 42)
> foo()
 [1] 10  9  3  6  4  8  5  1  2  7
> foo()
 [1] 10  9  3  6  4  8  5  1  2  7
> foo()
 [1] 10  9  3  6  4  8  5  1  2  7
> foo()
 [1] 10  9  3  6  4  8  5  1  2  7

Ответ 2

Я думаю, что этот вопрос страдает от путаницы. В этом примере семя было установлено для всего сеанса. Однако это не означает, что он будет производить одинаковый набор чисел каждый раз, когда вы используете команду print(sample)) во время прогона; что не будет напоминать случайный процесс, так как было бы совершенно очевидно, что каждый три числа будут отображаться одинаково. Вместо этого на самом деле происходит то, что после установки семени каждый раз при запуске script одно и то же семя используется для создания псевдослучайного выбора чисел, то есть чисел, которые выглядят так, как если бы они были случайными, но фактически произведенный воспроизводимым процессом с использованием установленного вами семени.

Если вы повторно запускаете весь script с самого начала, вы воспроизводите те числа, которые выглядят случайными, но не являются. Итак, в этом примере, во второй раз, когда семя установлено на значение 123, результат будет снова 9, 10 и 1, что именно то, что вы ожидаете увидеть, потому что процесс начинается с начала. Если бы вы продолжали воспроизводить свой первый запуск, написав print(sample(1:10,3)), тогда второй набор результатов снова будет 3, 8 и 4.

Итак, короткий ответ на вопрос: если вы хотите установить семя для создания воспроизводимого процесса, тогда сделайте то, что вы сделали, и установите семя один раз; однако вы не должны устанавливать семя перед каждой случайной ничьей, потому что это начнет псевдослучайный процесс снова с самого начала.

Этот вопрос старый, но по-прежнему высок в результатах поиска, и, похоже, он стоит направить на ответ Spacedman.

Ответ 3

Нет необходимости. Хотя результаты отличаются от образца к образцу (который вы почти наверняка хотите, в противном случае случайность очень сомнительна), результаты от запуска до запуска будут одинаковыми. См. Здесь вывод с моей машины.

> set.seed(123)
> sample(1:10,3)
[1] 3 8 4
> sample(1:10,3)
[1]  9 10  1

Ответ 4

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

> wrap.3.digit.sample <- function(x) {
+    set.seed(123)
+    return(sample(x, 3))
+ }
> wrap.3.digit.sample(c(1:10))
[1] 3 8 4
> wrap.3.digit.sample(c(1:10))
[1] 3 8 4

Вероятно, более элегантный способ, и я уверен, что кто-то зазвонит с ним. Но, если они этого не делают, это должно облегчить вашу жизнь.

Ответ 5

Я предлагаю вам set.seed перед вызовом каждого генератора случайных чисел в R. Я думаю, что вам нужна воспроизводимость для моделирования Монте-Карло. Если в цикле for вы можете set.seed(i) перед вызовом sample, что гарантирует полную воспроизводимость. В вашей внешней функции вы можете указать аргумент seed=1, чтобы в цикле for вы использовали set.seed(i+seed).

Ответ 6

Если вы хотите, чтобы всегда возвращал одни и те же результаты от случайных процессов, просто сохраняйте начальное значение всегда с помощью:

addTaskCallback(function(...) {set.seed(123);TRUE})

Теперь вывод один и тот же каждый раз:

print(sample(1:10,3))
# [1] 3 8 4
print(sample(1:10,3))
# [1] 3 8 4