Python 基于来自另一个数组的数据对numpy数组进行排序

Python 基于来自另一个数组的数据对numpy数组进行排序,python,sorting,numpy,Python,Sorting,Numpy,我有两组数组数据和结果结果在数据中包含相同的元素,但有一个额外的列,且未排序。我想重新排列结果数组,使其与数据中的行的顺序相同,同时在排序时将关联的值与行的其余部分一起放入最后一列 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 sorte

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

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
数据
反转为排序顺序,然后将其应用于
结果
,但是
argsort
似乎根据每个元素对数组的顺序进行排序,而我希望排序将
数据[:,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]])

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

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

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]])
这是一个初步的解决办法。它需要在其他样品上进行测试。需要解释。

方法#1

这是一种将每一行视为索引元组的方法,然后找到与这些线性索引等价物对应的
数据
结果
之间的匹配索引。这些索引将表示新的行顺序,当索引到结果中时,将为我们提供所需的输出。实现如下所示-

# 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

如果
数据
中的所有行都保证在
结果
中,则可以使用另一种基于
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]])
该软件包(免责声明:我是其作者)可用于高效、优雅地解决此类问题:

import numpy_indexed as npi
result[npi.indices(result[:, :-1], data)]
npi.index本质上是list.index的向量化等价物;所以对于数据中的每个元素(行),我们得到了结果中相同行的位置,减去最后一列


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

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