【问题标题】:Sorting a numpy array based on data from another array根据来自另一个数组的数据对 numpy 数组进行排序
【发布时间】:2016-04-11 23:35:36
【问题描述】:

我有两组数组data 和result。 result 包含与 data 相同的元素,但有一个额外的列且未排序。我想重新排列 result 数组,使其与 data 中的行顺序相同,同时在进行排序时将关联的值与行的其余部分一起放入最后一列。

data = np.array([[0,1,0,0],[1,0,0,0],[0,1,1,0],[0,1,0,1]])
result = np.array([[0,1,1,0,1],[1,0,0,0,0],[0,1,0,0,1],[0,1,0,1,0]])

# this is what the final sorted array should look like:
'''
array([[0, 1, 0, 0, 1],
       [1, 0, 0, 0, 0],
       [0, 1, 1, 0, 1],
       [0, 1, 0, 1, 0]])
 '''

我尝试过 argsort 以将 data 反转为排序顺序,然后将其应用于 result 但 argsort 似乎根据每个元素对数组的顺序进行排序,而我想要sort 将data[:,4] 的每一行视为一个整体。

ind = np.argsort(data)
indind =np.argsort(ind)
ind
array([[0, 2, 3, 1],
   [1, 2, 3, 0],
   [0, 3, 1, 2],
   [0, 2, 1, 3]])

这种按行排序的好方法是什么?

【问题讨论】:

  • 额外的列总是放在序列的最后吗?

标签: python sorting numpy


【解决方案1】:

numpy_indexed 包(免责声明:我是它的作者)可以用来高效优雅地解决这类问题:

import numpy_indexed as npi
result[npi.indices(result[:, :-1], data)]

npi.indices 本质上是 list.index 的矢量化等价物;因此,对于数据中的每个元素(行),我们得到同一行在结果中的位置,减去最后一列。

请注意,此解决方案适用于任意数量的列,并且是完全矢量化的(即,任何地方都没有 python 循环)。

【讨论】:

    【解决方案2】:

    方法#1

    这是一种将每一行视为一个索引元组的方法,然后在data 和result 之间找到对应于这些线性索引等效项的匹配索引。这些索引将代表新的行顺序,当索引到结果中时,将为我们提供所需的输出。实现看起来像这样 -

    # Slice out from result everything except the last column       
    r = result[:,:-1]       
    
    # Get linear indices equivalent of each row from r and data
    ID1 = np.ravel_multi_index(r.T,r.max(0)+1)
    ID2 = np.ravel_multi_index(data.T,r.max(0)+1)
    
    # Search for ID2 in ID1 and use those indices index into result
    out = result[np.where(ID1[:,None] == ID2)[1]]
    

    方法 #2

    如果data 中的所有行都保证在result 中,您可以使用仅基于argsort 的另一种方法,就像这样 -

    # Slice out from result everything except the last column       
    r = result[:,:-1]       
    
    # Get linear indices equivalent of each row from r and data
    ID1 = np.ravel_multi_index(r.T,r.max(0)+1)
    ID2 = np.ravel_multi_index(data.T,r.max(0)+1)   
    
    sortidx_ID1 = ID1.argsort()
    sortidx_ID2 = ID2.argsort()
    out = result[sortidx_ID1[sortidx_ID2]]
    

    为更通用的案例运行示例 -

    In [37]: data
    Out[37]: 
    array([[ 3,  2,  1,  5],
           [ 4,  9,  2,  4],
           [ 7,  3,  9, 11],
           [ 5,  9,  4,  4]])
    
    In [38]: result
    Out[38]: 
    array([[ 7,  3,  9, 11, 55],
           [ 4,  9,  2,  4,  8],
           [ 3,  2,  1,  5,  7],
           [ 5,  9,  4,  4, 88]])
    
    In [39]: r = result[:,:-1]
        ...: ID1 = np.ravel_multi_index(r.T,r.max(0)+1)
        ...: ID2 = np.ravel_multi_index(data.T,r.max(0)+1)
        ...: 
    
    In [40]: result[np.where(ID1[:,None] == ID2)[1]] # Approach 1
    Out[40]: 
    array([[ 3,  2,  1,  5,  7],
           [ 4,  9,  2,  4,  8],
           [ 7,  3,  9, 11, 55],
           [ 5,  9,  4,  4, 88]])
    
    In [41]: sortidx_ID1 = ID1.argsort()  # Approach 2
        ...: sortidx_ID2 = ID2.argsort()
        ...: 
    
    In [42]: result[sortidx_ID1[sortidx_ID2]]
    Out[42]: 
    array([[ 3,  2,  1,  5,  7],
           [ 4,  9,  2,  4,  8],
           [ 7,  3,  9, 11, 55],
           [ 5,  9,  4,  4, 88]])
    

    【讨论】:

    • 这个答案适用于我上面给出的示例这样的小数据集,但是当我使用更大的示例(5172x32 数据集)时,它会给我错误“ValueError:传递给 ravel_multi_index 的维度太多”。我应该如何解决这个问题?
    • @ROBOTPWNS 像这样计算那些ID1和ID2,看看它是否有效:ID1 = r.dot(r.max(0)+1); ID2 = data.dot(r.max(0)+1)?
    • 不,那没有用,我最终只是在序列混合之前重建了数组,然后根据这些指标进行了排序。不过还是谢谢。
    【解决方案3】:

    只是想弄清楚你在做什么。使用索引列表 [2,1,0,3] 我可以重新排序 result 的行,因此:

    In [37]: result[[2,1,0,3],:]
    Out[37]: 
    array([[0, 1, 0, 0, 1],
           [1, 0, 0, 0, 0],
           [0, 1, 1, 0, 1],
           [0, 1, 0, 1, 0]])
    
    In [38]: result[[2,1,0,3],:4]==data
    Out[38]: 
    array([[ True,  True,  True,  True],
           [ True,  True,  True,  True],
           [ True,  True,  True,  True],
           [ True,  True,  True,  True]], dtype=bool)
    

    我不知道argsort 或sort 将如何帮助提出这个索引顺序。

    使用np.lexsort 我可以对两个数组的行进行相同的排序:

    In [54]: data[np.lexsort(data.T),:]
    Out[54]: 
    array([[1, 0, 0, 0],
           [0, 1, 0, 0],
           [0, 1, 1, 0],
           [0, 1, 0, 1]])
    
    In [55]: result[np.lexsort(result[:,:-1].T),:]
    Out[55]: 
    array([[1, 0, 0, 0, 0],
           [0, 1, 0, 0, 1],
           [0, 1, 1, 0, 1],
           [0, 1, 0, 1, 0]])
    

    我通过反复试验发现我需要使用转置。我们需要查看lexsort 的文档以了解原因。

    更多的尝试和错误产生:

    In [66]: i=np.lexsort(data.T)
    In [67]: j=np.lexsort(result[:,:-1].T)
    In [68]: j[i]
    Out[68]: array([2, 1, 0, 3], dtype=int64)
    
    In [69]: result[j[i],:]
    Out[69]: 
    array([[0, 1, 0, 0, 1],
           [1, 0, 0, 0, 0],
           [0, 1, 1, 0, 1],
           [0, 1, 0, 1, 0]])
    

    这是一个暂定的解决方案。它需要在其他样品上进行测试。并且需要解释。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-02
      • 1970-01-01
      • 2022-12-18
      相关资源
      最近更新 更多