Xnは、0.5の確率でそれぞれ-1または1の値を取ることができます。そして、Sn = Sn-1 + Xn Sn = X1 + X2 + ::: + Xnで与えられる時間nで観測された部分和をどのように計算できますか。ここでランダムウォークをシミュレートしようとしています。私は次のことをしましたが、それが正しいかどうかは正確にはわかりません。
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)
}
助けてください!
この答えは、コードが機能しなかった理由を説明するためのものです。 @ jake-burkheadは、実際にコードを書く方法を示しました。
このコードでは、半分の時間だけステップを実行します。これは、移動するかどうかを決定するためにxdir
からサンプリングしているためです。代わりに、ループ内で次のことをお勧めします。
_for(i in 2:n){
x[i] <- x[i - 1] + sample(step, 1)
}
_
sample(step, 1)
呼び出しは、ウォークが_1
_または_-1
_のどちらを移動するかを決定します。
部分和を計算するには、x
を生成した後にcumsum()
を使用できます。結果は、ウォークの特定のポイントでの部分和のベクトルになります。
cumsum
を使用して、これを非常に簡潔かつ効率的に行うこともできます。
set.seed(1)
n <- 1000
x <- cumsum(sample(c(-1, 1), n, TRUE))
この投稿では、この計算のためのさまざまなベースRメソッドのタイミングについて説明します。この投稿は、 この投稿 へのコメントと、JakeBurkheadによって投稿された最速のメソッドへの投稿の@josilberのコメントに触発されています。
以下では、ランダムウォークの計算にさまざまな方法が使用されています。これを実現するために、各関数は、以下のfnc
で定義されているように、1または-1のいずれかの1000個の値をプルします。タイミングテストでは、メソッドごとに1000回のレプリケーションでmicrobenchmark
を使用します。
_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)
_
ここに、
cumsum
の提案を使用し、サンプルを一度にプルします。Reduce
を使用して合計を実行します。lapply
とunlist
を使用してベクトルを返し、1の1000インスタンスを反復処理して、名前で関数を直接呼び出します。seq
ではなくrep
を使用して反復変数を作成します。sapply
/lapply
の代わりにunlist
が呼び出されることを除いて、laplyRpClnなどと同じです。vapply
/lapply
の代わりにunlist
が使用される点が異なります。replicate
の呼び出しであり、デフォルトはsimplify = TRUEです。for
ループを使用します。numeric(0)
ベクトルを作成するfor
ループを使用し、次にc
を使用してそのベクトルに連結します。これは
_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
_
最初の方法が明らかに最速であることに注意してください。これに続いて、サンプル全体を一度にプルし、Reduce
を使用して合計を実行します。 _*apply
_関数の中で、関数の名前を直接使用する「クリーン」バージョンではパフォーマンスがわずかに向上しているようで、lapply
バージョンはvapply
と同等のようですが、値の範囲を考えると、結論は完全に単純ではありません。 sapply
は最も遅いように見えますが、関数呼び出しのメソッドが_*apply
_関数のタイプを支配しています。
2つのfor
ループのパフォーマンスが最悪で、事前割り当てのfor
ループがfor
ループを上回り、c
とともに成長しました。
ここでは、openSuse 42.1で3.4.1のパッチバージョン(2017年8月23日頃にパッチが適用されています)を実行しています。
間違いがありましたらお知らせください。できるだけ早く修正します。最終的な機能をさらに調査するように勧めてくれたBenBolkerに感謝します。そこで、いくつかのバグが見つかりました。
ここにそれを行う1つの方法があります。
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))
}