問題: 部屋がA, B, C, Dと4つあり、ロボットは最初部屋Aにいる。 そこで「停留」コマンドを選択した。このコマンドによりロボットは確率 1/2で同じ部屋にとどまるが、1/6の確率でそれぞれ別な部屋に飛ばされる。 そこでロボットAは光を感知した。光を感知できる確率はA, B, C, D それぞれ 1/10, 1/5, 2/5, 1/10 とする。
(1) 部屋Aにいる確率を求めよ.
(2) 再度「停留」コマンドを選択した後に、光を感知した。部屋Aにいる確率を求めよ。
条件は次の通り:
(a) 最初部屋Aにいる、
(b)「停留」コマンドを選択し,確率 1/2で同じ部屋にとどまるが、1/6の確率でそれぞれ別な部屋に飛ばされる。
(c) 光を感知した。光を感知できる確率はA, B, C, D それぞれ 1/10, 1/5, 2/5, 1/10
(1) 「停留」コマンドを選択した前の時点での存在確率と状態遷移確率の積」の総和によってそれぞれの状態に存在する「仮の値」を求め、
(2) (1)の値に観測確率を掛けて、存在確率に比例するG値を求め、
(3) G を正規化することで現在の時点での存在確率 F を求める。
import numpy as np
# ベイズフィルタ
# 前提: 存在確率を [A, B, C, D] で表す。(A, B, C, Dは確率、総和は1.0)
# 初期状態(a): Aにいるのだから、
F_0 = np.array([1.0, 0, 0, 0])
# 移動確率を MoveProb で表す
MoveProb = np.array([1/2, 1/6, 1/6, 1/6])
# (1) 「停留」コマンドを選択した前の時点での存在確率と状態遷移確率の積」の総和によってそれぞれの状態に存在する「仮の値」を求める
S1_tmp = F_0[0] * MoveProb
S1_tmp
# 光を観測する確率分布を Light = [1/10, 1/5, 2/5, 1/10] で表す
Light = np.array([1/10, 1/5, 2/5, 1/10] )
# (2) (1)の値に観測確率を掛けて、存在確率に比例するG値を求める
G1 = S1_tmp * Light
G1
# 見て分かるように、G1は確率ではない。総和が1にならない
sum(G1)
# (3) G を正規化することで現在の時点での存在確率 F を求める
F_1 = G1/sum(G1)
F_1
注意1: 乱数を用いるので同じ答えが得られる保証はない
注意2: 粒子の分布が存在確率を表す
(1) 粒子ごとに移動確率に基づいて、次の「仮の」分布状態を求める(サンプリング)
(2) 「仮の」分布状態と、観測確率の積によって重み付けする
(3) 重み付けにより、乱数によって粒子の分布状態を求める(リサンプリング)
import numpy as np
# ここでは粒子の個数を100 とする
Num = 100
# 前提: 粒子の分布を [A, B, C, D] で表す。(A, B, C, Dは粒子の個数、総和は100)
# 初期状態(a): Aにいるのだから、
P_0 = np.array([100, 0, 0, 0])
# (1) 粒子ごとに移動確率に基づいて、次の「仮の」分布状態を求める
# np.random.multinomial(Num, ProbDist) : Num個の粒子を確率分布ProbDistに基づきサンプリングする
# 移動確率を MoveProb で表す
MoveProb = np.array([1/2, 1/6, 1/6, 1/6])
P_1tmp = np.random.multinomial(Num, MoveProb)
P_1tmp
# 光を観測する確率分布を Light = [1/10, 1/5, 2/5, 1/10] で表す
Light = np.array([1/10, 1/5, 2/5, 1/10] )
# (2)「仮の」分布状態と、観測確率の積によって重み付けする
W_1 = Light*P_1tmp
W_1
# 見て分かるように、W_1は確率ではなく、粒子の個数でもない。
sum(W_1)
# (3) 重み付けにより、乱数によって粒子の分布状態を求める(リサンプリング)
# 重み付けを「確率分布」に変換して np.random.multinomial(Num, ProbDist) を用いてサンプリングする
# そのための変換
PD_1 = W_1/sum(W_1)
PD_1
# 最終的な粒子の分布
P_1 = np.random.multinomial(Num, PD_1)
P_1
確認: (1)の後の状態確率
F_1
# (1) 「停留」コマンドを選択した前の時点での存在確率と状態遷移確率の積」の総和によってそれぞれの状態に存在する「仮の値」を求める
tmp = F_1[0]* MoveProb
tmp
注意: 上の値は、前の状態がAである確率に、移動確率をかけたもの。前の状態がB, C, Dそれぞれの可能性も考えないといけない。
# rollメソッドを用いてそれぞれの部屋からの移動確率の計算に用いる: np.roll(List, int) --- Listの中身をintだけ回転(シフト)させる
np.roll(MoveProb,1)
S2_tmp = F_1[0]*MoveProb + F_1[1]*np.roll(MoveProb,1)+F_1[2]*np.roll(MoveProb,2)+F_1[3]*np.roll(MoveProb,3)
S2_tmp
# もっと簡単に書ける
sum([F_1[i] * np.roll(MoveProb,i) for i in range(4)])
# (2) (1)の値に観測確率を掛けて、存在確率に比例するG値を求める
G2 = S2_tmp * Light
G2
# (3) G を正規化することで現在の時点での存在確率 F を求める
F_2 = G2/sum(G2)
F_2
確認: (1)の後の状態確率
P_1
# (1) 粒子ごとに移動確率に基づいて、次の「仮の」分布状態を求める
dist_tmp=[np.random.multinomial(P_1[i], MoveProb) for i in range(4)]
dist_tmp
# 上はみな0番目の要素が「今いる部屋にとどまる」粒子の個数になっているので、A,B,C,Dそれぞれに分けなければならない
P_2tmp = dist_tmp[0]+np.roll(dist_tmp[1],1)+np.roll(dist_tmp[2],2)+np.roll(dist_tmp[3],3)
P_2tmp
# 上はもっと簡単にかける
sum([np.roll(dist_tmp[i],i) for i in range(4)])
# (2)「仮の」分布状態と、観測確率の積によって重み付けする
W_2 = Light*P_2tmp
W_2
# (3) 重み付けにより、乱数によって粒子の分布状態を求める(リサンプリング)
# 重み付けを「確率分布」に変換して np.random.multinomial(Num, ProbDist) を用いてサンプリングする
# そのための変換
PD_2 = W_2/sum(W_2)
PD_2
# 最終的な粒子の分布
P_2 = np.random.multinomial(Num, PD_2)
P_2