Mengurutkan array numpy secara efisien dalam urutan menurun?

121

Saya terkejut pertanyaan khusus ini belum pernah ditanyakan sebelumnya, tetapi saya benar-benar tidak menemukannya di SO atau di dokumentasi np.sort.

Katakanlah saya memiliki bilangan bulat numpy array acak, misalnya:

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

Jika saya mengurutkannya, saya mendapatkan urutan naik secara default:

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

tetapi saya ingin solusinya diurutkan dalam urutan menurun .

Sekarang, saya tahu saya selalu bisa melakukan:

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

tetapi apakah pernyataan terakhir ini efisien ? Bukankah itu membuat salinan dalam urutan naik, dan kemudian membalik salinan ini untuk mendapatkan hasil dalam urutan terbalik? Jika memang demikian, apakah ada alternatif yang efisien? Ini tidak terlihat seperti np.sortmenerima parameter untuk mengubah tanda perbandingan dalam operasi pengurutan untuk mendapatkan segala sesuatunya dalam urutan terbalik.

Amelio Vazquez-Reina
sumber

Jawaban:

139

temp[::-1].sort()mengurutkan array di tempat, sedangkan np.sort(temp)[::-1]membuat array baru.

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
Padraic Cunningham
sumber
30
Terima kasih, tetapi bagaimana cara temp[::-1].sort()mengetahui bahwa ia harus mengurutkan dalam urutan terbalik ?? Cara saya membacanya adalah: membalikkan larik aslinya, lalu mengurutkannya (dalam urutan menaik). Mengapa membalikkan larik asli (datang dalam urutan acak) dan kemudian mengurutkannya dalam urutan menaik mengembalikan larik dalam urutan terbalik?
Amelio Vazquez-Reina
14
Apakah perilaku ini didokumentasikan, karena sangat tidak intuitif.
ebarr
18
Sepertinya ini berfungsi karena perintah tersebut [::-1]hanya memberi tahu numpy untuk melakukan iterasi ke belakang larik, daripada benar-benar menyusun ulang larik. Jadi saat pengurutan di tempat terjadi, pengurutan sebenarnya dalam urutan menaik dan memindahkan bit, tetapi membiarkan bagian iterasi mundur tidak tersentuh.
perimosocordiae
45
Dengan a=np.array((...))idiom a[::-1]tidak membalikkan apa pun, itu hanya tampilan baru pada data yang sama, lebih khusus lagi tampilan cermin. Metode ini a[::-1].sort() beroperasi pada gambar yang dicerminkan , menyiratkan bahwa ketika sortbergerak meninggalkan item yang lebih kecil dalam gambar cerminnya, pada kenyataannya metode ini memindahkannya ke kanan dalam blok memori sebenarnya dari aarray. Tampilan cermin diurutkan dalam urutan menaik, data sebenarnya diurutkan dalam urutan menurun. Cobalah sendiri di rumah, dengan beberapa koin dan cermin yang berbeda!
gboffi
30
Ini benar-benar harus ditambahkan sebagai parameter yang dapat dibaca, seperti np.sort(temp,order='descending')daripada memerlukan peretasan semacam ini
Nathan
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])
Mike O'Connor
sumber
2
Jawaban terbaik - singkat dan manis, dan tidak diperlukan pengetahuan tentang axisyang np.sorttelah diterapkan.
Luke Davis
2
Ini berbeda np.sort(temp)[::-1]dengan yang menempatkan nans di bagian belakang array, bukan di depan. Apakah itu baik atau buruk untuk diperdebatkan ..
Ben
15

Untuk array pendek saya sarankan menggunakan np.argsort()dengan mencari indeks dari array negatif yang diurutkan, yang sedikit lebih cepat daripada membalikkan array yang diurutkan:

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
Kasravnd
sumber
a[np.argsort(-a)]mungkin merupakan pendekatan terbaik untuk orang lain di halaman ini. Tidak ada pembalikan -1 langkah dan satu tanda kurang kurang untuk dipikirkan.
Jarad
8

