ランダムウォーク 2

今度も線路の上をうろつく酔っ払いが登場します。ただし今度は 線路に沿って風が吹いていて,おじさんはどうも風下に向かって踏み出す 確率が高いようです。


バイアスのかかった1次元ランダムウォーク

前項では進む確率と後退する確率が等しいものとして,ランダムウォークを 扱った。今度は前進する確率を $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 によるシミュレーション

ステップ数を決めて行き着く先を調べた Ruby のソースのほうも 簡単な改造でバイアスありのシミュレーションを実現できる。 バイアスの値を固定してステップ数を変化させたり, その逆をやってみて,結果をGNUPLOT でグラフにしてみよう。