使用numpy,您可以进行间接排序。也就是说,来自像
这样的数组>> a = array([ 8, 10, 5, 2, 3, 1, 6])
然后做这样的间接排序:
>> np.argsort(a)
>> array([5, 3, 4, 2, 6, 0, 1])
这个数组表示“在有序数组的第0个位置应该是输入数组的a[5]
之一”,有序数组的第1个位置应为a[3]
“等等。但是,是否有一种Numpy驱动的方式来获得类似“应该在这里”的订单?我的意思是什么?使用argsort,您具有对输入数组进行排序的索引顺序,因此a[np.argsort(a)]
是一个有序数组。但是,我需要的是相反的,即,对于输入数组的每个元素,获取元素在有序数组上的位置。例如:
>>myweirdsort(a)
>>array([5, 6, 3, 1, 2, 0, 4])
这个数组表示类似“a[0]
进入有序数组的第5个位置,a[1]
进入有序数组的第6个位置”等等。
顺便说一下,当我说“Numpy-powered”时,我指的是一个矢量化的Numpy-ish方法来做到这一点。非Numpy方式应该只是遍历每个元素,做类似于数组的分区,然后找出元素在分区数组中的最终位置,但这需要太长时间。
答案 0 :(得分:6)
你只需要再次argsort argsort:
>>> a.argsort().argsort()
array([5, 6, 3, 1, 2, 0, 4], dtype=int64)
答案 1 :(得分:4)
虽然@BrenBarn的解决方案非常有效,非常紧凑,并且通常采用numpy代码构造,但您必须进行两次排序,这总是让我觉得有点浪费。事实证明你不必做第二种。以下代码并不简洁,但对于大型数组来说会更快:
>>> my_weird_sort = np.empty_like(idx)
>>> my_weird_sort[idx] = np.arange(idx.size)
>>> my_weird_sort
array([5, 6, 3, 1, 2, 0, 4])
快多少?我做了一些时间,在我的系统上,对于小尺寸,它的速度稍慢,对于大约100-200个项目的阵列开始更快,对于1000到1,000,000个项目的阵列,速度大约快1.4-1.5倍。
为了完整性,通常使用类似的构造来首先对数组进行排序,为排序数组中的每个项获取一些值,然后将结果重新排序回未排序状态。例如,要查明某个项是否是数组中该值的第一个实例,您可以执行以下操作:
>>> b = np.array([1, 3, 1, 2, 4, 3, 3, 2, 0])
>>> idx = np.argsort(b, kind='mergesort') # need stable sort
>>> sorted_b = b[idx]
>>> sorted_b
array([0, 1, 1, 2, 2, 3, 3, 3, 4])
>>> sorted_is_first = np.concatenate(([True], sorted_b[1:] != sorted_b[:-1]))
>>> sorted_is_first
array([ True, True, False, True, False, True, False, False, True], dtype=bool)
>>> is_first = sorted_is_first[idx.argsort()]
>>> is_first
array([ True, True, False, True, True, False, False, False, True], dtype=bool)
您也可以通过与上述类似的方式在没有第二种情况下获得此内容:
>>> is_first = np.empty_like(sorted_is_first)
>>> is_first[idx] = sorted_is_first
>>> is_first
array([ True, True, False, True, True, False, False, False, True], dtype=bool)
最近向np.unique
添加了与此类似的更改,对于请求return_inverse
索引的情况,请参阅here。在这种情况下,较大尺寸的速度几乎是2倍。