Sayangnya bila Anda memiliki array yang kompleks, hanya np.sort(temp)[::-1]berfungsi dengan baik. Dua metode lain yang disebutkan di sini tidak efektif.

anishtain4
sumber
@ anishtain4: Yang Anda maksud dengan "array kompleks" adalah array bilangan kompleks? Atau apakah yang Anda maksud adalah array dengan beberapa jenis kompleksitas lain (jika demikian, tolong tentukan jenis kerumitan apa). Dalam kedua kasus tersebut, saya merasa Anda dapat menguraikan lebih lanjut tentang jawaban Anda, dengan memahami bagaimana metode lain mungkin gagal. Terima kasih.
Fountainhead
@fountainhead yang saya maksud adalah deretan bilangan kompleks. Karena ini adalah pertanyaan lama, saya tidak ingat kasus uji saya sejak saat itu untuk menjelaskan lebih lanjut.
anishtain4
7

Hati-hati dengan dimensinya.

Membiarkan

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

Terbalik Penuh

z = x[-I]
z = -np.sort(-x)
z = np.flip(y)
  • flipdiubah 1.15, versi sebelumnya diperlukan . Solusi: .1.14 axispip install --upgrade numpy

Dimensi Pertama Terbalik

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

Dimensi Kedua Terbalik

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

Menguji

Menguji pada array 100 × 10 × 10 1000 kali.

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

Ini terutama karena pengindeksan ulang, bukan 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)
A. West
sumber
6

Halo Saya sedang mencari solusi untuk membalikkan penyortiran array numpy dua dimensi, dan saya tidak dapat menemukan apa pun yang berhasil, tetapi saya pikir saya telah menemukan solusi yang saya unggah untuk berjaga-jaga jika ada orang di kapal yang sama.

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

np.sort mengurutkan ascending yang bukan yang Anda inginkan, tetapi perintah fliplr membalik baris dari kiri ke kanan! Sepertinya berhasil!

Semoga membantu Anda!

Saya kira ini mirip dengan saran tentang -np.sort (-a) di atas tetapi saya menunda melakukannya dengan komentar bahwa itu tidak selalu berhasil. Mungkin solusi saya tidak selalu berhasil, namun saya telah mengujinya dengan beberapa array dan tampaknya OK.

Naz
sumber
1

Anda bisa mengurutkan array terlebih dahulu (Naik secara default) dan kemudian menerapkan np.flip () ( https://docs.scipy.org/doc/numpy/reference/generated/numpy.flip.html )

FYI Ia bekerja dengan objek datetime juga.

Contoh:

    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])
maleckicoa
sumber
Bagi mereka yang memiliki NaN dalam arraynya, berhati-hatilah, berbagai metode yang diusulkan menghasilkan hasil yang berbeda. Misalnya jika x = np.array([2,3,np.nan,1,0]) maka np.flip(np.sort(x))pendekatan menghasilkan [nan 3. 2. 1. 0.], sedangkan -np.sort(-x)pendekatan menghasilkan [3. 2. 1. 0. nan].
Uwe Mayer
1

Ini trik cepat

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]
Don Coder
sumber
-3

saya sarankan menggunakan ini ...

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

sebagai contoh:

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

Kemudian jawaban Anda:

[ 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. ]
morteza omidipoor
sumber
1
Bagaimana cara ini mengatasi masalah? Anda hanya menciptakan benar-benar, tidak terkait, baru (menurun) array yang yang - dengan cara - bisa dilakukan dengan cara yang lebih efisien: np.arange(20-0.5, 10-0.5, -0.5). Tapi itu cerita yang berbeda dan mungkin, karena keterbacaan yang lebih buruk, bisa diperdebatkan. Array input tidak diurutkan sama sekali
Daniel