web-dev-qa-db-fra.com

Simuler une promenade aléatoire

Xn peut prendre des valeurs de -1 ou 1 chacune avec une probabilité de 0,5. Et Sn = Sn-1 + Xn Comment puis-je calculer La somme partielle observée à l'instant n donnée par Sn = X1 + X2 +::: + Xn. J'essaie de simuler une promenade aléatoire ici. J'ai fait ce qui suit, mais je ne suis pas tout à fait sûr que c'est vrai:

rw <- function(n){
    x=numeric(n)
    xdir=c(TRUE, FALSE)
    step=c(1,-1)
    for (i in 2:n)
    if (sample(xdir,1)) {
        x[i]=x[i-1]+sample(step,1)
    } else {
        x[i]=x[i-1]
    }
    list(x=x)
}

S'il vous plaît aider!

10
user3347124

Cette réponse est juste pour expliquer pourquoi votre code n'a pas fonctionné. @ jake-burkhead a expliqué comment vous devriez écrire le code.

Dans ce code, vous ne faites qu'un pas la moitié du temps. En effet, vous échantillonnez à partir de xdir pour décider si vous déménagez ou non. Au lieu de cela, je vous recommanderais ce qui suit dans votre boucle:

for(i in 2:n){
  x[i] <- x[i - 1] + sample(step, 1)
}

L'appel sample(step, 1) décide si la marche déplace 1 ou -1

Pour calculer les sommes partielles, vous pouvez utiliser cumsum() après avoir généré x. Le résultat sera un vecteur des sommes partielles à un moment donné de la promenade.

4
Christopher Louden

Vous pouvez également le faire de manière très concise et efficace avec cumsum

set.seed(1)

n <- 1000
x <- cumsum(sample(c(-1, 1), n, TRUE))

enter image description here

39
Jake Burkhead

Cet article traite des timings de différentes méthodes de base R pour ce calcul. Ce message est inspiré par les commentaires à ce message et par le commentaire de @josilber dans le message sur la méthode la plus rapide publiée par Jake Burkhead.

Ci-dessous, diverses méthodes sont utilisées pour calculer la marche aléatoire. Pour ce faire, chaque fonction extrait 1 000 valeurs de 1 ou -1, comme défini dans fnc ci-dessous. Le test de synchronisation utilise microbenchmark avec 1 000 réplications pour chaque méthode.

fnc <- function(n) sample(c(1L, -1L), n, replace=TRUE)
library(microbenchmark)
microbenchmark(all=cumsum(fnc(1000L)),
      reduce=Reduce("+", fnc(1000L), accumulate=TRUE),
      laplyRpCln=cumsum(unlist(lapply(rep.int(1L, 1000L), fnc))),
      laplyRpAn=cumsum(unlist(lapply(rep.int(1L, 1000L), function(x) fnc(1L)))),
      laplySqAn=cumsum(unlist(lapply(seq_len(1000L), function(x) fnc(1L)))),
      saplyRpCln=cumsum(sapply(rep.int(1L, 1000L), fnc)),
      saplyRpAn=cumsum(sapply(rep.int(1L, 1000L), function(x) fnc(1L))),
      saplySqAn=cumsum(sapply(seq_len(1000L), function(x) fnc(1L))),
      vaplyRpCln=cumsum(vapply(rep.int(1L, 1000L), fnc, FUN.VALUE=0)),
      vaplyRpAn=cumsum(vapply(rep.int(1L, 1000L), function(x) fnc(1L), FUN.VALUE=0)),
      vaplySqAn=cumsum(vapply(seq_len(1000L), function(x) fnc(1L), FUN.VALUE=0)),
      replicate=cumsum(replicate(1000L, fnc(1L))),
      forPre={vals <- numeric(1000L); for(i in seq_along(vals)) vals[i] <- fnc(1L); cumsum(vals)},
      forNoPre={vals <- numeric(0L); for(i in seq_len(1000L)) vals <- c(vals, fnc(1L)); cumsum(vals)},
      times=1000)

