【问题标题】:Indices of n largest values in lower triangular region of a NumPy arrayNumPy 数组下三角区域中 n 个最大值的索引
【发布时间】:2017-11-15 00:23:19
【问题描述】:

我有一个 numpy 余弦相似度矩阵。我想找到 n 个最大值的索引,但不包括对角线上的 1.0,并且只针对其中的下三角区域。

similarities = [[ 1.          0.18898224  0.16903085]
 [ 0.18898224  1.          0.67082039]
 [ 0.16903085  0.67082039  1.        ]]

在这种情况下,如果我想要两个最高值,我希望它返回 [1, 0][2, 1]

我尝试过使用argpartition,但这并没有返回我正在寻找的内容

n_select = 1
most_similar = (-similarities).argpartition(n_select, axis=None)[:n_select]

如何获得不包括对角线 1 的 n 个最高值并排除上三角元素?

【问题讨论】:

  • 不是 [1, 0] 和 [2, 1] 两个最大值吗?矩阵是否总是对称的,您只对下/上三角部分感兴趣?
  • 抱歉,是的,我的索引有误。矩阵总是对称的。

标签: python arrays numpy distance


【解决方案1】:

方法#1

np.tril_indices 的一种方法-

def n_largest_indices_tril(a, n=2):
    m = a.shape[0]
    r,c = np.tril_indices(m,-1)
    idx = a[r,c].argpartition(-n)[-n:]
    return zip(r[idx], c[idx])

示例运行 -

In [39]: a
Out[39]: 
array([[ 1.  ,  0.4 ,  0.59,  0.15,  0.29],
       [ 0.4 ,  1.  ,  0.03,  0.57,  0.57],
       [ 0.59,  0.03,  1.  ,  0.9 ,  0.52],
       [ 0.15,  0.57,  0.9 ,  1.  ,  0.37],
       [ 0.29,  0.57,  0.52,  0.37,  1.  ]])

In [40]: n_largest_indices_tril(a, n=2)
Out[40]: [(2, 0), (3, 2)]

In [41]: n_largest_indices_tril(a, n=3)
Out[41]: [(4, 1), (2, 0), (3, 2)]

方法 #2

为了性能,我们可能希望避免生成所有下三角索引,而是使用掩码,为我们提供第二种解决问题的方法,就像这样 -

def n_largest_indices_tril_v2(a, n=2):
    m = a.shape[0]
    r = np.arange(m)
    mask = r[:,None] > r
    idx = a[mask].argpartition(-n)[-n:]

    clens = np.arange(m).cumsum()    
    grp_start = clens[:-1]
    grp_stop = clens[1:]-1    

    rows = np.searchsorted(grp_stop, idx)+1    
    cols  = idx - grp_start[rows-1]
    return zip(rows, cols)

运行时测试

In [143]: # Setup symmetric array 
     ...: N = 1000
     ...: a = np.random.rand(N,N)*0.9
     ...: np.fill_diagonal(a,1)
     ...: m = a.shape[0]
     ...: r,c = np.tril_indices(m,-1)
     ...: a[r,c] = a[c,r]

In [144]: %timeit n_largest_indices_tril(a, n=2)
100 loops, best of 3: 12.5 ms per loop

In [145]: %timeit n_largest_indices_tril_v2(a, n=2)
100 loops, best of 3: 7.85 ms per loop

对于n 最小索引

要获得最小的n,只需使用ndarray.argpartition(n)[:n] 代替这两种方法。

【讨论】:

  • 谢谢!我目前无法对此进行测试,但它很有意义。只是好奇,n 最小的索引会是idx = a[r,c].argpartition(-n)[:-n]
  • @Adam_G a[r,c].argpartition(n)[:n] 而不是。
【解决方案2】:

请记住,方阵的对角线元素有一个独特的性质:i+j=n,其中 n 是矩阵维数。 然后,您可以找到数组的 n + 个(对角线元素)最大元素,然后遍历它们并排除 i+j=n 的元组 (i,j)。 希望对您有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-18
    • 2017-03-27
    • 1970-01-01
    • 2013-05-24
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多