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!
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.
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))
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,
cumsum
et en tirant l'échantillon en même temps.Reduce
pour effectuer la somme.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.seq
plutôt que rep
.sapply
est appelé à la place de lapply
/unlist
.vapply
est utilisé à la place de lapply
/unlist
.replicate
, où la valeur par défaut est simplify = TRUE.for
qui pré-alloue le vecteur et le remplit.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.
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))
}