Sắp xếp hiệu quả một mảng numpy theo thứ tự giảm dần?


121

Tôi ngạc nhiên vì câu hỏi cụ thể này chưa từng được hỏi trước đây, nhưng tôi thực sự không tìm thấy nó trên SO cũng như trên tài liệu của np.sort.

Giả sử tôi có một mảng numpy ngẫu nhiên chứa các số nguyên, ví dụ:

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

Nếu tôi sắp xếp nó, tôi nhận được thứ tự tăng dần theo mặc định:

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

nhưng tôi muốn giải pháp được sắp xếp theo thứ tự giảm dần .

Bây giờ, tôi biết tôi luôn có thể làm:

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

nhưng câu lệnh cuối cùng này có hiệu quả không? Nó không tạo một bản sao theo thứ tự tăng dần, và sau đó đảo ngược bản sao này để nhận được kết quả theo thứ tự đảo ngược? Nếu điều này thực sự xảy ra, có một giải pháp thay thế hiệu quả không? Nó không giống như np.sortchấp nhận các tham số để thay đổi dấu hiệu của các phép so sánh trong thao tác sắp xếp để đưa mọi thứ theo thứ tự ngược lại.

Câu trả lời:


139

temp[::-1].sort()sắp xếp mảng tại chỗ, ngược lại np.sort(temp)[::-1]tạo một mảng mới.

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
Cảm ơn, nhưng làm sao temp[::-1].sort()biết rằng nó phải sắp xếp theo thứ tự ngược lại ?? Cách tôi đọc nó là: đảo ngược mảng ban đầu, và sau đó sắp xếp nó (theo thứ tự tăng dần). Tại sao việc đảo ngược mảng ban đầu (sắp xếp theo thứ tự ngẫu nhiên) và sau đó sắp xếp nó theo thứ tự tăng dần lại trả về mảng theo thứ tự đảo ngược?
Amelio Vazquez-Reina

14
Hành vi này có được ghi lại không, vì nó khá là không trực quan.
ebarr

18
Điều này có vẻ như nó hoạt động vì nó [::-1]chỉ đơn giản ra lệnh cho numpy lặp lại mảng ngược lại, thay vì thực sự sắp xếp lại thứ tự mảng. Vì vậy, khi sắp xếp tại chỗ xảy ra, nó thực sự sắp xếp theo thứ tự tăng dần và di chuyển các bit xung quanh, nhưng để lại phần lặp lại không bị ảnh hưởng.
perimosocordiae

45
Với a=np.array((...))thành ngữ a[::-1]không đảo ngược bất cứ điều gì, nó chỉ là một cái nhìn mới trên cùng một dữ liệu, cụ thể hơn là một cái nhìn phản chiếu. Phương thức này a[::-1].sort() hoạt động trên hình ảnh được phản chiếu , ngụ ý rằng khi sortdi chuyển sang trái một mục nhỏ hơn trong hình ảnh được phản chiếu của nó, trên thực tế, nó đang di chuyển nó sang phải trong khối bộ nhớ thực của amảng. Chế độ xem được nhân đôi được sắp xếp theo thứ tự tăng dần, dữ liệu thực được sắp xếp theo thứ tự giảm dần. Hãy thử nó ở nhà một mình, với một số đồng xu khác nhau và một chiếc gương!
gboffi

30
Đây thực sự nên được thêm vào như một tham số có thể đọc được, thích np.sort(temp,order='descending')chứ không phải là đòi hỏi những loại hacks
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])

2
Câu trả lời hay nhất - ngắn và ngọt ngào, và không có kiến thức về axisnp.sortđã được áp dụng là cần thiết.
Luke Davis

2
Điều này khác np.sort(temp)[::-1]ở chỗ nó đặt nans ở phía sau của mảng thay vì phía trước. Cho dù điều đó tốt hay xấu vẫn còn để tranh luận ..
Ben

15

Đối với mảng ngắn, tôi khuyên bạn nên sử dụng bằng np.argsort()cách tìm các chỉ số của mảng phủ định đã sắp xếp, nhanh hơn một chút so với việc đảo ngược mảng đã sắp xếp:

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)]có lẽ là cách tiếp cận tốt nhất cho bất kỳ người nào khác trên trang này. Không có -1 bước đảo ngược và một dấu trừ ít hơn để suy nghĩ về.
Jarad

