Sắp xếp mảng trong NumPy theo cột


336

Làm cách nào để sắp xếp một mảng trong NumPy theo cột thứ n?

Ví dụ,

a = array([[9, 2, 3],
           [4, 5, 6],
           [7, 0, 5]])

Tôi muốn sắp xếp các hàng theo cột thứ hai để tôi quay lại:

array([[7, 0, 5],
       [9, 2, 3],
       [4, 5, 6]])

8
Đây là một ví dụ thực sự tồi vì np.sort(a, axis=0)sẽ là một giải pháp thỏa đáng cho ma trận đã cho. Tôi đã đề xuất một chỉnh sửa với một ví dụ tốt hơn nhưng đã bị từ chối, mặc dù thực sự câu hỏi sẽ rõ ràng hơn nhiều. Ví dụ phải giống như a = numpy.array([[1, 2, 3], [6, 5, 2], [3, 1, 1]])với đầu ra mong muốnarray([[3, 1, 1], [1, 2, 3], [6, 5, 2]])
David

29
David, bạn không nhận được điểm của câu hỏi. Anh ấy muốn giữ trật tự trong mỗi hàng như nhau.
marcorossi

@marcorossi Tôi đã nhận được điểm, nhưng ví dụ được đưa ra rất tệ bởi vì như tôi đã nói, có nhiều câu trả lời có thể (tuy nhiên, điều đó sẽ không thỏa mãn yêu cầu của OP). Một chỉnh sửa sau đó dựa trên nhận xét của tôi đã thực sự được chấp thuận (mặc dù buồn cười là tôi đã bị từ chối). Vì vậy, bây giờ mọi thứ đều ổn.
David

Câu trả lời:


140

Câu trả lời của @steve thực sự là cách làm thanh lịch nhất.

Đối với cách "chính xác", hãy xem đối số từ khóa thứ tự của numpy.ndarray.sort

Tuy nhiên, bạn sẽ cần xem mảng của mình dưới dạng một mảng với các trường (một mảng có cấu trúc).

Cách "chính xác" khá xấu nếu ban đầu bạn không xác định mảng của mình bằng các trường ...

Ví dụ nhanh, để sắp xếp nó và trả lại một bản sao:

In [1]: import numpy as np

In [2]: a = np.array([[1,2,3],[4,5,6],[0,0,1]])

In [3]: np.sort(a.view('i8,i8,i8'), order=['f1'], axis=0).view(np.int)
Out[3]: 
array([[0, 0, 1],
       [1, 2, 3],
       [4, 5, 6]])

Để sắp xếp nó tại chỗ:

In [6]: a.view('i8,i8,i8').sort(order=['f1'], axis=0) #<-- returns None

In [7]: a
Out[7]: 
array([[0, 0, 1],
       [1, 2, 3],
       [4, 5, 6]])

@ Steve thực sự là cách thanh lịch nhất để làm điều đó, theo như tôi biết ...

Ưu điểm duy nhất của phương thức này là đối số "thứ tự" là danh sách các trường để sắp xếp tìm kiếm theo. Ví dụ: bạn có thể sắp xếp theo cột thứ hai, rồi cột thứ ba, rồi cột thứ nhất bằng cách cung cấp thứ tự = ['f1', 'f2', 'f0'].


3
Trong 1.6.1rc1 numpy của tôi, nó tăng lênValueError: new type not compatible with array.
Clippit

9
Nó có ý nghĩa để gửi một yêu cầu tính năng rằng cách "chính xác" được làm cho xấu xí hơn?
endolith

4
Nếu các giá trị trong mảng là floatgì? Tôi có nên thay đổi bất cứ điều gì?
Marco

1
Và đối với kiểu lai như a = np.array([['a',1,2,3],['b',4,5,6],['c',0,0,1]])tôi nên làm theo cách tiếp cận nào?
ePas Than

