numpy:将方阵的索引转换为其上三角索引的有效方法

时间:2018-11-09 21:52:43

标签: python numpy matrix

问题:给定一个索引元组,以上三角索引返回其顺序。这是一个示例:

假设我们有一个形状为(3,3)的方阵A。

A有6个上三角索引,分别是(0,0),(0,1),(0,2),(1,1),(1、2),(2,2)。

现在我知道索引(1、2)处的元素,该元素属于A的上三角部分。我想返回4(这意味着它是所有上三角索引中的第5个元素。)

一般来说,有什么想法吗?

最好, 志浩

6 个答案:

答案 0 :(得分:5)

可以写下明确的公式:

def utr_idx(N, i, j):
    return (2*N+1-i)*i//2 + j-i

演示:

>>> N = 127
>>> X = np.transpose(np.triu_indices(N))
>>> utr_idx(N, *X[2123])
2123

答案 1 :(得分:4)

对于 n×n 矩阵,上三角形的(i,j)项是 i×(2×n-i矩阵的第+1)/ 2 + ji 个元素。

我们也可以反算,并通过以下方法获得第 k 个元素的(i,j)元素:

i =⌊(-√((2n + 1) 2 -8k)+ 2n + 1)/2⌋ j = k + ii ×(2×n-i + 1)/ 2

例如:

from math import floor, sqrt

def coor_to_idx(n, i, j):
    return i*(2*n-i+1)//2+j-i

def idx_to_coor(n, k):
    i = floor((-sqrt((2*n+1)*(2*n+1)-8*k)+2*n+1)/2)
    j = k + i - i*(2*n-i+1)//2
    return i, j

例如:

>>> [idx_to_coor(4, i) for i in range(10)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
>>> [coor_to_idx(4, i, j) for i in range(4) for j in range(i, 4)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

鉴于数字不是很大(如果数字很大,那么计算不再是在恒定时间内完成的),因此我们可以在 O(1)中计算第 k 个坐标,例如:

>>> idx_to_coor(1234567, 123456789)
(100, 5139)

等效于通过枚举获取它:

>>> next(islice(((i, j) for i in range(1234567) for j in range(i, 1234567)), 123456789, None))
(100, 5139)

将索引转换为坐标时,由于浮点数的不精确性,对于大量对象,还可能会有一些舍入误差。

答案 2 :(得分:2)

IIUC,您可以使用itertools组合with replacement

获得索引
>>> ind = tuple(itertools.combinations_with_replacement(range(3),2))
((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2))

要检索索引,只需使用index方法

>>> ind.index((1,2))
4

答案 3 :(得分:2)

您可以使用np.triu_indicesdictionary

import numpy as np

iu1 = np.triu_indices(3)
table = {(i, j): c for c, (i, j) in enumerate(zip(*iu1))}
print(table[(1, 2)])

输出

4

答案 4 :(得分:1)

类似于@DanielMesejo,您可以将np.triu_indicesargwherenonzero一起使用:

my_index = (1,2)

>>> np.nonzero((np.stack(np.triu_indices(3), axis=1) == my_index).all(1))
(array([4]),)
>>> np.argwhere((np.stack(np.triu_indices(3), axis=1) == my_index).all(1))
array([[4]])

说明:

np.stack(np.triu_indices(3), axis=1)按顺序提供上三角的索引:

array([[0, 0],
       [0, 1],
       [0, 2],
       [1, 1],
       [1, 2],
       [2, 2]])

因此,您要做的就是找到与[1,2]匹配的位置(您可以使用==运算符和all进行匹配)

答案 5 :(得分:1)

构造较高的索引会很昂贵。我们可以像这样直接获取相应的索引-

def triu_index(N, x, y):
    # Get index corresponding to (x,y) in upper triangular list
    idx = np.r_[0,np.arange(N,1,-1).cumsum()]
    return idx[x]+y-x

样品运行-

In [271]: triu_index(N=3, x=1, y=2)
Out[271]: 4