からっぽのしょこ

読んだら書く!書いたら読む!同じ事は二度調べ(たく)ない

【Python】1次元ランダムウォークの作図【Matplotlib】

はじめに

 PythonのMatplotlibライブラリを使ってグラフを動かそうシリーズです。
 この記事では、1次元のランダムウォークのアニメーションを作成します。

【他の内容】

www.anarchive-beta.com

【目次】

1次元ランダムウォークの作図

 1方向(上下)に移動するランダムウォーク(random walk)のアニメーションを作成します。

 利用するライブラリを読み込みます。

# 利用するモジュール
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np


1サンプル

 まずは、1つのサンプルを描画します。

 試行回数を指定して、移動量をランダムに生成します。

# 試行回数を指定
max_iter = 100

# 乱数を生成
random_vec = np.random.choice([-1, 1], size=max_iter, replace=True) # 移動量
print(random_vec[:5])
print(random_vec.shape)
[-1 -1  1  1 -1]
(100,)

 試行ごとに -1 または 1 をランダムに(等確率で)割り当てます。1 は正の方向、-1 は負の方向の移動に対応します。

 移動量に応じた座標を計算します。

# 試行ごとに集計
x_vec = np.cumsum(
    np.hstack([0, random_vec]) # 初期値を追加
)
print(x_vec[:5])
print(x_vec.shape)
[ 0 -1 -2 -1  0]
(101,)

 初期値(スタート地点・0回目の結果)を 0 として追加して、各試行までの和(累積和)を np.cumsum() で計算します。

 点の推移のグラフを作成します。

# 余白サイズを指定
margin_rate = 0.1

# グラフサイズを設定
axis_size = np.abs(x_vec).max()
axis_size = np.ceil(axis_size * (1+margin_rate)) # 余白を追加

# 1Dランダムウォークを作図
fig, ax = plt.subplots(figsize=(3, 6), dpi=250, facecolor='white')
ax.axhline(y=0, color='red', linestyle='dashed') # 初期値
ax.plot(np.repeat(0, repeats=max_iter+1), x_vec) # 軌跡
ax.scatter(x=0, y=x_vec[max_iter], s=100, zorder=100) # 最終地点
ax.set_xticks(ticks=[0], labels=[''])
ax.set_xlabel('')
ax.set_ylabel('x')
ax.set_title('iteration: {}, $x = {}$'.format(max_iter, x_vec[max_iter]), loc='left')
fig.suptitle('Random Walk', fontsize=20)
ax.set_ylim(ymin=-axis_size, ymax=axis_size)
ax.grid()
plt.show()

1次元ランダムウォーク:1サンプル


 点の推移のアニメーションを作成します。

# 余白サイズを指定
margin_rate = 0.1

# グラフサイズを設定
axis_size = np.abs(x_vec).max()
axis_size = np.ceil(axis_size * (1+margin_rate)) # 余白を追加

# グラフオブジェクトを初期化
fig, ax = plt.subplots(figsize=(3, 6), facecolor='white')
fig.suptitle('Random Walk', fontsize=20)

# 作図処理を定義
def update(i):
    
    # 前フレームのグラフを初期化
    plt.cla()
    
    # 1Dランダムウォークを作図
    ax.axhline(y=0, color='red', linestyle='dashed') # 初期値
    ax.plot(np.repeat(0, repeats=i+1), x_vec[:i+1]) # 軌跡
    ax.scatter(x=0, y=x_vec[i], s=100, zorder=100) # 現在地点
    ax.set_xticks(ticks=[0], labels=[''])
    ax.set_xlabel('')
    ax.set_ylabel('x')
    ax.set_title('iteration: {}, $x = {}$'.format(i, x_vec[i]), loc='left')
    ax.set_ylim(ymin=-axis_size, ymax=axis_size)
    ax.grid()

# 動画を作成
ani = FuncAnimation(fig=fig, func=update, frames=max_iter+1, interval=100)

# 動画を書出
ani.save(filename='1d_x_1.gif', dpi=250)

1次元ランダムウォーク:1サンプル

 初期値(期待値)を破線で示します。

 試行回数軸を追加したグラフを作成します。

# 余白サイズを指定
margin_rate = 0.1

# グラフサイズを設定
axis_size = np.abs(x_vec).max()
axis_size = np.ceil(axis_size * (1+margin_rate)) # 余白を追加

# 1Dランダムウォークを作図
fig, ax = plt.subplots(figsize=(8, 6), dpi=250, facecolor='white')
ax.axhline(y=0, color='red', linestyle='dashed', zorder=0) # 初期値
ax.plot(np.arange(max_iter+1), x_vec) # 軌跡
ax.scatter(x=max_iter, y=x_vec[max_iter], s=100, zorder=100) # 最終地点
ax.set_xlabel('iteration')
ax.set_ylabel('x')
ax.set_title('iteration: {}, $x = {}$'.format(max_iter, x_vec[max_iter]), loc='left')
fig.suptitle('Random Walk', fontsize=20)
ax.set_ylim(ymin=-axis_size, ymax=axis_size)
ax.grid()
plt.show()

1次元ランダムウォーク:1サンプル


 試行回数軸を追加した点の推移のアニメーションを作成します。

# 余白サイズを指定
margin_rate = 0.1

# グラフサイズを設定
axis_size = np.abs(x_vec).max()
axis_size = np.ceil(axis_size * (1+margin_rate)) # 余白を追加

# グラフオブジェクトを初期化
fig, ax = plt.subplots(figsize=(8, 6), facecolor='white')
fig.suptitle('Random Walk', fontsize=20)

# 作図処理を定義
def update(i):
    
    # 前フレームのグラフを初期化
    plt.cla()
    
    # 1Dランダムウォークを作図
    ax.axhline(y=0, color='red', linestyle='dashed', zorder=0) # 初期値
    ax.plot(np.arange(i+1), x_vec[:i+1]) # 軌跡
    ax.scatter(x=i, y=x_vec[i], s=100, zorder=100) # 現在地点
    ax.set_xlabel('iteration')
    ax.set_ylabel('x')
    ax.set_title('iteration: {}, $x = {}$'.format(i, x_vec[i]), loc='left')
    ax.set_xlim(xmin=-max_iter*margin_rate, xmax=max_iter*(1+margin_rate))
    ax.set_ylim(ymin=-axis_size, ymax=axis_size)
    ax.grid()

# 動画を作成
ani = FuncAnimation(fig=fig, func=update, frames=max_iter+1, interval=100)

# 動画を書出
ani.save(filename='1d_ix_1.gif', dpi=250)

1次元ランダムウォーク:1サンプル

 試行回数(時間)の変化を横軸で表します。

複数サンプル

 続いて、複数のサンプルを並べて描画します。
 作図コードについては「RandomWalk_1d.py at anemptyarchive/matplotlib · GitHub」を参照してください。

・サンプル軸あり

1次元ランダムウォーク:複数サンプル

 等確率で移動する場合、初期値が期待値になりますが分散を持ち(散らばり)ます。

・試行回数(時間)軸あり

1次元ランダムウォーク:複数サンプル

 回数が増えると分散が大きくなるのを確認できます。

 この記事では、1次元の(上下に移動する)ランダムウォークを扱いました。次の記事では、2次元の(上下左右に移動する)場合を扱います。

おわりに

 Rで作った2次元までのランダムウォークをリメイクしたところ、3次元版を作りたくなったのでPythonで1次元からやっていきます。

 2024年2月22日は、モーニング娘。'24の横山玲奈さんの23歳のお誕生日です。

 いつも楽しそうにしている姿が素敵です。

【次の内容】

www.anarchive-beta.com