有效地对numpy数组进行降序排序?


121

令我惊讶的是,之前没有提出过这个具体问题,但是我真的没有在SO或文档中找到它np.sort

假设我有一个包含整数的随机numpy数组,例如:

> temp = np.random.randint(1,10, 10)    
> temp
array([2, 4, 7, 4, 2, 2, 7, 6, 4, 4])

如果对它进行排序,则默认情况下我将获得升序:

> np.sort(temp)
array([2, 2, 2, 4, 4, 4, 4, 6, 7, 7])

但我希望解决方案按降序排序。

现在,我知道我可以永远做:

reverse_order = np.sort(temp)[::-1]

但这最后的陈述有效吗?它不是按升序创建副本,然后反转此副本以反转顺序获得结果吗?如果确实如此,是否有有效的选择?看起来好像不np.sort接受参数来更改排序操作中的比较符号以使事情相反。

Answers:


139

temp[::-1].sort()对数组进行排序,然后np.sort(temp)[::-1]创建一个新数组。

In [25]: temp = np.random.randint(1,10, 10)

In [26]: temp
Out[26]: array([5, 2, 7, 4, 4, 2, 8, 6, 4, 4])

In [27]: id(temp)
Out[27]: 139962713524944

In [28]: temp[::-1].sort()

In [29]: temp
Out[29]: array([8, 7, 6, 5, 4, 4, 4, 4, 2, 2])

In [30]: id(temp)
Out[30]: 139962713524944

30
谢谢,但是怎么temp[::-1].sort()知道它必须以相反的顺序排序呢?我的阅读方式是:反转原始数组,然后对其进行排序(以升序排列)。为什么要反转原始数组(以随机顺序出现)然后按升序排序将数组以反转顺序返回?
Amelio Vazquez-Reina 2014年

14
是否已记录此行为,因为这很不直观。
ebarr 2014年

18
这看起来像行得通,因为[::-1]简单地告诉numpy向后遍历数组,而不是实际对数组重新排序。因此,当发生就地排序时,它实际上是按升序排序并在周围移动位,但保留了反向迭代部分。
perimosocordiae 2014年

45
使用a=np.array((...))该惯用法a[::-1]不会反转任何内容,它只是对相同数据的新视图,更具体地说是镜像视图。该方法a[::-1].sort() 对镜像图像进行操作,这意味着当在其镜像图像中向左sort移动较小项时,实际上是在数组的实际存储块中将其向右移动。镜像视图按升序排序,实际数据按降序排序。自己尝试,用一些不同的硬币和一面镜子,自己在家尝试吧!a
gboffi 2014年

30
这确实应该被添加为可读的参数,喜欢np.sort(temp,order='descending')而不需要这些类型的黑客
弥敦道

92
>>> a=np.array([5, 2, 7, 4, 4, 2, 8, 6, 4, 4])

>>> np.sort(a)
array([2, 2, 4, 4, 4, 4, 5, 6, 7, 8])

>>> -np.sort(-a)
array([8, 7, 6, 5, 4, 4, 4, 4, 2, 2])

2
最佳答案-短小精悍,并且没有知识axisnp.sort应用是必要的。
卢克·戴维斯

2
这与np.sort(temp)[::-1]nans放在数组的后面而不是数组的前面不同。不管是好还是坏是为辩论..

15

对于短数组,我建议np.argsort()通过查找已排序的否定数组的索引来使用,这比反转已排序的数组要快一些:

In [37]: temp = np.random.randint(1,10, 10)

In [38]: %timeit np.sort(temp)[::-1]
100000 loops, best of 3: 4.65 µs per loop

In [39]: %timeit temp[np.argsort(-temp)]
100000 loops, best of 3: 3.91 µs per loop

a[np.argsort(-a)]可能是此页面上其他方法最好的方法。没有-1步反转,可考虑减少一个负号。
Jarad

8

不幸的是,当您有一个复杂的数组时,只能np.sort(temp)[::-1]正常工作。这里提到的其他两种方法无效。


@ anishtain4:“复数数组”是指复数数组吗?还是您说的是具有其他复杂性的数组(如果这样,请指定哪种复杂性)。无论哪种情况,我都认为您可以通过研究其他方法可能失败的方式来详细说明答案。谢谢。
水源

@fountainhead我的意思是复数数组。由于这是一个老问题,因此我不记得我的测试用例了。
anishtain4

7

注意尺寸。