10
Một ưu điểm chính của phương pháp này so với Steve là nó cho phép các mảng rất lớn được sắp xếp tại chỗ. Đối với một mảng đủ lớn, các chỉ mục được trả về np.argsortcó thể chiếm khá nhiều bộ nhớ và trên hết, việc lập chỉ mục với một mảng cũng sẽ tạo ra một bản sao của mảng đang được sắp xếp.
ali_m

735

Tôi cho rằng điều này hoạt động: a[a[:,1].argsort()]

Điều này chỉ ra cột thứ hai avà sắp xếp nó dựa trên nó.


2
Điều này không rõ ràng, những gì 1ở đây? chỉ số được sắp xếp theo?
orezvani

29
[:,1]chỉ ra cột thứ hai của a.
Steve Tjoa

60
Nếu bạn muốn sắp xếp ngược lại, hãy sửa đổi nó thànha[a[:,1].argsort()[::-1]]
Steven C. Howell

1
Trông đơn giản và hiệu quả! Có nhanh hơn np.sorthay không?
Václav Pavlík

14
Tôi thấy điều này dễ đọc hơn:ind = np.argsort( a[:,1] ); a = a[ind]
poppie

32

Bạn có thể sắp xếp trên nhiều cột theo phương pháp của Steve Tjoa bằng cách sử dụng một loại ổn định như sáp nhập và sắp xếp các chỉ số từ các cột ít quan trọng nhất đến các cột quan trọng nhất:

a = a[a[:,2].argsort()] # First sort doesn't need to be stable.
a = a[a[:,1].argsort(kind='mergesort')]
a = a[a[:,0].argsort(kind='mergesort')]

Điều này sắp xếp theo cột 0, sau đó 1, sau đó 2.


4
Tại sao First Sort không cần ổn định?
Bàn Bobby nhỏ

10
Câu hỏi hay - ổn định có nghĩa là khi có một ràng buộc, bạn duy trì thứ tự ban đầu và thứ tự ban đầu của tệp chưa được sắp xếp là không liên quan.
JJ

Đây dường như là một điểm thực sự siêu quan trọng. có một danh sách mà âm thầm không sắp xếp sẽ là xấu.
Con mèo vụng về

20

Từ wiki tài liệu Python , tôi nghĩ bạn có thể làm:

a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]); 
a = sorted(a, key=lambda a_entry: a_entry[1]) 
print a

Đầu ra là:

[[[0, 0, 1], [1, 2, 3], [4, 5, 6]]]

20
Với giải pháp này, người ta có được một danh sách thay vì mảng NumPy, vì vậy điều này có thể không phải lúc nào cũng thuận tiện (chiếm nhiều bộ nhớ hơn, có thể chậm hơn, v.v.).
Eric O Lebigot

18

Trong trường hợp ai đó muốn sử dụng phân loại tại một phần quan trọng của chương trình của họ, đây là so sánh hiệu suất cho các đề xuất khác nhau:

import numpy as np
table = np.random.rand(5000, 10)

%timeit table.view('f8,f8,f8,f8,f8,f8,f8,f8,f8,f8').sort(order=['f9'], axis=0)
1000 loops, best of 3: 1.88 ms per loop

%timeit table[table[:,9].argsort()]
10000 loops, best of 3: 180 µs per loop

import pandas as pd
df = pd.DataFrame(table)
%timeit df.sort_values(9, ascending=True)
1000 loops, best of 3: 400 µs per loop

Vì vậy, có vẻ như lập chỉ mục với argsort là phương pháp nhanh nhất cho đến nay ...


16

Từ danh sách gửi thư NumPy , đây là một giải pháp khác:

>>> a
array([[1, 2],
       [0, 0],
       [1, 0],
       [0, 2],
       [2, 1],
       [1, 0],
       [1, 0],
       [0, 0],
       [1, 0],
      [2, 2]])
>>> a[np.lexsort(np.fliplr(a).T)]
array([[0, 0],
       [0, 0],
       [0, 2],
       [1, 0],
       [1, 0],
       [1, 0],
       [1, 0],
       [1, 2],
       [2, 1],
       [2, 2]])

