【问题标题】:How to convert a scalar index to a 2 dimensional index in numpy如何在numpy中将标量索引转换为二维索引
【发布时间】:2020-08-15 08:00:14
【问题描述】:

假设我们有一组可以耦合的 N 个节点,就像在一个复杂的网络中一样,我们不关心链接的方向(所以 1 和 2 之间的链接与 2 和 1 相同)。

我想用一个 numpy 一维数组来表示每个链接的状态。状态采用 {1,0} 中的值,其中 1 表示链接存在。我想这个数组,我们称之为“状态”,应该是 N*(N-1)/2 长(不包括自动循环)。

在这种情况下,如何正确索引从节点 a 开始的所有链接,或以节点 b 结束的链接?如果我们将数组称为“状态”,我会说 state[i] = 从节点 a 开始或在节点 j 结束的链接的状态。有没有办法,可能是一种有效的方法来做到这一点?如果我们有 N=10 个节点,则前 8 个条目对应于从节点 1 开始并以节点 2、3、4、...、10 结束的链接,但我找不到通用的表达方式。谢谢。

P.s.:我知道二维矩阵可能更有用,但出于我的目的,我想解决将状态保持在一维数组中的问题。

【问题讨论】:

  • 请重复介绍导览中的on topic。 “请解决我的设计问题”过于宽泛且定义不足,无法成为 Stack Overflow 问题。你已经描述了你想要的数据结构;似乎目前的症结在于为您想要的功能编写支持代码的编程敏锐度。那来自实践;当你对你想要的代码有很好的尝试时,可能会成为一个很好的堆栈溢出问题。

标签: python arrays numpy indexing adjacency-matrix


【解决方案1】:

节点对 (a,b) 的索引可以使用变量基数来计算,该变量基数由两个节点 ID 中较小者的前面元素的数量确定。将较大的添加到该基数会得到正确的索引:

您可以创建一个函数从一对节点标识符(从零开始)中获取状态索引,如下所示:

def indexOf(a,b,N=10):
    return indexOf(b,a,N) if a>b else N*a-a*(a+1)//2+b

根据要求生成索引:

for a in range(10):
    print([indexOf(a,b) for b in range(10)])

[0, 1,  2,  3,  4,  5,  6,  7,  8,  9]
[1, 10, 11, 12, 13, 14, 15, 16, 17, 18]
[2, 11, 19, 20, 21, 22, 23, 24, 25, 26]
[3, 12, 20, 27, 28, 29, 30, 31, 32, 33]
[4, 13, 21, 28, 34, 35, 36, 37, 38, 39]
[5, 14, 22, 29, 35, 40, 41, 42, 43, 44]
[6, 15, 23, 30, 36, 41, 45, 46, 47, 48]
[7, 16, 24, 31, 37, 42, 46, 49, 50, 51]
[8, 17, 25, 32, 38, 43, 47, 50, 52, 53]
[9, 18, 26, 33, 39, 44, 48, 51, 53, 54]

allPairs = [ (a,b) for a in range(10) for b in range(a,10) ]
print( sorted(allPairs,key=lambda ab:indexOf(*ab) ) )
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (6, 6), (6, 7), (6, 8), (6, 9), (7, 7), (7, 8), (7, 9), (8, 8), (8, 9), (9, 9)]

请注意,这会将节点链接的条目分配给它们自己

该索引模型的缺点是它需要预先知道节点数 (N) 并在每次调用时提供。

一种更通用的方法是根据不需要预先确定 N 值的进程对平面列表进行不同的索引。无论节点总数如何,每对都将始终位于相同的索引处:

def indexOf(a,b):
    return indexOf(b,a) if a<b else a*(a+1)//2+b

它可以像这样反转(以获取给定索引处的节点对):

def unindex(X):
    b = int( ((8*X+1)**0.5-1)/2 )
    a = X - b*(b+1)//2
    return a,b

索引顺序不同但函数不需要知道N:

for a in range(10):
    print([indexOf(a,b) for b in range(10)])

[0,  1,  3,  6,  10, 15, 21, 28, 36, 45]
[1,  2,  4,  7,  11, 16, 22, 29, 37, 46]
[3,  4,  5,  8,  12, 17, 23, 30, 38, 47]
[6,  7,  8,  9,  13, 18, 24, 31, 39, 48]
[10, 11, 12, 13, 14, 19, 25, 32, 40, 49]
[15, 16, 17, 18, 19, 20, 26, 33, 41, 50]
[21, 22, 23, 24, 25, 26, 27, 34, 42, 51]
[28, 29, 30, 31, 32, 33, 34, 35, 43, 52]
[36, 37, 38, 39, 40, 41, 42, 43, 44, 53]
[45, 46, 47, 48, 49, 50, 51, 52, 53, 54]

print( [unindex(x) for x in range(N*(N+1)//2) ])
[(0, 0), (0, 1), (1, 1), (0, 2), (1, 2), (2, 2), (0, 3), (1, 3), (2, 3), (3, 3), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4), (0, 5), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (0, 6), (1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (0, 7), (1, 7), (2, 7), (3, 7), (4, 7), (5, 7), (6, 7), (7, 7), (0, 8), (1, 8), (2, 8), (3, 8), (4, 8), (5, 8), (6, 8), (7, 8), (8, 8), (0, 9), (1, 9), (2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9), (9, 9)]

使用numpy,如果你有一个节点对数组,你可以通过编写函数(第二版)来获取它们对应的状态索引:

import numpy as np

def indexOf(ab):
    a,b = np.max(ab,axis=-1),np.min(ab,axis=-1)
    return a*(a+1)//2 + b

输出:

N = 10

states = np.arange(N*(N+1)//2)%2        # some random node links

pairs = np.array( [[1,3],[2,4],[7,2]] ) # array of node pairs

connected= states[indexOf(pairs)]       # indirection to states

print(states)
# [0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0]
print(indexOf(pairs))
# [ 7 12 30]
print(connected)
# [1 0 0]

如果您使用该函数的第一个版本,则需要在每次调用时传递节点数:

def indexOf(ab,N=10):
    a,b = np.min(ab,axis=-1),np.max(ab,axis=-1)
    return N*a-a*(a+1)//2+b

connected= states[indexOf(pairs,N=10)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 2019-10-02
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 2023-01-14
    相关资源
    最近更新 更多