根据索引和值填充scipy / numpy矩阵

时间:2015-02-09 18:17:09

标签: python numpy matrix scipy

我有一个节点图,每个节点代表大脑中的大约100个体素。我将图表划分为社区,但现在我需要创建一个关联矩阵,其中节点中的每个体素都连接到同一社区中的每个节点中的每个体素。换句话说,如果节点1和2在同一社区中,我需要在节点1中的每个体素和节点2中的每个体素之间的矩阵中使用1。这需要花费很长时间使用下面的代码。有谁知道如何加快这个速度?

for edge in combinations(graph.nodes(),2):
    if partition.get_node_community(edge[0]) == partition.get_node_community(edge[1]): # if nodes are in same community
        voxels1 = np.argwhere(flat_parcel==edge[0]+1) # this is where I find the voxels in each node, and I get the indices for the matrix where I want them.
        voxels2 = np.argwhere(flat_parcel==edge[1]+1)
        for voxel1 in voxels1:
            voxel_matrix[voxel1,voxels2] = 1

感谢您的回复,我认为最简单,最快速的解决方案是用最后一个循环替换     voxel_matrix [np.ix_(voxels1,voxels2)] = 1

1 个答案:

答案 0 :(得分:1)

这是我希望为您效劳的方法。这是我机器上的一个延伸 - 甚至存储两个体素邻接矩阵副本(使用dtype=bool)将我(有点旧)的桌面向右推到其内存容量的边缘。但我假设您有一台能够处理至少两个(300 * 100)** 2 = 900 MB阵列的机器 - 否则,您可能会在此阶段之前遇到问题。我的桌面需要大约30分钟才能处理30000个体素。

这假定voxel_communities是一个简单数组,其中包含索引为i的每个体素的社区标签。听起来你可以很快地生成它。它还假设体素仅存在于一个节点中。

def voxel_adjacency(voxel_communities):
    n_voxels = voxel_communities.size
    comm_labels = sorted(set(voxel_communities))
    comm_counts = [(voxel_communities == l).sum() for l in comm_labels]

    blocks = numpy.zeros((n_voxels, n_voxels), dtype=bool)
    start = 0
    for c in comm_counts:
        blocks[start:start + c, start:start + c] = 1
        start += c

    ix = numpy.empty_like(voxel_communities)
    ix[voxel_communities.argsort()] = numpy.arange(n_voxels)
    blocks[:] = blocks[ix,:]
    blocks[:] = blocks[:,ix]
    return blocks

这是一个快速解释。这使用逆索引技巧将对角块阵列的列和行重新排序成所需的矩阵。

    n_voxels = voxel_communities.size
    comm_labels = sorted(set(voxel_communities))
    comm_counts = [(voxel_communities == l).sum() for l in comm_labels]

    blocks = numpy.zeros((n_voxels, n_voxels), dtype=bool)
    start = 0
    for c in comm_counts:
        blocks[start:start + c, start:start + c] = 1
        start += c

这些行用于构造初始块矩阵。例如,假设您有六个体素和三个社区,每个社区包含两个体素。然后初始块矩阵将如下所示:

array([[ True,  True, False, False, False, False],
       [ True,  True, False, False, False, False],
       [False, False,  True,  True, False, False],
       [False, False,  True,  True, False, False],
       [False, False, False, False,  True,  True],
       [False, False, False, False,  True,  True]], dtype=bool)

这与体素已按社区成员资格排序后的所需邻接矩阵基本相同。所以我们需要扭转这种排序。我们通过构造反argsort数组来实现。

    ix = numpy.empty_like(voxel_communities)
    ix[voxel_communities.argsort()] = numpy.arange(n_voxels)

现在ix将在用作索引时反转排序过程。由于这是一个对称矩阵,我们可以在列上分别对行执行反向排序操作:

    blocks[:] = blocks[ix,:]
    blocks[:] = blocks[:,ix]
    return blocks

以下是为小输入生成的结果示例:

>>> voxel_adjacency(numpy.array([0, 3, 1, 1, 0, 2]))
array([[ True, False, False, False,  True, False],
       [False,  True, False, False, False, False],
       [False, False,  True,  True, False, False],
       [False, False,  True,  True, False, False],
       [ True, False, False, False,  True, False],
       [False, False, False, False, False,  True]], dtype=bool)

在我看来,这与[{3}}建议的voxel_matrix[np.ix_(voxels1, voxels2)] = 1非常相似,除非它同时完成,而不是跟踪每个可能的节点组合。

可能有更好的解决方案,但这至少应该是一种改进。

另外,请注意,如果您可以简单地接受体素的新排序,那么此解决方案就像创建块阵列一样简单!这需要大约300毫秒。