8

Thật không may khi bạn có một mảng phức tạp, chỉ np.sort(temp)[::-1]hoạt động đúng cách. Hai phương pháp khác được đề cập ở đây không hiệu quả.


@ anishtain4: Theo "mảng phức", ý bạn là một mảng các số phức? Hoặc bạn có nghĩa là một mảng với một số loại phức tạp khác (nếu vậy xin vui lòng chỉ định loại phức tạp). Trong cả hai trường hợp, tôi cảm thấy bạn có thể giải thích thêm một số chi tiết về câu trả lời của mình, bằng cách tìm hiểu cách các phương pháp khác có thể thất bại. Cảm ơn.
đài phun nước vào

@fountainhead Ý tôi là mảng các số phức. Vì nó là một câu hỏi cũ nên tôi không nhớ trường hợp thử nghiệm của mình từ đó để giải thích thêm.
anishtain

7

Hãy cẩn thận với các kích thước.

Để cho

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

Đảo ngược hoàn toàn

z = x[-I]
z = -np.sort(-x)
z = np.flip(y)
  • flipđã thay đổi 1.15, cần có phiên bản trước . Giải pháp: .1.14 axispip install --upgrade numpy

Thứ nguyên đầu tiên được đảo ngược

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

Thứ nguyên thứ hai được đảo ngược

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

Thử nghiệm

Thử nghiệm trên mảng 100 × 10 × 10 1000 lần.

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

Điều này chủ yếu là do lập chỉ mục lại chứ không phải 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

Xin chào Tôi đang tìm kiếm một giải pháp để sắp xếp ngược lại một mảng numpy hai chiều và tôi không thể tìm thấy bất kỳ thứ gì hiệu quả, nhưng tôi nghĩ rằng tôi đã vấp phải một giải pháp mà tôi đang tải lên để đề phòng bất kỳ ai ở cùng thuyền.

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

np.sort sắp xếp tăng dần không phải là những gì bạn muốn, nhưng lệnh flipplr lật các hàng từ trái sang phải! Có vẻ hiệu quả!

Hy vọng nó giúp được bạn!

Tôi đoán nó tương tự như đề xuất về -np.sort (-a) ở trên nhưng tôi đã bị tạm dừng vì nhận xét rằng nó không phải lúc nào cũng hoạt động. Có lẽ giải pháp của tôi cũng không phải lúc nào cũng hoạt động, tuy nhiên tôi đã thử nghiệm nó với một vài mảng và có vẻ ổn.


1

Bạn có thể sắp xếp mảng trước (Tăng dần theo mặc định) và sau đó áp dụng np.flip () ( https://docs.scipy.org/doc/numpy/reference/generated/numpy.flip.html )

FYI Nó cũng hoạt động với các đối tượng datetime.

Thí dụ:

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

Đối với những người có NaN trong mảng của họ, hãy cẩn thận, các phương pháp được đề xuất khác nhau tạo ra các kết quả khác nhau. Ví dụ: nếu x = np.array([2,3,np.nan,1,0]) sau đó np.flip(np.sort(x))cách tiếp cận mang lại [nan 3. 2. 1. 0.], trong khi -np.sort(-x)cách tiếp cận cho kết quả [3. 2. 1. 0. nan].
Uwe Mayer

1

Đây là một mẹo nhanh

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

tôi đề nghị sử dụng cái này ...

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

ví dụ:

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

Sau đó, resault của bạn:

[ 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
Làm thế nào để giải quyết vấn đề này? Bạn chỉ cần tạo ra một (giảm dần) mới mảng hoàn toàn, không liên quan, trong đó - bằng cách này - có thể được thực hiện một cách hiệu quả hơn: np.arange(20-0.5, 10-0.5, -0.5). Nhưng đó là một câu chuyện khác và có thể do tính dễ đọc kém hơn, gây tranh cãi. Một mảng đầu vào không được phân loại tại tất cả
Daniel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.