递归函数,以概率从列表中随机选择



我需要制作一个模拟器,用于输入列表,列表(元素是从rdm_lst随机选择的)列表。我:

lst = ["a", "a", "a"]
rdm_lst = ["a", "b", "c"]
def simulator(lst, rdm_lst):
sim = []
for i in lst:
if i == "a":
sim.append(np.random.choice(rdm_lst, size=1, p=[0.6, 0.2, 0.2]).tolist()[0])
elif i == "b":
sim.append(np.random.choice(rdm_lst, size=1, p=[0.2, 0.6, 0.2]).tolist()[0])
elif i == "c":
sim.append(np.random.choice(rdm_lst, size=1, p=[0.2, 0.2, 0.6]).tolist()[0])
return sim
simulator(rdm_lst)

输出是一个列表,我遇到的问题是,我不知道如何重复这个函数k时间,作为列表的结果列表,其中模拟器()的输入将是前一个列表,而不是第一个。我试过了,放:

return simulator(sim)

:

return sim

出现错误。请帮助。

听起来你在尝试实现一个马尔可夫链。

您可以通过使用dict定义您的转换来简化您的代码(因为您的状态是标记的,并且您当前使用的是numpy—在这种情况下,Pandas DataFrame将更直观,但这将完成)。

Px = {
'a': np.array([0.6, 0.2, 0.2]),
'b': np.array([0.2, 0.6, 0.2]),
'c': np.array([0.2, 0.2, 0.6]),
}
def simulator(xs, Px, k=1):
labels = list(Px)
return [
xs := [np.random.choice(labels, p=Px[x]) for x in xs]
for _ in range(k)
]

np.random.seed(0)
>>> simulator(['a', 'b', 'c'], Px, k=10)
[['a', 'b', 'c'],
['a', 'b', 'c'],
['a', 'c', 'c'],
['a', 'c', 'c'],
['a', 'c', 'a'],
['a', 'a', 'c'],
['b', 'c', 'c'],
['b', 'c', 'c'],
['a', 'c', 'a'],
['c', 'c', 'a']]

给定xs一个初始状态列表,我们用列表理解构造一个新的状态列表:[np.random.choice(labels, p=Px[x]) for x in xs]。然后将其赋值给xs(使用"海象操作符"),并迭代k数次。

有趣的东西有限状态马尔可夫链更常用的定义是带转移矩阵的:

P = np.c_[list(Px.values())]
>>> P
array([[0.6, 0.2, 0.2],
[0.2, 0.6, 0.2],
[0.2, 0.2, 0.6]])

(您可以单独映射标签,或者使用pandas将标签作为索引和列)。

给定初始状态(1,0,0)('a'),经过两次转换后的预期状态分布是什么?

>>> np.array((1,0,0)) @ P @ P
array([0.44, 0.28, 0.28])

给定初始状态(1,0,0),终端期望状态分布是什么?

# approximation of v @ P^inf
>>> np.array((1,0,0)) @ np.linalg.matrix_power(P, int(10**9))
array([0.33333334, 0.33333334, 0.33333334])

更准确地说:什么是平稳分布(一种状态分布,它不受转换P的影响)?

w, v = np.linalg.eig(P.T)  # left eigen system
k = np.argmax(w)
assert np.allclose(w[k], 1), 'no stationary state!'
e = v[:, k]
e /= e.sum()
>>> e
array([0.33333333, 0.33333333, 0.33333333])
>>> e @ P
array([0.33333333, 0.33333333, 0.33333333])

因此,无论初始状态如何(因为所有状态都可以从任何初始状态到达),经过大量转换后的期望分布为每个状态的1/3。

最新更新