3
Khái quát chính xác là a[np.lexsort(a.T[cols])]. ở đâu cols=[1]trong câu hỏi ban đầu.
Đài phát thanh được điều khiển

5

Tôi đã có một vấn đề tương tự.

Vấn đề của tôi:

Tôi muốn tính toán một SVD và cần sắp xếp các giá trị riêng theo thứ tự giảm dần. Nhưng tôi muốn giữ ánh xạ giữa giá trị riêng và giá trị riêng. Các giá trị riêng của tôi nằm ở hàng đầu tiên và hàm riêng tương ứng bên dưới nó trong cùng một cột.

Vì vậy, tôi muốn sắp xếp một cột mảng hai chiều theo hàng đầu tiên theo thứ tự giảm dần.

Giải pháp của tôi

a = a[::, a[0,].argsort()[::-1]]

Vậy làm thế nào để làm việc này?

a[0,] chỉ là hàng đầu tiên tôi muốn sắp xếp theo.

Bây giờ tôi sử dụng argsort để lấy thứ tự các chỉ số.

Tôi sử dụng [::-1]bởi vì tôi cần thứ tự giảm dần.

Cuối cùng, tôi sử dụng a[::, ...]để có được một khung nhìn với các cột theo đúng thứ tự.


1

Một lexsortví dụ phức tạp hơn một chút - giảm dần trên cột thứ nhất, tăng dần lên trên cột thứ 2. Các thủ thuật với lexsortnó là sắp xếp trên các hàng (vì thế .T) và ưu tiên cho hàng cuối cùng.

In [120]: b=np.array([[1,2,1],[3,1,2],[1,1,3],[2,3,4],[3,2,5],[2,1,6]])
In [121]: b
Out[121]: 
array([[1, 2, 1],
       [3, 1, 2],
       [1, 1, 3],
       [2, 3, 4],
       [3, 2, 5],
       [2, 1, 6]])
In [122]: b[np.lexsort(([1,-1]*b[:,[1,0]]).T)]
Out[122]: 
array([[3, 1, 2],
       [3, 2, 5],
       [2, 1, 6],
       [2, 3, 4],
       [1, 1, 3],
       [1, 2, 1]])

0

Đây là một giải pháp khác xem xét tất cả các cột (cách trả lời gọn hơn của JJ );

ar=np.array([[0, 0, 0, 1],
             [1, 0, 1, 0],
             [0, 1, 0, 0],
             [1, 0, 0, 1],
             [0, 0, 1, 0],
             [1, 1, 0, 0]])

Sắp xếp với lexsort,

ar[np.lexsort(([ar[:, i] for i in range(ar.shape[1]-1, -1, -1)]))]

Đầu ra:

array([[0, 0, 0, 1],
       [0, 0, 1, 0],
       [0, 1, 0, 0],
       [1, 0, 0, 1],
       [1, 0, 1, 0],
       [1, 1, 0, 0]])

0

Đơn giản chỉ cần sử dụng sắp xếp, sử dụng số coloumn dựa trên đó bạn muốn sắp xếp.

a = np.array([1,1], [1,-1], [-1,1], [-1,-1]])
print (a)
a=a.tolist() 
a = np.array(sorted(a, key=lambda a_entry: a_entry[0]))
print (a)

0

Đây là một câu hỏi cũ nhưng nếu bạn cần khái quát hóa điều này thành mảng cao hơn 2 chiều, thì đây là giải pháp có thể dễ dàng khái quát hóa:

np.einsum('ij->ij', a[a[:,1].argsort(),:])

Đây là một mức độ quá mức cho hai chiều và a[a[:,1].argsort()]sẽ đủ cho câu trả lời của @ steve, tuy nhiên câu trả lời đó không thể khái quát cho các chiều cao hơn. Bạn có thể tìm thấy một ví dụ về mảng 3D trong câu hỏi này.

Đầu ra:

[[7 0 5]
 [9 2 3]
 [4 5 6]]
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.