установка семян локально (не глобально) в R

Я хотел бы устанавливать семена в R только локально (внутри функций), но кажется, что R устанавливает семена не только локально, но и глобально. Вот простой пример того, что я пытаюсь (не) делать.

myfunction <- function () {
  set.seed(2)
}

# now, whenever I run the two commands below I'll get the same answer
myfunction()
runif(1)

Итак, мои вопросы: почему R устанавливает семя глобально, а не только внутри моей функции? И как я могу заставить R устанавливать семя только внутри моей функции?


person Manoel Galdino    schedule 14.01.2013    source источник


Ответы (2)


Что-то вроде этого делает это для меня:

myfunction <- function () {
  old <- .Random.seed
  set.seed(2)
  res <- runif(1)
  .Random.seed <<- old
  res
}

Или, возможно, более элегантно:

myfunction <- function () {
  old <- .Random.seed
  on.exit( { .Random.seed <<- old } )
  set.seed(2)
  runif(1)
}

Например:

> myfunction()
[1] 0.1848823
> runif(1)
[1] 0.3472722
> myfunction()
[1] 0.1848823
> runif(1)
[1] 0.4887732
person Romain Francois    schedule 14.01.2013
comment
Спасибо! Я попробую ваш ответ. Любая идея, почему R имеет этот неожиданный (по крайней мере, для меня) побочный эффект? - person Manoel Galdino; 14.01.2013
comment
+1 Опереди меня. @ManoelGaldino Почему? Я не думаю, что это неожиданно. Я думаю, что реализация нового отдельного генератора случайных чисел для каждой функциональной среды была бы ужасно сложной. И, возможно, несут некоторые накладные расходы на производительность. - person joran; 14.01.2013
comment
Я думаю, что кто-то с большими знаниями, чем я, должен прокомментировать, как эта проблема влияет на параллельные процессы. - person IRTFM; 14.01.2013
comment
С этим ответом есть небольшая проблема. Объект .Random.seed может не существовать, если начальное число не было установлено или runif() (или другие функции, обращающиеся к генератору случайных чисел) не вызывались в текущем сеансе R. Таким образом, перед сохранением .Random.seed необходимо проверить его существование с помощью exists() и, возможно, вызвать runif(), если это не так. - person Theodore Lytras; 14.01.2013
comment
@TheodoreLytras В идеальном мире set.seed вернет старое значение семени. - person hadley; 15.01.2013
comment
Это отличный ответ. Один вопрос: не будет ли <<-- всегда помещаться в родительский фрейм? Разве мы не должны использовать assign с envir = globalenv, чтобы гарантировать, что old будет перемещен обратно в глобальную среду? - person Konrad; 08.10.2018
comment
Как насчет on.exit(set.seed(NULL))? Тогда вам не нужно хранить старое значение? - person Dan Lewer; 26.06.2019

Используя ответ @Romain Francois, обобщите как функцию:

withRandom <- function(expr, seed = 1) {
    old <- .Random.seed
    on.exit({.Random.seed <<- old})
    set.seed(seed)
    expr
}

Применение:

runif(2)
withRandom(seed = 2, {
    runif(1)
    runif(1)
})
runif(2)
withRandom(seed = 2, runif(2))
runif(2)

выход:

> runif(2)
[1] 0.5776099 0.6309793
> withRandom(seed = 2, {
+     runif(1)
+     runif(1)
+ })
[1] 0.702374
> runif(2)
[1] 0.5120159 0.5050239
> withRandom(seed = 2, runif(2))
[1] 0.1848823 0.7023740
> runif(2)
[1] 0.5340354 0.5572494

person Gwang-Jin Kim    schedule 23.01.2020