x  # initial numpy array
I = np.argsort(x) or I = x.argsort() 
y = np.sort(x)    or y = x.sort()
z  # reverse sorted array

全反转

z = x[-I]
z = -np.sort(-x)
z = np.flip(y)
  • flip更改1.15需要以前的版本。解决方案:。1.14 axispip install --upgrade numpy

第一维反转

z = y[::-1]
z = np.flipud(y)
z = np.flip(y, axis=0)

逆向二维

z = y[::-1, :]
z = np.fliplr(y)
z = np.flip(y, axis=1)

测试中

在100×10×10阵列上测试1000次。

Method       | Time (ms)
-------------+----------
y[::-1]      | 0.126659  # only in first dimension
-np.sort(-x) | 0.133152
np.flip(y)   | 0.121711
x[-I]        | 4.611778

x.sort()     | 0.024961
x.argsort()  | 0.041830
np.flip(x)   | 0.002026

这主要是由于重新索引而不是argsort

# Timing code
import time
import numpy as np


def timeit(fun, xs):
    t = time.time()
    for i in range(len(xs)):  # inline and map gave much worse results for x[-I], 5*t
        fun(xs[i])
    t = time.time() - t
    print(np.round(t,6))

I, N = 1000, (100, 10, 10)
xs = np.random.rand(I,*N)
timeit(lambda x: np.sort(x)[::-1], xs)
timeit(lambda x: -np.sort(-x), xs)
timeit(lambda x: np.flip(x.sort()), xs)
timeit(lambda x: x[-x.argsort()], xs)
timeit(lambda x: x.sort(), xs)
timeit(lambda x: x.argsort(), xs)
timeit(lambda x: np.flip(x), xs)

6

您好,我在寻找一种对二维numpy数组进行反向排序的解决方案,但找不到任何有效的方法,但是我想我偶然发现了一个我上载的解决方案,以防万一有人在同一条船上。

x=np.sort(array)
y=np.fliplr(x)

np.sort对升序进行排序,这不是您想要的,但是命令fliplr将行从左向右翻转!似乎可以工作!

希望它可以帮助您!

我猜这与上面关于-np.sort(-a)的建议相似,但是由于评论它并不总是有效而推迟了我的建议。也许我的解决方案也不总是可行,但是我已经用几个阵列对其进行了测试,似乎还可以。


1

您可以先对数组进行排序(默认为升序),然后应用np.flip()https://docs.scipy.org/doc/numpy/reference/generated/numpy.flip.html

仅供参考,它也适用于日期时间对象。

例:

    x = np.array([2,3,1,0]) 
    x_sort_asc=np.sort(x) 
    print(x_sort_asc)

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

    x_sort_desc=np.flip(x_sort_asc) 
    print(x_sort_desc)

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

对于那些在阵列中具有NaN的人要小心,各种建议的方法会产生不同的结果。例如,如果x = np.array([2,3,np.nan,1,0]) np.flip(np.sort(x))方法得出[nan 3. 2. 1. 0.nan],而该-np.sort(-x)方法得出[3. 2. 1. 0. nan]。
Uwe Mayer

1

这是一个快速窍门

In[3]: import numpy as np
In[4]: temp = np.random.randint(1,10, 10)
In[5]: temp
Out[5]: array([5, 4, 2, 9, 2, 3, 4, 7, 5, 8])

In[6]: sorted = np.sort(temp)
In[7]: rsorted = list(reversed(sorted))
In[8]: sorted
Out[8]: array([2, 2, 3, 4, 4, 5, 5, 7, 8, 9])

In[9]: rsorted
Out[9]: [9, 8, 7, 5, 5, 4, 4, 3, 2, 2]

-3

我建议使用这个...

np.arange(start_index, end_index, intervals)[::-1]

例如:

np.arange(10, 20, 0.5)
np.arange(10, 20, 0.5)[::-1]

然后您的恢复:

[ 19.5,  19. ,  18.5,  18. ,  17.5,  17. ,  16.5,  16. ,  15.5,
    15. ,  14.5,  14. ,  13.5,  13. ,  12.5,  12. ,  11.5,  11. ,
    10.5,  10. ]

1
这如何解决问题?您只是在创建一个完全不相关的,新的(递减)数组(顺便说一句),该数组可以通过更有效的方式完成:np.arange(20-0.5, 10-0.5, -0.5)。但这是一个不同的故事,由于可读性较差,可能值得商bat。输入数组是不是在所有分类
丹尼尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.