识别稀疏图中的吸收类

时间:2016-06-01 11:48:28

标签: python numpy scipy markov-chains

我的问题如下。我有几个吸收类的马尔可夫链,我想确定状态空间中的哪些状态是吸收的,哪些是瞬态的。举一个简单的例子,我们可以得到以下稀疏转移矩阵,每一行都有状态0,1,2,3的转移概率。

import numpy as np
from scipy.sparse import csr_matrix,csgraph

P = np.array([[0.6,0.4,0.,0.],[0.3,0.7,0.,0.],[0.2,0.4,0.2,0.2],[0.,0.,0.,1.]])
P = csr_matrix(P)

这里有两个吸收类:状态0-1和状态3.状态2是瞬态的。由于存在吸收状态的类别,因此在对角线上检查概率1不足以识别吸收类别。

我想知道如何以编程方式识别吸收类。使用csgraph中的工具,我可以使用

找到强关联组件
components,labels = csgraph.connected_components(P,connection="strong")
print( components, labels )

3 [0 0 2 1]

所以,我有3个组件,每个组件都有自己的标签。吸收类肯定对应于这些组件之一,但也有瞬态组件。如何确定哪个组件正在吸收哪个组件是暂时的?

有没有人对此有个好主意?

2 个答案:

答案 0 :(得分:2)

解决马尔可夫链问题,您需要依赖浮点数学(np.isclose)表示您的图表表示对于您尝试解决的问题不正确。

下面我提出了一个使用networkx的替代解决方案(但我认为改为csgraph并不难),它只依赖于连接并确定哪些边连接强大的组件。

import networkx as nx

def absorbing_classes(g):
    internal = set()

    # Tarjan is approximately linear O(|V| + |E|)
    cpts = list(nx.strongly_connected_component_subgraphs(g))
    for sg in cpts:
        for e in sg.edges():
            internal.add(e)

    # find all the edges that aren't part of the strongly connected components
    # ~ O(E)
    transient_edges = set(g.edges()) - internal

    # find the start of the directed edge leading out from a component
    # ~ O(E)
    transient_srcs = set([ e[0] for e in transient_edges ])

    # yield everything that don't have a vertex in transient_srcs
    for sg in cpts:
        if transient_srcs - set(sg.nodes()):
            yield sg

例如,在您提供的图表上:

import numpy as np
P = np.array([[0.6,0.4,0.,0.],[0.3,0.7,0.,0.],[0.2,0.4,0.2,0.2],[0.,0.,0.,1.]])

g = nx.from_numpy_matrix(P, create_using=nx.DiGraph())
for subg in absorbing_classes(g):
    print subg.nodes()

你会得到两个吸收类,其中一个节点[0, 1]和另一个节点[3]

答案 1 :(得分:1)

以下内容应该有效,并指出吸收状态集中的总概率等于该集合中的状态数:

components,labels = csgraph.connected_components(P, directed=True, connection='strong',return_labels=True)
absorbingStates = np.zeros(P.shape[0],dtype=bool)
for component in range(components):
    indices = np.where(labels==component)[0]
    n = len(indices)
    if n==1:
        probSum = P[indices,indices].sum() #np.ix_ gives an error if n==1
    else:            
        probSum = P[np.ix_(indices,indices)].sum()
    if np.isclose(probSum,n):
        absorbingStates[indices] = True

我不认为从P不断选择子矩阵是非常有效的。欢迎更好的想法。