web-dev-qa-db-fra.com

Fixation de set.seed pour une session entière

J'utilise R pour construire un modèle basé sur un agent avec un processus de monte carlo. Cela signifie que j'ai de nombreuses fonctions qui utilisent un moteur aléatoire quelconque. Afin d'obtenir des résultats reproductibles, je dois réparer la graine. Mais, autant que je sache, je dois définir la graine avant chaque tirage au sort ou échantillon. C'est une vraie douleur dans le cou. Existe-t-il un moyen de réparer la graine?

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
27
Elad663

Il existe plusieurs options, selon vos besoins précis. Je soupçonne la première option, la plus simple n'est pas suffisante, mais mes deuxième et troisième options peuvent être plus appropriées, la troisième option étant la plus automatisable.

Option 1

Si vous savez à l'avance que la fonction utilisant/créant des nombres aléatoires tirera toujours le même numéro, et que vous ne réorganisez pas les appels de fonction ou insérez un nouvel appel entre les appels existants, alors tout ce que vous avez à faire est de définir la graine une fois. En effet, vous ne voudrez probablement pas continuer à réinitialiser la graine car vous continuerez à obtenir le même ensemble de nombres aléatoires pour chaque appel de fonction.

Par exemple:

> 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

Option 2

Si vous voulez vraiment vous assurer qu'une fonction utilise la même graine et que vous ne voulez la définir qu'une seule fois, passez la graine comme argument:

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)

(où .... signifie d'autres arguments pour votre fonction; c'est du pseudo code).

Option 3

Si vous voulez automatiser encore plus cela, vous pourriez abuser du mécanisme options, ce qui est bien si vous le faites simplement dans un script (pour un package, vous devez utiliser votre propre objet options). Ensuite, votre fonction peut rechercher cette option. Par exemple.

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

Ensuite, en cours d'utilisation, nous avons:

> 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
23
Gavin Simpson

Je pense que cette question souffre d'une confusion. Dans l'exemple, la graine a a été définie pour toute la session. Toutefois, cela ne signifie pas qu'il produira le même ensemble de nombres à chaque fois que vous utilisez la commande print(sample)) pendant une exécution; cela ne ressemblerait pas à un processus aléatoire, car il serait tout à fait déterminé que les trois mêmes nombres apparaîtraient à chaque fois. Au lieu de cela, ce qui se passe réellement, c'est qu'une fois que vous avez défini la valeur de départ, chaque fois que vous exécutez un script, la même valeur de départ est utilisée pour produire une sélection pseudo-aléatoire de nombres, c'est-à-dire des nombres qui semblent aléatoires mais qui sont en fait produit par un processus reproductible en utilisant la graine que vous avez définie.

Si vous réexécutez l'intégralité du script depuis le début, vous reproduisez ces nombres qui semblent aléatoires mais qui ne le sont pas. Ainsi, dans l'exemple, la deuxième fois que la valeur de départ est définie sur 123, la sortie est à nouveau 9, 10 et 1, ce qui est exactement ce que vous attendez car le processus recommence depuis le début. Si vous deviez continuer à reproduire votre première exécution en écrivant print(sample(1:10,3)), alors le deuxième ensemble de sortie serait à nouveau 3, 8 et 4.

Donc, la réponse courte à la question est: si vous voulez définir une graine pour créer un processus reproductible, faites ce que vous avez fait et définissez la graine une fois; cependant, vous devez pas définir la valeur de départ avant chaque tirage aléatoire car cela relancera le processus pseudo-aléatoire depuis le début.

Cette question est ancienne, mais vient toujours en tête des résultats de recherche, et il semblait utile d'étendre la réponse de Spacedman.

13
TilmanHartley

Ce n'est pas nécessaire. Bien que les résultats soient différents d'un échantillon à l'autre (ce que vous voulez presque certainement, sinon le caractère aléatoire est très discutable), les résultats d'une exécution à l'autre seront les mêmes. Vous voyez, voici la sortie de ma machine.

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

Vous pouvez faire une fonction wrapper, comme ceci:

> 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

Il y a probablement une manière plus élégante, et je suis sûr que quelqu'un s'y adaptera. Mais s'ils ne le font pas, cela devrait vous faciliter la vie.

2
hd1

Si vous voulez toujours retourner les mêmes résultats à partir de processus aléatoires, gardez simplement la graine définie tout le temps avec:

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

Maintenant, la sortie est la même à chaque fois:

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

Je vous suggère de set.seed Avant d'appeler chaque générateur de nombres aléatoires dans R. Je pense que ce dont vous avez besoin est reproductibilité pour les simulations de Monte Carlo. Si dans une boucle for, vous pouvez set.seed(i) avant d'appeler sample, ce qui garantit d'être entièrement reproductible. Dans votre fonction externe, vous pouvez spécifier un argument seed=1 Afin que dans la boucle for, vous utilisiez set.seed(i+seed).

0
alittleboy