今度も線路の上をうろつく酔っ払いが登場します。ただし今度は 線路に沿って風が吹いていて,おじさんはどうも風下に向かって踏み出す 確率が高いようです。
前項では進む確率と後退する確率が等しいものとして,ランダムウォークを 扱った。今度は前進する確率を $p$ として,偏り(バイアス, bias)を持たせることができるように して,どんなことが起きるかを確かめてみよう。
前項と同じく次の二項分布を考えよう。
$ f(x) = _nC_x (p)^{x}(1-p)^{n-x} $
これは全部で $n$ 歩のうち前進したのが $x$ 歩である確率を表している。 $x$ の期待値と分散はすでに出てきたように次の式で表される。
$ E[x] = np $
$ V[x] = n p (1-p) $
前進した正味の距離 $z = 2x - n$ の期待値と分散は次のようになる。
$ E[z] = E[2x] - n = n(2p-1)$
$ V[z] = V[2x -n] = 2^2V[x] = 4np(1-p) $
上の結果について考えてみよう。$E[z] = n(2p-1)$ という式の意味するところは なんだろうか。これは $p > 1/2$ のときに 正の値をとり,そのときには$n$ とともに増加する。つまり,歩数が増えれば 大きくなるのだから,平均の位置も前進していくことになる。 その速度は,1 ステップあたり $(2p-1)$となり,これがバイアスのかかった ランダムウォークの平均速度となる。
この平均速度の式に $p= 1/2$ を代入すると 0 になり,これは両側に等しい確率で進むときに相当する。また$p = 1,0 $ を代入すると $\pm1$ となるが,これはまったくぶれずにどちらかへだけ進むことに相当するので,毎回1だけ前進または後退するという わけだ。
また,分散を見ると,$p=\pm1$ のときに0 となり, $p=1/2$ で最も大きくなる。 バイアスがかかっていないと分散は大きく,片方へ前進する傾向が強いときには分散は小さくなる。 どっちかずでふらふらのおじさんと,多少は迷いながらも決然と向きを決めて進む おじさんとの対照がはっきりと出ているということだね。
バイアスなしのときの Java のソースを改造して 偏りをもった酔歩を実現するにはどうしたらいいだろうか。 なお,Java の場合にはファイル名とそのプログラムのメインのクラス名が 一致していないといけないので,コピーして別のファイルを作って書き直すときには, クラス宣言および,そのクラスを参照してい るところをすべて書き直さないといけない。
具体的には, RandomWalk_1D.java を RandomWalk_1Db.java という名前のファイルにコピーしたら, ファイルの中の RandomWalk_1D を RandomWalk_1Db にすべて変更する。 M-% で確認しながらの置換が行えるので,それを利用しよう(置換を実行する前にファイルの先頭に移動しておくこと!)。
さて, もとのソースで, 向きを前進と後退に等確率で振り分けているところを見てみよう。
// 次のステップの計算 boolean goNextStep(){ Random rand = new Random(); if (rand.nextBoolean()) xWalker ++; else xWalker --; int xw = xWalker + nx / 2; if(xw < 0 || xw >= nx){ return false; } else{ cell[xWalker+nx/2] = true; } return true; }
nextBoolean というメソッドは, true か false のいずれかを等しい確率で返すので,ここで用いている。 しかし,これだと確率を好きなように偏らせることはできない。
そこで,別の乱数発生メソッドとして,すでに紹介したうちの nextDouble を利用する。これは 0 以上 1 未満の連続一様乱数を発生するので,その途中の値を使って if 文で仕分ければ,たとえば 0.6 と 0.4 の確率に振り分けることができる。
仕分けのための値は,double 型の変数 bias に予め代入してあるものとする。すると,上の処理は次のように書き換えればよい。
// 次のステップの計算 boolean goNextStep(){ Random rand = new Random(); if (rand.nextDouble() < bias) xWalker ++; else xWalker --; int xw = xWalker + nx / 2; if(xw < 0 || xw >= nx){ return false; } else{ cell[xWalker+nx/2] = true; } return true; }
あとは,どこか最初の方で bias を宣言して,たとえば 0.6 といった値を与えておけば,偏りのあるランダムウォークが 実現できる。
ステップ数を決めて行き着く先を調べた Ruby のソースのほうも 簡単な改造でバイアスありのシミュレーションを実現できる。 バイアスの値を固定してステップ数を変化させたり, その逆をやってみて,結果をGNUPLOT でグラフにしてみよう。