Эффективно сортировать массив numpy в порядке убывания?

Я удивлен, что этот конкретный вопрос не задавался раньше, но я действительно не нашел его на 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 принимает параметры для изменения знака сравнений в операции сортировки, чтобы получить вещи в обратном порядке.

Ответ 1

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

Ответ 2

>>> 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])

Ответ 3

Для коротких массивов я предлагаю использовать 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

Ответ 4

К сожалению, когда у вас сложный массив, работает только np.sort(temp)[::-1]. Два других метода, упомянутых здесь, неэффективны.

Ответ 5

Здравствуйте! Я искал решение для обратной сортировки двумерного массива numpy, и я не смог найти ничего, что сработало, но я думаю, что наткнулся на решение, которое я загружаю на тот случай, если кто-нибудь окажется в одной лодке.

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

np.sort сортирует по возрастанию, что не то, что вам нужно, но команда fliplr переворачивает строки слева направо! Кажется, работает!

Надеюсь, это поможет вам!

Я предполагаю, что это похоже на предложение о -np.sort(-a) выше, но я был отстранен от комментариев, что это не всегда работает. Возможно, мое решение не всегда будет работать, однако я проверил его с несколькими массивами и, похоже, все в порядке.

Ответ 6

Я предлагаю использовать это...

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. ]

Ответ 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 требовалось axis. Решение: pip 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)