Ici,

  • "tous" utilise la suggestion de Jake Burkhead, cumsum et en tirant l'échantillon en même temps.
  • "réduire" extrait l'échantillon à la fois, mais utilise Reduce pour effectuer la somme.
  • laplyRpCln utilise lapply et unlist pour renvoyer un vecteur et effectue une itération sur 1 000 instances de 1, appelant la fonction directement par son nom.
  • laplyRpAn diffère en utilisant une fonction anonyme.
  • laplySqAn utilise une fonction anonyme et crée la variable itérative avec seq plutôt que rep.
  • saplyRpCln, laplyRpAn, laplySqAn sont identiques à laplyRpCln, etc. sauf que sapply est appelé à la place de lapply/unlist.
  • vaplyRpCln, etc. sont identiques à laplyRpCln, etc. sauf que vapply est utilisé à la place de lapply/unlist.
  • réplicate est un appel à replicate, où la valeur par défaut est simplify = TRUE.
  • forPre utilise une boucle for qui pré-alloue le vecteur et le remplit.
  • forNoPre utilise une boucle for qui crée un vecteur numeric(0) vide, puis utilise c pour concaténer ce vecteur.

Cela retourne

Unit: microseconds
       expr      min         lq        mean     median         uq      max neval     cld
        all   25.634    31.0705    85.66495    33.6890    35.3400 49240.30  1000 a      
     reduce  542.073   646.7720   780.13592   696.4775   750.2025 51685.44  1000  b     
 laplyRpCln 4349.384  5026.4015  6433.60754  5409.2485  7209.3405 58494.44  1000   c e  
  laplyRpAn 4600.200  5281.6190  6513.58733  5682.0570  7488.0865 55239.04  1000   c e  
  laplySqAn 4616.986  5251.4685  6514.09770  5634.9065  7488.1560 54263.04  1000   c e  
 saplyRpCln 4362.324  5080.3970  6325.66531  5506.5330  7294.6225 59075.02  1000   cd   
  saplyRpAn 4701.140  5386.1350  6781.95655  5786.6905  7587.8525 55429.02  1000     e  
  saplySqAn 4651.682  5342.5390  6551.35939  5735.0610  7525.4725 55148.32  1000   c e  
 vaplyRpCln 4366.322  5046.0625  6270.66501  5482.8565  7208.0680 63756.83  1000   c    
  vaplyRpAn 4657.256  5347.2190  6724.35226  5818.5225  7580.3695 64513.37  1000    de  
  vaplySqAn 4623.897  5325.6230  6475.97938  5769.8130  7541.3895 14614.67  1000   c e  
  replicate 4722.540  5395.1420  6653.90306  5777.3045  7638.8085 59376.89  1000   c e  
     forPre 5911.107  6823.3040  8172.41411  7226.7820  9038.9550 56119.11  1000      f 
   forNoPre 8431.855 10584.6535 11401.64190 10910.0480 11267.5605 58566.27  1000       g

Notez que la première méthode est clairement la plus rapide. Ceci est suivi en extrayant l'échantillon complet en une fois et en utilisant ensuite Reduce pour effectuer la totalisation. Parmi les fonctions *apply, les versions "propres", utilisant le nom de la fonction, semblent légèrement améliorer les performances, et la version lapply semble être sur un pied d'égalité avec vapply, mais étant donné la plage de valeurs, cette conclusion n'est pas entièrement simple. sapply semble être la plus lente, bien que la méthode d'appel de fonction domine le type de la fonction *apply.

Les deux boucles for ont donné les résultats les moins bons et la boucle pré-allocation for surperformant la boucle for croissant avec c.

Ici, je lance une version corrigée de 3.4.1 (corrigée le 23 août 2017) sur openSuse 42.1.

S'il vous plaît laissez-moi savoir si vous voyez des erreurs et je les corrigerai dès que je peux. Merci à Ben Bolker de m'avoir incité à enquêter davantage sur la fonction finale, où j'ai trouvé quelques bugs.

3
lmo

Voici une façon de le faire.

GenerateRandomWalk <- function(k = 250,initial.value = 0) {
  # Add a bionomial at each step
  samples = rbinom(k,1,0.5)
  samples[samples==0] = -1
  initial.value + c(0, cumsum(samples))
}
0
shahram